Webフォーム:ブラウザからサーバにデータを送るためのしくみ

Webフォームを使ってデータを送る(GETリクエスト)
利用者がデータを送る際に、その内容を(URLエンコードで)URLに書き加えてくれというのは難しい注文ですよね。そのために用意されているものが、Webフォームです。誰でも一度は触ったことがあるでしょう。

図3:ブラウザで見たWebフォーム
HTMLソース
<form method="GET" action="profile.php"> 名前:<input type="text" name="name" value="John"><br> 年齢:<input type="text" name="age" value="25"><br> 性別:<label><input type="radio" name="sex" value="male" checked>男</label> <label><input type="radio" name="sex" value="female">女</label><br> 趣味:<label><input type="checkbox" name="hobbies[]" value="cooking" checked>料理</label> <label><input type="checkbox" name="hobbies[]" value="swimming" checked>水泳</label> <label><input type="checkbox" name="hobbies[]" value="running">ランニング</label><br> 住所:<select name="address"> <option value="north">北日本</option> <option value="east" selected>東日本</option> <option value="west">西日本</option> <option value="south">南日本</option> </select><br> コメント:<textarea type="text" name="comment">Hello</textarea><br> <br> <input type="submit" value="送信"> </form>
submitボタンを押すと、そのボタンが含まれているformタグの中にあるすべての入力フォーム(input、selectタグなど)のデータが送信されます。送信先はformタグのaction属性で指定したURLで、このときに使われるHTTPリクエストをmethod属性に指定します。それぞれのフォーム要素のname属性がキーになります。
つまり、入力フォームにデータを入力して送信ボタンを押すと、ブラウザが自動的に次のようなリクエストを送信するのです。これならば、利用者が自分でURLを作る必要がありませんよね。
GET http://example.jp/profile.php?name=John&age=25&sex=male&hobbies[]=cooking&hobbies[]=swimming&address=east&comment=Hello
ここでの1つ目のポイントは、チェックボックスで入力する「趣味」の項目です。このフォームの name 属性は「hobbies[]」とカッコが付いていて、同じキーが複数あります。これは、PHPの配列の書き方と似ていますよね。そうです、趣味は複数選ぶことができるので、選択したものが配列に入るのです。
<?php var_dump($_GET["hobbies"]); // ※キー名に [] は不要です // array(2) { // [0]=> // string(7) "cooking" // [1]=> // string(8) "swimming" // } ?>
もう1つのポイントは、このように送信されてきたデータはすべて「文字列型」になっているということです。年齢は数字で入力しますが、数値型ではなく文字列型の数字で送られてきます。このことは、後述する「検証」のところで関係してきます。
<?php var_dump($_GET["name"]); // string(4) "John" var_dump($_GET["age"]); // string(2) "25" // 参考までに… var_dump(25); // int(25) var_dump("25"); // string(2) "25" ?>
Webフォームを使ってデータを送る(POSTリクエスト)
ところで、URLに情報を乗せたくない場合や、情報が多すぎて乗せ切れない(Internet ExplorerではURLに2000文字程度までしか使えない)こともあります。そのようなときは、GETリクエストではなく、POSTリクエストを使います。
<form method="POST" action="profile.php"> 名前:<input type="text" name="name" value="John"><br> 年齢:<input type="text" name="age" value="25"><br> 性別:<label><input type="radio" name="sex" value="male" checked>男</label> <label><input type="radio" name="sex" value="female">女</label><br> 趣味:<label><input type="checkbox" name="hobbies[]" value="cooking" checked>料理</label> <label><input type="checkbox" name="hobbies[]" value="swimming" checked>水泳</label> <label><input type="checkbox" name="hobbies[]" value="running">ランニング</label><br> 住所:<select name="address"> <option value="north">北日本</option> <option value="east" selected>東日本</option> <option value="west">西日本</option> <option value="south">南日本</option> </select><br> コメント:<textarea type="text" name="comment">Hello</textarea><br> <br> <input type="submit" value="送信"> </form>
formのmethodをPOSTにすると、ブラウザは以下のようなリクエストを送信します。POSTパラメータは、URLには含まれない形でサーバに送られます。
POST http://example.jp/profile.php POSTパラメータ name John age 25 ...
PHPではPOSTパラメータを取得するには、$_POSTというグローバル変数を使います。
<?php echo $_POST["name"]; // John echo $_POST["age"]; // 19 echo $_POST["comment"]; // Hello ?>
POSTリクエスト時に 、併せてGETパラメータを付けることもできます。
POST http://example.jp/profile.php?design=sky POSTパラメータ name John age 25 ...
<?php echo $_GET["design"]; // sky echo $_POST["name"]; // John ?>
受け取ったデータを表示する
利用者からデータを受け取る方法が分かりましたので、今度は受け取ったデータを画面に表示するプログラムを書きましょう。WebフォームはPOST送信を使うことにします。
Webフォームを出力しているのも、プロフィール画面を出力しているのも、同じ profile.php のプログラムです。つまり、条件によって別の画面を表示する必要があります。プログラム側の処理の流れは図5のようになります。

