バリデーションとは受け付けない値を弾いて、確かな(valid)値だけを扱うという処理です。 こう説明されてもわかりにくいと思うので、いつもの生活の中でどのようなチェックが行われているかを例に説明しましょう。 アンケートフォームなどで数字の項目に文字を入れるとエラーになったり、携帯電話で着信拒否の番号を登録したり、身近で値のチェックを行っていますね。 本書で作成したレシピアプリでも、POSTやGETで値を取得していますが、このような値はHTML5やJavaScriptなどで入力チェックを行っていても信用してはいけません。ここで重要になるのがバリデーションです。
※Windows環境の場合は、使用しているエディタによってはプログラム内の「\」(半角バックスラッシュ)が「¥」(半角円マーク)で表示される場合があります。
これらを調べて、不正な入力値を除外する必要があります。
バリデーションに適した関数を紹介しましょう。 preg_matchという関数です。 preg_match()は正規表現により、値が期待するパターンにマッチするかを検査します。
正規表現というと難しいですが、ここでは下記のサンプルを見て雰囲気をつかんでください。
preg_match('/\A[123]\z/',変数);
preg_match('/\A[0-9]{1,4}+\z/',変数);
preg_match('/\A[[:^cntrl:]]{1,100}+\z/u',変数);
preg_match('/\A[\r\n[:^cntrl:]]{1,200}+\z/u',変数);
なんとなく予想がつきませんか? パターンの部分で「/\A ... \z/」というふうに、「/」に挟まれた中にそれぞれ違いがあります。 ここでは細かく説明しませんが、この書き方を覚えておいてください。
表:例に使われている正規表現の簡単な説明
| 項目 | 内容 |
|---|---|
| // | //で囲まれた部分に正規表現が入っている |
| \A | 文字列の先頭 |
| \z | 文字列の最後 |
| [] | []の中が使って良い文字列になる |
| 0-9 | 0〜9の数字 |
| a-z | アルファベット |
| [:^cntrl:] | 制御文字以外 |
| \r\n | 改行 |
| + | 一文字以上の繰り返し |
| {} | {}の直前のパターンの有効桁(文字)数 |
| u | UTF-8が対象 |
さらに詳細な内容ついては「PHP 正規表現」などで検索し、どのようなものなのか勉強してください
(コピー&ペーストでの利用は意図しない処理になる場合もあるので、よく内容を理解して利用しましょう)。
この先では上記サンプルのみを用います。
さて、バリデーションをするためには、色々な条件で入力を受け付けない文字や数値を設定する必要があります。 そのようなときにif文を用いて複数の条件を1回で判定する方法をここで補足します。 まずif文の構文を見てみましょう。
でしたね。この条件というところがポイントで、中が真(TRUE),偽(FALSE)かで条件の判定を行います。 elseも覚えましたが、ここでは条件の部分に注目して新しい使い方を覚えましょう。
「●●ではない」というような条件を利用したい場合は多いと思います。そのような場合は論理演算子の!を利用することで条件の否定を行うことができます。
例:emptyではない場合
例を見てみると何か気づくと思いますが、 if文の条件で!(否定)を付けることはelseの条件のときと同じです。 真(TRUE)の側の判定が不要な場合、!を用いるとif文が短くなり可読性がよくなるので覚えておきましょう。
例1をif〜elseで表すと
条件文でよく出てくるので覚えておくといいでしょう。
いままではシンプルな判定を行ってきましたが複合的な判定も必要になります。 例えば「●●かつ●●」や、「●●または●●」といった判定です。
「かつ」の場合は論理積と呼ばれるもので、2つの条件を&&でつなぎます。 「または」の場合は論理和と呼ばれ、2つの条件を||でつなぎます。 なお、複数の条件を利用する場合、1つ1つの条件を()で括ることで可読性が増します。
例:
この後も利用するので覚えておいてください。
emptyとは逆に、存在するということを判定するissetという言語構造があります。 先ほど!(否定)を学びました。この2つは完璧に対になるものではないので注意が必要です。 大きな違いは0の判定を行ったときに0を空とするのか、数値が入力されているのかどちらで判定するかです。
このような短いサンプルをtest.phpなどとして実行してみましょう。 結果は 「int(0) bool(true) bool(false)」 と、「empty($a)」は「true」、「!isset($a)」は「false」と、異なる判定結果が返ってきます。empty()とisset()が完璧に対の関係ではないということが理解できたでしょうか?
※他にも「$a="";」の場合などでも異なる判定結果が返ります。
レシピアプリではIDはデータベースのオートインクリメント設定によって、1から始まりました。通し番号では0から始まる場合もありますね。このような場合、上記のようにif (empty($id)) と記述してしまうと、0も条件を満たしたと判断されてしまいます。これはempty()が0を真(TRUE)と判定するためです。このような場合は、値がある場合に真(TRUE)と判定するisset()という関数を用いましょう。isset()は0が入力されても入力があると判定します。このisset()に先ほど説明に出てきた!(否定)を行うと何も入力されていない場合の判定が行えます。なお、0や未入力の扱いには注意が必要です。マニュアルを参考にテストを行い意図したデータを判定しているか確認しましょう。
PHPマニュアルなどを参考にして、仕様上どちらが最適かを検討してください。
http://php.net/manual/ja/function.isset.php
http://php.net/manual/ja/function.empty.php
いよいよ実際にバリデーションを行っていきましょう。 まずはIDの場合を考えてみます。
いまIDの値はどのように作成されるかというと、 データベースを作成したときのオートインクリメントが有効になっているので、 1から順にカウントアップしていきます。 PHPにもMySQLにも扱える型により扱える限界はあります。 ※執筆時点でのMAMPの環境では、MySQLのINT型の範囲-2147483648〜2147483647、PHPのinteger型の最大値9223372036854775807(脚注) いままで決めていませんでしたが、今回のプログラムでは1000件まで入力できることに決めましょう。 とすると、IDに入力されるべき整数は1-1000の整数ということになります。 では、それ以外の値についても下記表のように、入力できる値に制約を設けましょう。
表:入力を許可する値
| 項目 | 内容 |
|---|---|
| ID | 1から1000までの整数 |
| 料理名 | 100文字までの文字列 |
| カテゴリ、難易度 | 1〜3の整数 |
| 予算 | 0-9999までの整数 |
| 作り方 | 200文字までの文字列と改行 |
ではそれぞれの項目についてソースコードを修正していきましょう。 レシピの数は1000個まで登録できるようにしましょう。
対象となるファイルはdetail.php、edit.php、delete.phpになります。 それぞれの箇所から該当する箇所を探して修正しましょう。
元の箇所
変更後
さてURLにIDが付与されてくるのは、いま修正した3つのファイルでしたが、 もう1カ所IDを受け渡す処理がありましたね。 更新作業の送信をした後にデータベースに書き込むupdate.phpです。 update.phpにも同様の処理を入れておきましょう。 該当する行を見てみると違いはGETとPOSTだけですね。同様に修正しておきましょう。
では、修正のテストしてみましょう。以下のテスト項目を満たしているか試してみましょう。
どうでしょう。追加、更新に問題は無かったですか?メッセージは正しく表示されましたか? 処理が上手くいかない場合はもう一度ソースコード見直しましょう。 エラーメッセージの内容をよく読んで、どこか原因か探りましょう。
detail.php、edit.php、delete.php共に修正して、index.phpからそれぞれの処理が正しく動作することを確認してください。
次は新規追加と更新の修正を行います。 つまりadd.phpとupdate.phpを修正します。
新規追加と更新の際には、ID以外の項目のバリデーションも行う必要があります。
ID以外の項目のバリデーションはadd.phpとupdate.phpで共通する部分が多いので、 先ほど覚えたinclude_onceを利用しましょう。 db_config.phpと同じ階層にerror_check.phpを作成しましょう。
いままではif文の後に{}で括らずに、すぐにthrow new Exceptionを記述していましたが、 判定やメッセージなど1行で表示するには長くなってきたので、 if{}の書き方にしましょう(いままでは誌面の節約のために1行の記述が多かったのですが、今後は{}を使うようにしましょう)。
それぞれのpreg_matchによる判定で利用している正規化表現はこのレッスンの冒頭で説明したものばかりです。内容を見比べてください。 POSTされたそれぞれの変数と比べてマッチしないもの(!を先頭に付ける)でExceptionを発生させます。 Exceptionの引数のエラーメッセージもエラーの内容がわかるものにしましょう。
後は実際にadd.phpとupdate.phpに、このファイルを読み込むだけです。db_config.phpの読み込み箇所を参考に追加してみましょう。
追加する箇所はtryのすぐ後で、項目ごとに変数に格納する前です。
※includeできない場合はファイル名で検索して、保存場所のパスを指定してください。
これでadd.phpとupdate.phpの修正は完了です。 includeさせると、そのファイルの中身がプログラムに取り込まれます。 これでadd.phpやupdate.phpが実行されるたびに毎回、いま作成したバリデーション処理が実行されることになります。
それでは、実際に予算に9999より大きな数字を入れてみて、メッセージを確認してみましょう。 エラーメッセージが表示されましたか? これでバリデーションは完成です。 お疲れ様でした!
バリデーションは仕様に沿った入力を行うために必要になります。 仕組みを覚えておいて、ぜひ活用してください。