前回の最後で検索機能を強化してみたい…などと書きましたが、やはりその前にできるだけスクリプトを綺麗にしておきたいという気持ちが強く、まあごにょごにょいじってたわけですが、そういえば入力データを全然チェックしてなかったなぁ?などと今更になって気づきました。
そこで今回はCodeIgniterのValidationクラスを使ってみることにしたのですが、結論から言えば、これは使えませんでした。
ユーザからの入力データをそのまま信用してスクリプトで用いることは、ご法度というよりもはや犯罪行為に近いかのように、巷ではうるさく言われています。まあ個人的な趣味のスクリプトとはいえ、それを踏み台にされてどーのこーの…ということが日常茶飯事らしいので、このような傾向にあるのは致し方ないとはおもいますが、スクリプトを書く身としてはメンドイことが増えるなぁ…と。
で、そうした悪事を防ぐ意味でサニタイズとかヴァリデーションとか言われていますが、サニタイズってのはぶっちゃけデータベースにクエリを発行する時とHTMLに表示する時だけ気をつけてればまあいいかなぁ?と。
前者はSQLインジェクション防止のため、後者はXSS防止のためということらしいですが、これらはSQL組立でプリペアードステートメントを使うなりアクティブレコードに任せるなりエスケープするなり、後者は表示直前にえいちてぃーえむえるすぺしゃるきゃらすれば一応大丈夫ってことになってるらしいです。共通していることはクエリ送信の直前とかHTML表示の直前とかに処理を施すってことでしょうか。
んでヴァリデーションの方はサニタイズとは逆に入力された時にそれが想定の範囲内かどうか?をチェックする〜みたいな。
ところが想定される入力値というのはまさに千差万別で、同じformから送られてくるものでも、フィールドやその他のUIなんかで微妙にチェック基準が違ってしまいます。なので手続き型だと$_POST['hoge']を直接扱うことはまずしなくて、例えば…
$hoge = preg_replace("/[^0-9]/", "", $_POST['hoge']);
のように数値以外は問答無用で削除したり、文字列の長さを調べてみたりなどしてから$hogeの方を使ったりするわけです。
で、CodeIgniterのユーザガイドを見ると…
上で挙げたプロセスには何ら複雑なものはありませんが、たいてい大量のコードが必要になり、エラーメッセージを表示させるために、フォームHTMLの中に、さまざまな制御構造が書かれることになります。フォームの検証は、難しくなくつくれますが、実装するのはいつも面倒で退屈です。
なんて書いてあって、そうそうその通りその通り!これをすっきり書きたいんだ!と諸手を上げて賛同します。さらに…
CodeIgniter では、書く必要があるコードを最低限にとどめる包括的なバリデーション(検証)フレームワークが提供されています。 また、このフレームワークを使うと、HTMLフォームから制御構造を取り除くことができ、コードをわかりやすく、メンテナンスしやすいようにすることができます。
なんて太字でしかも緑色で書いてあって「さすがCodeIgniterだ!」「やはりこのフレームワークを選択して間違いなかった」と思わせてくれます。
んで喜んでられるのはその辺までで、結局使えません(--;。いや、まあみんながみんな使えないというわけではないでしょう(ないと思いたい…)。おそらくこれはログインの画面みたいなもの(それだけともいえよう)を作る場合には重宝しそうな気はしますが…。
まずココで作ってる検索アプリですが、検索フィールドが3つ(都道府県・新市町村・旧市町村)あって、そのテキストフィールドはnameが配列になっているわけです。
都道府県<input type="text" name="condition[pref]" />
新市町村<input type="text" name="condition[nc]" />
旧市町村<input type="text" name="condition[oc]" />
で、validationクラスの説明の通り
$this->load->library('validation');
$rules['condition[pref]'] = "required";
$rules['condition[nc]'] = "required";
$rules['condition[oc]'] = "required";
$this->validation->set_rules($rules);
のように書いて試してみましたが、↑のコードは動きません。
配列のキーの書き方が問題ありっぽかったので、$rules["condition['pref']"]とか$rules[condition[pref]]とかいろいろやってみましたが全部ダメでした。
そこでそもそもこのような書き方、つまり配列のキーに配列?を書くようなことがPHP的にNGなんじゃないか?とおもい、PHPのマニュアルを見ながらechoしたりしてみましたが、どうもこの書き方自体は間違ってない?というか一応ちゃんと値もセットできるし取り出すこともできました。
そこで今度は$_POSTの配列自体がどうなってるのかとおもいprint_r()してみたら…
Array
(
[condition] => Array
(
[pref] => 神奈川
[nc] => 相模
[oc] => 津久井
)
)
当たり前ですが、多次元配列になっているわけです。なので…
$rules['condition']['pref'] = "required";
のように書いてみました。するとさっきまでと違うエラーが…
A PHP Error was encountered
Severity: Notice
Message: Array to string conversion
Filename: libraries/Validation.php
Line Number: 195
つまり配列が強制的に?文字列にされちゃったよぉ〜ということらしいので、ソースを覗いて見ました。そしたらなんと$rulesは一次元配列だけを想定されているようです。どうもValidationクラスの説明にあるルールのパイプ機能が問題っぽく、「|」でパイプされてるルールをexplodeしている部分で上記のエラーが出ているようでした。
というわけでformのテキストフィールドの名前を配列にしている以上、このままだとvalidationクラスは使えません。libraries/Validation.phpのソースを若干いじってみようかなぁと途中までやってみたりしたんですが、どうもその部分のコードが長くて挫折しました。
んで、結局検索フィールドのヴァリデーションはあきらめて自力で実装することにしたのですが、↑のソースを見ていてちょっとオヤ?とおもったのは、なんと$_POSTがハードコーディングされていたという部分です。
結局コレってPOSTにしか使えないんじゃないの?という疑問が…。そういえばユーザガイドのどこにも任意のデータを渡してごにょごにょできますみたいなことは書かれてません。ということはココで作ってる検索アプリの場合だと五十音パッドから送られてくるデータとかソートした時とかページ移動した時とかのパラメータなんかはPOSTではないので、結局validationクラスは使えないってことになります(--;。
んで上述の通り唯一(ではないけど)使えそうな検索フィールドもnameが配列になってるとダメ、残るは表示件数と表示モード(これらは独立したformでしたがうざいので結局一つにまとめちゃいました)のformから送られてくるデータですが、なんかこれだけのために結構重そう(ユーザガイドにも書いてありますが)なValidationクラスをロードするのもなんだなぁ…と。
そうすると一体このクラスはどういう用途を想定してるんだ?ということなんですが、これは冒頭述べたとおりログインフォームぐらいにしか使えないんじゃないかな?。それ以外でこのクラス使ってる人がいたら教えてください。(あ、いや教えてもらわなくてもいいや…)
ラベル:codeigniter 愚痴