HTTPメソッドにはGETとPOST(の他のあるが今回は触れない)がある。GETメソッドはURLの一部としてデータを送信できるに過ぎず、データの容量やタイプに制限がある。POSTメソッドはプログラムやサーバの設定が許す範囲の大きさのデータを扱え、ファイルのアップロードなども行える。
■GETメソッド
以下のように、form要素のmethod属性にGETと記述する。
<form acton="index.php" method="get"> <input type="text" name="name" /> <input type="text" name="tel" /> <input type="submit" name="submit" value="submit" /> </form>
上述のGETメソッドを使用したフォームで送信を行うと、入力が「John Norton」「0120123456」のとき、以下のURLでブラウザはリクエストを行う。
http://sample.org/index.php?name=John+Norton&tel=0120123456&submit=submit
スペースは「+」に、「&」は「%26」に、「=」は「%3d」といった具合に自動でエンコードされる。index.php側でデータを受け取るには以下のようにスーパーグローバル変数$_GETを使用する。
<?php $name = $_GET['name']; ?>
URLのエンコードとデコードについて
前述のようにデータを送信するときには、自動でエンコード処理されるが、PHPでデータを受け取るときはインタプリタが自動でデコードしてくれる。従って例えば「John+Norton」でリクエストされた場合でも以下のように、$_GET[‘name’]内には「John Norton」が格納されている。
<?php print($_GET['name']);//John Norton ?>
但し、リンク先のURLを文字列として出力する必要がある場合などは、以下のようにプログラムでエンコードしてあげる必要がある。
<?php $name = 'John Norton'; ?> <a href="<?php print('http://sample.org/index.php?name=' . urlencode($name)); ?>">詳細はこちら</a>
■POSTメソッド
以下のように、form要素のmethod属性にPOSTと記述する。
<form acton="index.php" method="post"> <input type="text" name="name" /> <input type="text" name="tel" /> <input type="submit" name="submit" value="submit" /> </form>
上述のフォームでPOSTメソッドを使いリクエストをした場合、index.php側でデータを受け取るには以下のようにスーパーグローバル変数$_POSTを使用する。
<?php $name = $_POST['name']; ?>
通常フォームのデータを受け取る場合
相当に簡略化しているが、submitボタンが押されたリクエストか判断するために、以下のようにif構文を用いることが多い。
<?php if(isset($_POST['submit'])){ //code } ?>
また、以下のようなコードもしばしば見つけるが、「Notice: Undefined index・・・」と注意が表示される原因にもなる。submitキーのデータが無い状態でページをリクエストすると、$_POSTの配列にsubmitのキーが存在しないことに起因するものである。
<?php if($_POST['submit']){ //code } ?>
■チェックボックスのデータをPHPで受け取る方法
name属性に重複名がある場合、PHPでは以下のように、任意の名前の後に[]を付加しなければ正しくデータを受信できない。
<?php if(isset($_POST['submit']) && isset($_POST['language']) && $_POST['language']){ foreach($_POST['language'] as $lang){ print($lang . PHP_EOL); } } ?> <form action="<?php print($_SERVER['SCRIPT_NAME']); ?>" method="post"> <p>What languages do you use?</p> <ul> <li><input type="checkbox" name="language[]" value="javascript" />JavaScript</li> <li><input type="checkbox" name="language[]" value="php" />PHP</li> <li><input type="checkbox" name="language[]" value="mysql" />MySQL</li> </ul> <input type="submit" name="submit" value="submit" /> </form>
このコードでは条件文で$_POST[‘language’]をテストしているが、チェックボックスが一つもチェックされていないときに、$_POSTにlanguageキーが存在しなくなるためである。また、$_POST[‘language’]が配列となる仕組みは以下の特性に起因する。
<?php if(isset($_POST['submit'])){ print($_POST['dat']['name']); print($_POST['dat']['tel']); } ?> <form action="<?php print($_SERVER['SCRIPT_NAME']); ?>" method="get"> <ul> <li><input type="text" name="dat[name]" /></li> <li><input type="text" name="dat[tel]" /></li> </ul> <input type="submit" name="submit" value="submit" /> </form>
つまりHTTPクエリのキー内の配列リテラルはそのままPHPに引き継がれるということになる。そして同名キーが存在する場合は、データを正しく取得する方法でもある。
■スーパーグローバル変数$_REQUEST
スーパーグローバル変数$_REQUEST[‘key’]を使用すると、$_POST、$_GET、$_COOKIEにアクセスが出来るが、データのどういったものなのか分からずセキュリティを下げる要因になる。従って、$_REQUESTは使用しないことをお勧めする。
■ファイルのアップロード
フォームについて
ファイルのアップロードを行う場合のフォームは、以下のようにenctype属性を記述せねばならない。そして、MAX_FILE_SIZEでは転送できるファイルの最大容量をバイトで指定できるがtype=”file”の前に記述しないと効果がない。また、upload_max_filesizeより大きな値を指定した場合は無視される。
<form enctype="multipart/form-data" action="index.php" method="post"> <input type="hidden" name="MAX_FILE_SIZE" value="50000"> <input type="file" name="file" /> <input type="submit" name="submit" value="submit" /> <form>
但し、MAX_FILE_SIZEの値はクライアント側で編集可能な値であり、これを信頼したアプリケーションを作ってはならない。但し、ファイルの転送が終わってから容量制限の判断をする、といった無駄な時間をユーザに与えてしまうといった愚行を防ぐには非常に有効である。
スクリプトについて
上述のHTMLから送信されたファイルを受け取るには、以下のように$_FILESを用いる。
<?php $dat = $_FILES['file']; var_dump($dat); /* array(5) { ["name"]=> string(12) "20090428.txt" ["type"]=> string(10) "text/plain" ["tmp_name"]=> string(14) "/tmp/phpGxxRLV" ["error"]=> int(0) ["size"]=> int(140) } */ ?>
以上を見てみると、$_FILESには実際のファイルの情報でなく、以下のような情報が格納されている。
- name
- 送信したファイルのクライアント上の名前
- type
- ブラウザが判断したMIMEタイプ
- tmp_name
- サーバ上に保存された一時的なファイルの名前
- error
- エラー番号
- size
- ファイルのサイズ(バイト)
アップロードしたファイルをアプリケーションで使用する場合は、以下のようにmove_uploaded_file関数を使う。move_uploaded_file関数では、第一引数にテンポラリーファイル名、第二引数に保存するファイル名を指定する。
<?php $filename = 'sample.txt'; if(move_uploaded_file($_FILES['file']['tmp_name'], "/www/sample.org/httpdocs/doc/$filename"){ //code } ?>
move_uploaded_file関数は指定ファイルがユーザーによりアップロードされたものか判定する処理も含まれている。また、アップロードされたファイルをサーバー上に保存する際に、クライアントの送信に依存した$_FILES[‘file’][‘name’]をそのまま使うのは、セキュリティ上の問題となり得る。ちなみにファイルがアップロードできたか判定するには、以下のようにis_uploaded_file関数を使用する。
<?php if(is_uploaded_file($_FILES['file']['tmp_name'])){ //code } else{ print($_FILES['file']['error']); } ?>
ファイルアップロードに関連するphp.iniの設定
- post_max_size
- POSTメソッドで許可するデータのサイズ。upload_max_filesizeより大きな値を設定する必要がある。
- max_input_time
- POST、GET 、ファイルアップロードなどの入力を パースする最大の時間を設定。秒単位で指定。
- upload_max_filesize
- アップロードできる最大ファイル容量。
■GETとPOSTの性質
DBを更新するような、サーバに変更を加えるような処理にGETリクエストを使ってはならない。ファイルをはじめとした、大量のデータ送信する場合はPOSTを使わなければならない。
GET | POST | |
---|---|---|
データの送信 | フォームのパラメータをURL形式にエンコードして、クエリ文字列として送信する | フォームのパラメータをHTTPリクエストに直接、書き込む |
ブックマーク | 可能 | 不可能 |
仕様上の冪等性 | ○ 任意のURLで何回リクエストしても結果が同じというような実装をすべきある。またブラウザは結果をキャッシュする |
× リクエストの結果が場合によって異なるなど、結果をキャッシュしないような場面に適している |
冪等性について
冪等性とは「ある操作を複数回行っても動作が同じである事」である。
また、POSTリクエストでも、実際には一般ユーザーが「戻る」ボタンを押し「リロード(再送信)」する事もある。従って、アプリケーションを制作する際は考慮しなくてはならない。
フォーム要素について
- method属性の属性値は大文字で書いた方が良い(理論上、大文字/小文字の両方を受け付けるが、ブラウザのバグを考慮)