ウィルキンソンの炭酸が抜けていく。

webクリエイターのイロハ

PHP定義済みの変数研究

 

 

1、HTMLフォーム機能についてのおさらい。

 

 

<form action="送信先URL" method="post">

<input type="text" name="example">

<input type="submit" value="送信">

</form>

 

 入力欄に何か入力してボタンを押すと、Webブラウザーは指定したURLに対して入力内容を送信します。通常そのURLでは何らかのWebアプリケーションが動作していて、入力内容に従って動作するように作られています。例えば、検索エンジンなら検索結果を表示する、などです。

 

 

2、PHPの定義済み変数

 PHPの便利なところは、この送信先のURLにPHPのファイルを指定するだけで、Webブラウザー上のフォームから送信された値を受け取ることができる点です。

 「定義済みの変数」というあらかじめ決められた変数群があり、この変数に送信値が格納されています。つまり、変数にアクセスするだけで送信値を取り出せるようになっています。

 これまでの解説では、変数は何らかの値を代入することで使えるようになりましたが、定義済みの変数は、そういった操作をせず、いきなり使える点が異なっています。

 定義済みの変数はいくつか種類があり、フォームの送信値以外の目的でも使われています。よく使われるのは次のものです

  • $_COOKIE:クッキーの値
  • $_ REQUEST:$_GET、$_POST、$_COOKIEをまとめたもの
  • $_SERVER:サーバーの環境情報やクライアント(Webブラウザー)の情報
  • $_SESSION:セッションに格納した値

 

 

 全て変数名の冒頭に「_(アンダースコア)」が付いていますが、これは「通常の変数ではない」ということを主張しています。特に、文法上のルールがあるわけではありません。通常のものとは違うという主張をするためにアンダースコアから始まる名前を付けることは、PHP以外の言語でもよく行われています。

 上記のうち、$_GETと$_POSTがフォームから送信された値が格納される定義済みの変数です。いずれの変数も連想配列になっています。

 例として、$_SERVERの内容を見てみましょう。$_GETや$_POSTはフォームから送信しないと空っぽですが、$_SERVERなら常に値が格納されています。

 次のコードで$_SERVERを表示してみましょう。

<pre><?php var_dump($_SERVER) ?></pre>

 

連想配列として、さまざまな情報が格納されていることが分かります。$_SERVER内の要素の意味は、「PHP: $_SERVER - Manual」で解説されているので、参考にしてください。

 

 

3定義済みの変数「$_GET」「$_POST」の中身を見る

 

フォームにはGETメソッドとPOSTメソッドの2種類があり、それぞれ定義済みの変数、$_GETと$_POSTに対応しています。このメソッドはHTML上で<form>要素のmethod属性として指定するものです。

GETメソッドの例

 GETとPOSTの違いは、GETメソッドの場合、送信値はURLに連結した形で送信されるということです。URLの一部になっているため、送信する値を含めてブックマークしたり、リンク先を保存したりといったことが可能になります。

 get_dump.phpとして次の内容を保存し、ブラウザーで「http://localhost:8000/get_dump.php」にアクセスしてみましょう。

<pre><?php var_dump($_GET) ?></pre>

 何も送信していないため、$_GETは空です。「array(0){}」と表示されたことでしょう。次に下記URLにアクセスしてみます。「?」から右側がURLに追加した文字列です。

http://localhost:8000/get_dump.php?key1=abc&key2=xyz
php8_02.jpg図2 GETメソッドによる値の送信はURLを介して行われている

 $_GETの中に、URLに追加した文字列が格納されていることが分かります。

 GETメソッドで追加する文字列の規則は例を見ればだいたい分かると思いますが、「?」「&」「=」といった区切りに使われている文字列を値に使いたい場合どうするかという疑問が生じることと思います。

 こういった特殊な文字は「URLエンコード」という変換をする必要があります。詳しくは各自調べてみてください。

 

POSTメソッドの例

 POSTメソッドの場合は送信するフォームが必要になります。フォームを表示するHTMLと、送信先となるPHPの2つにファイルを分けてもいいのですが、ここでは1つのPHPファイルとしてサンプルを作ってみることにします。

 サンプルは、送信された2つの数値を足し算して表示するという、ごく簡単なものとします。段階を追って作っていきましょう。まずはフォームです。

  1. <form action="" method="post">
  2. <input type="text" name="num1" size="4"> +
  3. <input type="text" name="num2" size="4">
  4. <input type="submit" value=" = ">
  5. </form>

 これを表示すると次のようになります。