図5:条件によって出力する画面が異なる
図5にしたがって、プログラムの内容を書き出すと、以下のようになります。
- 1回目のアクセスの場合 → Webフォームを表示する
- 2回目以降のアクセスの場合
- すべてのデータが適切かどうかチェックする
- 適切でないデータがある場合 → エラーメッセージと再入力用のWebフォームを表示する
- すべてのデータが適切である場合 → データを画面に表示する
これらをひとつずつ見てみましょう。
(1)1回目のアクセスの場合
それではまず、初回表示かどうかを判断しましょう。初回表示というのは、まだ何もデータが送られて来ていない状態です。つまり、$_POST["name"]、$_POST["age"]、$_POST["sex"]、$_POST["hobbies"]、$_POST["address"]、$_POST["comment"]のどれかの値が取得できたら、2回目以降のアクセスということになります。しかし、いちいち全部の値を調べるのは面倒です。また、入力項目の種類や名前が今後変わるかもしれませんし、その際にまた書き直すのも大変です。というわけで、初回表示かどうかを判断するための項目をWebフォームに追加しましょう。画面上には表示されないhiddenタイプのinput要素を使います(送信ボタンにname属性を付ける方法もありますが、初回表示のチェック専用の要素を用意しておくほうが、汎用性が高くなります)。
<form method="POST" action="profile.php"> 名前:<input type="text" name="name" value="John"><br> 年齢:<input type="text" name="age" value="25"><br> 性別:<label><input type="radio" name="sex" value="male" checked>男</label> <label><input type="radio" name="sex" value="female">女</label><br> 趣味:<label><input type="checkbox" name="hobbies[]" value="cooking" checked>料理</label> <label><input type="checkbox" name="hobbies[]" value="swimming" checked>水泳</label> <label><input type="checkbox" name="hobbies[]" value="running">ランニング</label><br> 住所:<select name="address"> <option value="north">北日本</option> <option value="east" selected>東日本</option> <option value="west">西日本</option> <option value="south">南日本</option> </select><br> コメント:<textarea type="text" name="comment">Hello</textarea><br> <br> <input type="hidden" name="not_the_first_time" value="yes"> <input type="submit" value="送信"> </form>
こうすると、1回目のアクセスでは $_POST["not_the_first_time"] は存在しませんが、送信ボタンを押されてアクセスしてくる2回目以降のアクセスでは、$_POST["not_the_first_time"] が存在しています。配列の中に、あるキーが存在するかどうかを調べるには、array_key_existsというPHPの関数を使います。
<?php /*------------------------------------------------------------ 2回目以降のアクセス ------------------------------------------------------------*/ if (array_key_exists("not_the_first_time", $_POST)) { // 2回目以降はtrue } /*------------------------------------------------------------ 1回目のアクセス ------------------------------------------------------------*/ else { // 1回目はfalse echo ' <form method="POST" action="profile.php"> 名前:<input type="text" name="name" value="John"><br> 年齢:<input type="text" name="age" value="25"><br> 性別:<label><input type="radio" name="sex" value="male" checked>男</label> <label><input type="radio" name="sex" value="female">女</label><br> 趣味:<label><input type="checkbox" name="hobbies[]" value="cooking" checked>料理</label> <label><input type="checkbox" name="hobbies[]" value="swimming" checked>水泳</label> <label><input type="checkbox" name="hobbies[]" value="running">ランニング</label><br> 住所:<select name="address"> <option value="north">北日本</option> <option value="east" selected>東日本</option> <option value="west">西日本</option> <option value="south">南日本</option> </select><br> コメント:<textarea type="text" name="comment">Hello</textarea><br> <br> <input type="hidden" name="not_the_first_time" value="yes"> <input type="submit" value="送信"> </form> '; } ?>