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

2015年4月1日(水)
野田 貴子

はじめに

これから始めるPHP入門コラムでは、PHPを学ぶ人が、PHPで簡単なプログラムを書けるようになるまでに必要な知識とポイントをTips的に書いていきます。今後PHPのスキルを身につけて仕事に役立てたい、という方のために「PHP技術者認定初級試験」の出題範囲を意識しながら進めていきますので、ぜひ最後までお付き合いください。

今回のあらすじ

  1. リクエストとレスポンス
  2. データを取得する
  3. データを表示する
  4. セキュリティ上の問題を修正する

このトピックはお伝えしたいことが多くて、前回はテキストが多くなってしまい、編集部に前後編にされてしまいました(笑)。ぜひ合わせてお読みください。

受け取ったデータを表示する

(4)適切でないデータがある場合

利用者が入力したデータが不適切だった場合(年齢が1200歳など)、エラーメッセージと再入力用のWebフォームを表示する必要があります。

前回までのチェック処理により、不適切なデータが存在した場合は、配列の$errorMsgにエラーメッセージが格納されています。エラーメッセージが存在するかどうかをチェックして、処理を分岐させましょう。Webフォームを表示する処理は関数に分けて再利用するようにします。

(5)すべてのデータが適切である場合

すべてのデータが適切であるかどうかは、先ほど$errorMsgでチェックしたので、データを画面に表示する処理を考えましょう。

選択肢の配列を用意してあるものについては、その配列を使います。入力されてくるのは性別であれば「male」などなので、それを「男」という表示にするためです。

コメントでは改行が入力されるので、textareaでの改行部分に
タグを挿入するnl2br関数を使います。

ブラウザ上での表示

ブラウザ上での表示

セキュリティ上の問題を修正する

ここまでで、とりあえず動くレベルのものができましたが、実際に運用するにはまだバグとセキュリティ上の問題があります。

Webフォームを出力するこの部分を見てください。

1<?php
2echo '名前: <input type="text" name="name" value="' . $form["name"] . '">';
3?>

form["name"]trim(_POST["name"])」が入っているので、もし名前に「山田"太郎"花子」と入力された場合、以下のようにHTMLの構文エラーになってしまいます。

1名前: <input type="text" name="name" value="山田"太郎"花子">

それではstr_replace関数を使い「"」を「"」に変換すればそれでよいでしょうか。しかしHTMLには、他にも「 (>)」「& (&)」など、エスケープしなければならない文字がいくつかあります。これらを一手に引き受けてくれるのが、htmlentities関数です。

1<?php
2echo '名前: <input type="text" name="name" value="' . htmlentities($form["name"], ENT_QUOTES, "UTF-8") . '">';
3?>

この例のようにHTMLが崩れてしまうだけならちょっとしたバグで済みますが、入力されたデータをそのまま出力していると、もっと悪質な他人に害を及ぼすようなコードを埋め込まれてしまうことがあります。データ出力部分である、次のコードを見てください。

1<?php
2echo '<h2>名前</h2>';
3if (strlen($form["name"]) > 0) {
4    echo $form["name"];
5}
6?>

もし名前の入力欄に、悪質なWebサイトへ勝手に画面遷移してしまうようなJavaScriptが入力されてしまったらどうなるでしょう。

1<h2>名前</h2><script>location.href='http://悪質なサイト.jp';</script>

今のところ、この画面を見るのはデータを入力した本人だけですが、今後プロフィールデータをデータベースに登録する処理を追加し、ある人のプロフィール画面に他の人もアクセスできるようになったとしたら、その画面を見た人が被害を受けてしまいます。このようにHTMLの中に悪意のあるスクリプトを埋め込んでしまうことを「クロスサイトスクリプティング」といいます。

クロスサイトスクリプティングも先ほどのhtmlentities関数で防ぐことができます。

1echo '<h2>名前</h2>';
2if (strlen($form["name"]) > 0) {
3    echo htmlentities($form["name"], ENT_QUOTES, "UTF-8");
4}
5 
6<h2>名前</h2><script>location.href='http://悪質なサイト.jp';</script>

以上で、プログラムが完成しました。

おまけ

Webシステムを作る際に、よく必要となりそうなデータ形式のチェック方法を2点ほど紹介します。

日付の入力値チェック方法

一週間後までの予約ができるシステムがあるとしましょう。予約日として入力された日付が、一週間以内であるかどうかをチェックするには以下のようにします。

1<?php
2$date = $_POST["date"]; // 例:2015/03/02
3// $dataのタイムスタンプと一週間後のタイムスタンプを比較する
4if (strtotime($date) > strtotime('+1 week')) {
5echo '予約日は一週間以内の日付を入力してください。';
6}
7?>

strtotimeは、文字列をタイムスタンプ(1970年1月1日からの経過秒数)に変換する関数です。数値であるタイムスタンプは、大小の比較に適しています。使用できる文字列の種類は多数ありますので、詳細はマニュアルをご覧ください。

メールアドレスの入力値チェック方法

「正規表現」という、文字列の規則を表す特殊な書き方があります。例えば「小文字のアルファベット1文字と数字1文字」は「[a-z][0-9]」と書きます。入力されたデータが規則に適合しているかどうかを調べる際には、preg_matchを利用できます。

メールアドレスも、ある程度までなら正規表現でチェックすることができます。「@マークが入っていればOK」というくらい簡単でゆるいものにするか、正規表現で厳密にチェックするかどうかは、システムの性格にもよるでしょう。

おわりに

いかがでしたか。前回・今回にわたって、がっつりとコードを書いたので量が多かったかもしれませんが、ブラウザで入力したデータがPHPに送られ、画面に表示されるというインタラクティブな部分を楽しめたのではないでしょうか。次回はWebシステムになくてはならないデータベースについて取り上げます。それではまた。

1983年生まれ。大学卒業後、ソフトウェア開発の営業を経て、ソフトウェア開発業務に転向。現在は自社パッケージのフロントエンド開発のほか、PHPでの受託開発案件、日→英のローカライズ案件などを担当。

連載バックナンバー

Think ITメルマガ会員登録受付中

Think ITでは、技術情報が詰まったメールマガジン「Think IT Weekly」の配信サービスを提供しています。メルマガ会員登録を済ませれば、メルマガだけでなく、さまざまな限定特典を入手できるようになります。

Think ITメルマガ会員のサービス内容を見る

他にもこの記事が読まれています