元々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っていろんなライブラリありますね。