php8_03.jpg図3 足し算をするフォームの表示。足し算っぽく表示してみた

 フォームの送信先URLは空になっています。空のままでも当該ファイル自身が送信先になりますが、ここでは明示することにしましょう。ファイル自身は、$_SERVER配列のSCRIPT_NAME要素として格納されていますので、次のようになります。

  1. <form action="<?php echo $_SERVER['SCRIPT_NAME'] ?>" method="post">
  2. <input type="text" name="num1" size="4"> +
  3. <input type="text" name="num2" size="4">
  4. <input type="submit" value=" = ">
  5. </form>

 ブラウザーのHTMLソース表示機能を使って確認してみてください。

 次に、値が送信されていた場合に足し算を行って表示する部分を追加します。値が送信されたということは、$_POSTに何か値が入っているということです。配列が空かどうかは、if文で比較する(すなわち、真偽値へ型変換する)と、空の場合は偽となるので判定できます。

  1. <form action="<?php echo $_SERVER['SCRIPT_NAME'] ?>" method="post">
  2. <input type="text" name="num1" size="4"> +
  3. <input type="text" name="num2" size="4">
  4. <input type="submit" value=" = ">
  5. </form>
  6. <?php
  7. if ($_POST) {
  8. $num1 = $_POST['num1'];
  9. $num2 = $_POST['num2'];
  10. echo $num1, ' + ', $num2, ' = ', $num1 + $num2;
  11. }
  12. ?>

 これを表示し、フォームに数字を入力してボタンを押すと、次のようになります。

php8_04.jpg図4 足し算が実行されて表示されたところ

 <input>要素のvalue属性に入力された値を入れて表示すれば、もっときれいに表示することもできるでしょう。ぜひ挑戦してみてください。

コラム「フォームの名前に『』を使うと、PHP上では配列として格納される」

 フォームの名前に「」を使うと、PHP上では配列として格納されます。これは他の言語にはない特徴です。例えば、次のようなフォームから送信すると、$_POST['foo']に2つの要素を持つ配列が格納されます。

  1. <form action="" method="post">
  2. <input type="text" name="foo[1]"><br>
  3. <input type="text" name="foo[2]">
  4. <input type="submit" value="送信">
  5. </form>
 

編集部注:一部内容の補足について(2014年7月8日)

本記事ではPHPプログラミングにおけるセキュリティ対策の必要性を以降の文章で記載しておりましたが、内容について一部読者から指摘があり、内容を補足させていただきました。また本連載「Web業界で働くためのPHP入門」はPHPの文法解説を行うものなので、セキュリティ対策について詳細に解説するものではないにもかかわらず、本稿タイトルに「セキュリティ対策」と入れたため誤解を招いた点がありました。タイトルも変更させていただきます。

 
 

 

 

フォーム送信値の取り扱いにおける注意点

 今回のサンプルプログラムは、あくまで解説のためのサンプルです。テストサーバー上で、PHPを理解するために試行錯誤する分には問題ありませんが、実際にWebサーバー上で公開してはいけません。

 PHPに限らず、どのようなプログラムでもいえることですが、外部からの入力は、何らかの悪意をもって行われる可能性を常に考慮に入れなければならないためです。「悪意」というのは誤動作や停止を引き起こさせたり、セキュリティを侵害したりといったことです。サンプルプログラムは、そういった考慮を一切していません。

 例えば、前回の例では数値が素数かどうか判定するのに、数え上げる方法で判定しましたが、調べる数値をフォームから入力できるようにしたとします。この方法は数値が大きくなると計算量が増える可能性があるため、ブラウザータイムアウトになってしまったり、同時に接続している他のユーザーに影響したりすることもあるでしょう。

 従って、フォーム送信値の範囲を制限することが必要になってきます。もちろん望ましいのは判定方法を見直すことですが、ここではあくまで送信値に対する考え方を示しています。このように値の型式や範囲が正しいかどうか確認することを、「バリデーション」といいます。

 さらに致命的な例を紹介します。認証のためにフォームから送信されたパスワードをデータベースに問い合わせる、といった処理は典型的ですが、その際、問い合わせのための命令(「SQL」といいます)に、送信値を単純に埋め込むと、パスワードを知らなくても認証を通すこともできるようになってしまいます。これは引用符などのSQLにおける特殊文字を入力に使うことで可能になります。

 こういった攻撃は「SQLインジェクション」と呼ばれますが、防ぐための1つの方法として、特殊な文字を取り除いたりエスケープしたりして無害化するといった対応があります。これを「サニタイズ」といいます。ただし、SQLの実行には入力値を安全に受け渡す仕組みも別途存在しているので、根本的にはそちらを利用するべきです。

 このようにフォームの送信値は、目的に応じたバリデーションやサニタイズをきちんと行うことが大切です。これは入力値を受け取るという部分に限った話で、全体的に見れば、より望ましい対策がある可能性も忘れてはなりません。

 また、Webアプリケーションの場合、もう一つ注意しなければならないことがあります。ブラウザーに返すHTMLに変数の内容を表示する場合です。HTML上の特殊文字である「<」「>」「&」をエスケープして表示しなければなりません。エスケープをしないとHTMLのタグとして認識されてしまいます。

 特に、フォーム送信値をそのままエスケープせずに表示してしまうと、任意のタグを表示できることにつながってしまいます。