2007年11月30日

CodeIgniterのValidationクラスは使えなかった(--;

前回は愚痴っぽくなりましたが、今回も半分は愚痴です。

前回の最後で検索機能を強化してみたい…などと書きましたが、やはりその前にできるだけスクリプトを綺麗にしておきたいという気持ちが強く、まあごにょごにょいじってたわけですが、そういえば入力データを全然チェックしてなかったなぁ?などと今更になって気づきました。

そこで今回は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クラスをロードするのもなんだなぁ…と。

そうすると一体このクラスはどういう用途を想定してるんだ?ということなんですが、これは冒頭述べたとおりログインフォームぐらいにしか使えないんじゃないかな?。それ以外でこのクラス使ってる人がいたら教えてください。(あ、いや教えてもらわなくてもいいや…)
posted by ciallost at 02:46| Comment(4) | TrackBack(0) | 日記 | このブログの読者になる | 更新情報をチェックする
この記事へのコメント
http://codeigniter.com/wiki/Validation_Class/

更新止まってますね。
お忙しいのでしょうが、記事楽しみにしていますので再開を心待ちにしております。
Posted by しまこ at 2009年07月26日 03:50
残念だけど、CodeIgniterのValidationクラス読んでみたら、いかに勝手な思い込みで使ってるかわかるよ。CodeIgniterはパッケージが小さいからコードを気軽に読めるんだよ。
ちょっと残酷だけど、使えないのはフレームワークを理解できないお前の能力と思ってしまう。
スマン。
Posted by た at 2009年10月05日 17:20
GETとPOSTの使い分けについては最近のREST論争を見れば分かるとおもいますので参照してみてください。別にValidationがPOSTだけにしか使えないからって悪いとは思いません。
Posted by し at 2011年04月02日 15:58
パイプの部分は自分の好きなように拡張してしまえば良いのでは?
呼ぶ前に$_POSTにセットすれば良いのでは?
Posted by at 2012年08月20日 15:47
コメントを書く
お名前:

メールアドレス:

ホームページアドレス:

コメント:

認証コード: [必須入力]


※画像の中の文字を半角で入力してください。
この記事へのトラックバックURL
http://blog.seesaa.jp/tb/70090982

この記事へのトラックバック
×

この広告は1年以上新しい記事の投稿がないブログに表示されております。