検索
連載

get/postでフォームから送信された値をPHPで受け取る「定義済みの変数」Web業界で働くためのPHP入門(8)(2/2 ページ)

オープンソースのWeb開発向けスクリプト言語「PHP」の文法を一から学ぶための入門連載。今回は、HTMLのフォーム機能についておさらいし、get/postメソッドで送信された内容を連想配列で格納するPHPの「定義済みの変数」の中身や、フォーム送信値の取り扱いにおける注意点について解説します【PHP 7.1含め2017年の情報に合うように更新】。

Share
Tweet
LINE
Hatena
前のページへ |       

getメソッドの例

 では、まずgetで送信した場合の処理を記述しましょう。これは、リスト2のformタグのaction属性を見ても分かるように、getPlus.phpに記述します。

<?php
$num1 = $_GET["num1"];
$num2 = $_GET["num2"];
$ans = $num1 + $num2;
print($num1." + ".$num2." = ".$ans);
リスト3 phplesson/chap08/getPlus.php

 先ほどの入力画面にあるgetのフォームに何か数値を入力して、[=]ボタンをクリックしてください。以下のような結果が表示されると思います。

4 + 5 = 9

注意! 入力チェック

 今回のサンプルでは、入力欄に数値以外のもの、例えば「aa」のような文字列を入力するとエラーとなります。本来なら、このような入力不備のチェック(バリデーション)をプログラムとして組み込む必要がありますが、ここでは話を簡単にするために割愛しています。


 getで送信したデータは、$_GET連想配列に格納されます。キーにname属性の文字列(これをリクエストパラメーター名といいます)を指定することで、値を取り出すことができます。

 ところで、getとpostの違いは、getメソッドの場合は送信されたデータはURLに連結した形を取っていることです。先ほどの[=]ボタンをクリックした際のURLを確認してください。以下のようになっているはずです。「?」から右側に「パラメーター名=値」の形でデータを送信しています。

http://localhost/phplesson/chap08/getPlus.php?num1=4&num2=5

 送信するデータが複数の場合はこれを「&」でつないでいきます。こうなると、「?」「&」「=」といった区切りに使われている文字列を値に使いたい場合どうするかという疑問が生じることと思います。こういった特殊な文字は「URLエンコード」という変換をする必要があります。

 これは、文字を16進数のコードで表し、「%xx」(xxは16進数)という形に変換することです。例えば、「?」は「%3F」、「&」は「%26」、「=」は「%3D」です。実は、この変換、上記特殊文字だけではなく、非ASCII文字(いわゆる半角英数字以外)は全て変換する必要があります。詳しくは各自調べてみてください。なお、これら、エンコードされたパラメーターは、$_GETに格納されるときに元通りの文字列に変換(デコード)されています。従って、PHP側では気にする必要はありません。

 このように、getメソッドの場合は、送信データがURLの一部になっているため、送信する値を含めてブックマークしたり、リンク先を保存したりといったことが可能になります。

postメソッドの例

 では、もう1つのpostメソッドを見ていきましょう。getと同様に、postPlus.phpを作成しましょう。といっても、ほとんどgetPlus.phpを同じ記述になります。$_GETを$_POSTに変えるだけです。

<?php
$num1 = $_POST["num1"];
$num2 = $_POST["num2"];
$ans = $num1 + $num2;
print($num1." + ".$num2." = ".$ans);
リスト4 phplesson/chap08/postPlus.php

 先ほどの入力画面にあるpostのフォームに何か数値を入力して、[=]ボタンをクリックしてください。実行結果はgetの場合と同じです。

 ここで、postで送信した場合のURLを確認してください。今度は下記のように、「?」以降が記述されていません。

http://localhost/phplesson/chap08/postPlus.php

 postの場合は、送信データはURLに付与せずにリクエスト本体に埋め込む形で送信されます。そのため、例えばパスワードの送信など、見られては困るデータは必ずpostで送信します。

コラム「入力値を配列として受け取る」

 リクエストパラメーター名、つまり、フォームのname属性値として「[]」を使うと、PHP上では配列として格納されます。例えば、次のようなフォームから送信すると、$_POST['foo']に2つの要素を持つ配列が格納されます。

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

 また上記例で、単に「foo[]」と記述しても、配列に格納されます。ただし、その場合は、「どの入力欄の値か」の対応関係が分からなくなります。下記例のチェックボックスのように、対応関係を気にせずに単に値を受け取る場合などには、この方法の方が扱いやすくなります。

<form method="post" action="">
    <input type="checkbox" name="season[]" value="1"> 春
    <input type="checkbox" name="season[]" value="2"> 夏
    <input type="checkbox" name="season[]" value="3"> 秋
    <input type="checkbox" name="season[]" value="4"> 冬
</form>

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

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

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

 例えば、前回の例では数値が素数かどうか判定するのに、数え上げる方法で判定しましたが、調べる数値をフォームから入力できるようにしたとします。この方法は数値が大きくなると計算量が増える可能性があるため、ブラウザの「タイムアウト」になってしまったり、同時に接続している他のユーザーに影響したりすることもあるでしょう。従って、フォーム送信値の範囲を制限し、チェックすることが必要になってきます。つまり、「バリデーション」です。もちろん望ましいのは判定方法を見直すことですが、ここではあくまで送信値に対する考え方を示しています。

 さらに致命的な例を紹介します。認証のためにフォームから送信されたパスワードをデータベースに問い合わせる、といった処理は典型的ですが、その際、問い合わせのための命令(「SQL」といいます)に、送信値を単純に埋め込むと、パスワードを知らなくても認証を通すことができるようになってしまいます。これは引用符などのSQLにおける特殊文字を入力に使うことで可能になります。こういった攻撃は「SQLインジェクション」と呼ばれます。防ぐためには、SQLの実行時に入力値を安全に受け渡す仕組みとして「プリペアドステートメント」というのが存在しているので、そちらを利用すべきです。

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

 その際、例えば、入力欄に<script>タグに囲まれた悪意のあるJavaScriptコードを入力し、それがそのまま表示されると、その悪意あるJavaScriptコードが実行されてしまいます。これらを避けるために、PHPでは「htmlspecialchars()」というエスケープ関数が用意されており、これを利用するのが通常です。

 こういった、実際のWebアプリケーションを公開する場合のお作法に関しても、このように機会があればこの連載中でも紹介していきたいと思います。

次回はPHPの関数について

 次回は関数について解説します。

今回のサンプルコード

 今回のサンプルコードはこちらからダウンロードできます。

■更新履歴

【2014/7/2】初版公開(山口晴広,株式会社イメージズ・アンド・ワーズ)。

【2014/7/8】編集部注:一部内容の補足について

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

【2017/7/10】PHP 7.1含め2017年の情報に合うように更新(齊藤新三/山田祥寛(監修),WINGSプロジェクト)。


前のページへ |       

Copyright © ITmedia, Inc. All Rights Reserved.

ページトップに戻る