元々Javaを触っていて、最近はPHPのLaravel+VueでのMPAっぽいものの開発を行っています。
※MPA(Multi Page Application)はSPA(Single Page Application)と対比して使われている言葉です。イメージとしてはテンプレートエンジンとフロントのフレームワーク(VueやReact等々)とを併用して、必要な部分だけフロントのフレームワークを使用して開発します。
今回のお話は要約すると
全角が混ざる文字入力のバリデーションで、validationのmaxで文字数チェックするのはおすすめしない。
(Laravel: 5.8, PHP: 7.3)
ってお話です。
FormRequestを拡張してリクエストのチェックをしているのですが、文字数チェックのバリデーションをすり抜ける現象が発生してました。
例として、記事の本文などにこのようにValidationルールを記載していました。
public function rules() {
return [
'body'=> 'required|max:2000',
]
}
上のように設定してたのですが、バリデーションではじかれる場合と弾かれない場合がありました。
色々調査してみると以下のようなバリデーション結果のパターンがありました。
全角が含まれるとなんか挙動が変になる。。。
詳細にmaxの処理を追ったわけではないのですが、おそらく内部ではmb_strlen()を使用しているような挙動でした。
mb_strlenに上記の3パターンで試してみた結果が以下です。(入力文字数
は2000文字)
良さそうなValidationルールも特になかったので自作しました。(ホントにいいかはさておき)
全部全角にしてmb_strwidthでカウント。
<?php namespace App\Http\Rules; use Illuminate\Contracts\Validation\Rule; class WordCount implements Rule { /** * @var int */ private $max; /** * Create a new rule instance. * * @param int $max */ public function __construct(int $max) { $this->max = $max; } /** * Determine if the validation rule passes. * * @param string $attribute * @param mixed $value * @return bool */ public function passes($attribute, $value) { $trim = str_replace(array("\r\n", "\r", "\n"), '', $value); // まともにカウントできないので全部全角へ変換 $upper = mb_convert_kana($trim, 'RNASKHCV', 'UTF-8'); $mbLen = mb_strwidth($upper, 'UTF-8'); return $this->max >= $mbLen; } /** * Get the validation error message. * * @return string */ public function message() { return "「:attribute」は{$this->max}文字以下で入力してください"; } }
PHPっていろんなライブラリありますね。