2015.11.19
0からはじめるPHP#57【TDDで作り直す掲示板#5-カスタムバリデーション-】
僕もはやく実装をしたいのですが、こういう基礎知識というか
仕様にハマってなかなか先に進まないことが多くてですね・・・・・・。
初心者のプログラミングって時間効率最悪ですよ。バグが1個出るだけで普通に数時間~数日吸われますからね・・・・・・。
for文の無限ループみたいなわかりやすいバグだったらいいんですけど、もっと深い要因になると、それはもう・・・・・・。
ということで、今回は僕が1日無駄に消費した
カスタムバリデーションの話をするとしましょう。
今回導入するルールは
「no_ctrl_chars」「no_ctrl_chars_lb」の2種類のルールです。
no_ctrl_charsに関しては
#43でちょろっと触れてるんですが
実はあれでは日本語が使えません。
プログラミングの世界ではよくあるんですが
サンプルがそもそも間違っているという典型例ですね。
ちなみに僕が今まで書いたサンプルもバグが多かったりしますが、気付き次第このように後で書くことにしています。例えば
#47で触れた暗号化も実はあれではちゃんと動かないんですよね。
いや、大体は動くので見逃してたんですが、色々ためしてみると動かない時があって・・・・・・
話が逸れましたね。
まぁこっちでは丁寧に一から解説していこうかなと思います。
まず、
app/Validation/ParameterValidator.phpを作成します。名前はなんでもいいかも知れません。
<?php namespace App\Validation;
class ParameterValidator
{
/**
* @param $attribute
* @param $value
* @param $parameters
* @return bool
*/
public function validateNoControlCharacters($attribute, $value, $parameters)
{
if (preg_match('/^[[:^cntrl:]]+$/', $value)) {
return true;
}
return false;
}
public function validateNoControlCharactersPermitLb($attribute, $value, $parameters)
{
if (preg_match('/^[\r\n\t[:^cntrl:]]+$/', $value)) {
return true;
}
return false;
}
}
(追記)「む」が入力できないなどの問題があるので、最後に改良したものを載せます。
以前紹介したサイトと異なるのは
preg_match()を使っているところです。
mb_eregでは内部文字エンコーディングをいちいち変えないと正常に処理がされないようで、ダンプして確認してみると
SJISで処理されているんですね。
なので
mb_regex_encoding("UTF-8");としてUTF-8に明示的に変えてやらなければなりませんでした。
そしてさらに調べてみると
ereg()はそもそも非推奨になっていたので、推奨されているpreg_match()を使います。こちらはデフォルトできちんとUTF-8になってるんで問題なく動作します。デリミタが必要になっていることに注意ですね。
ここで2つのカスタムバリデーションを実装していますが、Lbがついてる方は
改行を許可するバリデーションです。
制御文字に改行文字が含まれているため、本文は改行文字を許可しなければなりません。\tは
タブ文字らしいです。まぁ別にこれは受け入れなくても良いかも知れませんが一応・・・・・・。
ちなみに、空白文字全てを意味する\sという制御文字があるのですが、これを用いると\f(改ページ)なんていう物騒なものも許可してしまうので良くないと思います。詳しくないので危険かどうかは知りませんが・・・・・・。
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use Validator;//これも追記すること!
public function boot()
{
//カスタムバリデーション
Validator::extend('no_ctrl_chars', 'App\Validation\ParameterValidator@validateNoControlCharacters');
Validator::extend('no_ctrl_chars_lb', 'App\Validation\ParameterValidator@validateNoControlCharactersPermitLb');
/////////
}
次のステップは
app/Providers/AppServiceProvider.php の bootメソッド内に上記を追記します。
ここでのポイントとしては
バリデーション名は全て小文字にすることです。
僕は最初
「no_ctrl_chars_Lb」としていて泥沼にハマり
1日分くらい無駄にしたんですが、小文字に変えてみるとあっさり解決しました。どうやらそういう仕様らしいです。
あ、4行目のuse Varidator;がないと動きません。
で、最後にエラーメッセージの追加ですね。
これは
これを
resources/lang/ja/validation.phpにすれば良いです。
勝手にtxtファイル化してるので、もしphpに戻しても動かなかったらすみません。(笑)
ただ、僕が拾ったファイルはどっかが壊れてた記憶があるので、それを修正したバージョンになります。ついでに上で追加したルールのエラーメッセージも入れてたりします。
このファイルを使うためには
config/app.phpの locale を ja に変更という手順を踏めばそれで置き換わります。
他のバリデーションを実装した方はそれに応じてエラーメッセージを追加すれば良いかなと思います。さすがにこれは説明要らないでしょ(笑)
これでめでたくカスタムバリデーションが実装できましたね。
制御文字を禁止することはセキュリティ的にも好ましいと思いますので、取り入れてみても良いかなーと思います。
(追記)
class ParameterValidator
{
/**
* @param $attribute
* @param $value
* @param $parameters
* @return bool
*/
static $preg='[:^cntrl:]ぁ-んァ-ヶ亜-黑a-zA-Z0-9!”#$%&’()*+-.,/:;<=>?@¥^_~{|}「」○?◎● ー。「」、・ヲァィゥェォャュョッタアイウエオカキクケコサシスセソミチツテトナニヌネノハヒフヘホマムメモヤユヨラリルレロワン゙゚!"#$%&()*+-.,:;<=>?@\^_`{|}~\[\]';
public function validateNoControlCharacters($attribute, $value, $parameters)
{
if (preg_match('/\A['.self::$preg.']+\z/', $value)) {
return true;
}
return false;
}
public function validateNoControlCharactersPermitLb($attribute, $value, $parameters)
{
if (preg_match('/\A['.self::$preg.'\r\n\t]+\z/', $value)) {
return true;
}
return false;
}
public function validateNot_empty($attribute, $value, $parameters)
{
if (preg_match('/\A(\s| )+\z/', $value)) {
return false;
}
return true;
}
}
最終的にはこうなりました。参考にどうぞ。実はシングルクォート抜けてますけど必要だったら追加してください笑