【PHP】Laravel-Validationのmaxでの落とし穴

元々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',
]
}

上のように設定してたのですが、バリデーションではじかれる場合と弾かれない場合がありました。
色々調査してみると以下のようなバリデーション結果のパターンがありました。

  1. 半角のみ NG
  2. 全角のみ OK (4000文字入力したらNG)
  3. 全半角 OK

全角が含まれるとなんか挙動が変になる。。。
詳細にmaxの処理を追ったわけではないのですが、おそらく内部ではmb_strlen()を使用しているような挙動でした。

mb_strlenに上記の3パターンで試してみた結果が以下です。(入力文字数
は2000文字)

  1. 半角のみ 2000
  2. 全角のみ 1000
  3. 全半角 (全角文字数/2 + 半角文字数)

 

自作した

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

The following two tabs change content below.

新歩一 正己

初めまして。 新歩一と申します。 現在開発系のフリーランスで4年目となります。 新しいもの好きなので色々開発言語は触っております。 Web関係、業務用システム構築がメインでJava, Javascript, PHP, Pythonを使っております。 オリンピック期間は国外逃亡します。(たぶん)

Related posts