7
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

filter_var関数とLaravelの落とし穴

Posted at

tl;dr

  • filter_var('1 ', FILTER_VALIDATE_INT) としたときの戻り値は 1
  • これが引き金になってLaravelのバリデーションルールに integer を使っても '1 ' が素通りする

はじめに

PHPの標準関数には罠があるものが数多ありますが、今回はfilter_var関数の罠について書きます。

filter_var関数とは

PHP: filter_var - Manualによれば

指定したフィルタでデータをフィルタリングする

とのことです。巷ではバリデーションに使われているようです。

以下のコードを実行したときの戻り値はどうなるでしょうか。

filter_var('1 ', FILTER_VALIDATE_INT);

このコードによって 1 が返ってきます。いかにもPHPらしいですね。
実行結果は https://wandbox.org/permlink/m4jD8Iiktn4VaQXb でご覧になれます。

filter_var関数の第2引数に渡しているFILTER_VALIDATE_INTPHP: 検証フィルタ - Manualによると以下の効果があります。

値が整数であるかどうか、オプションで指定した範囲内にあるかどうかを検証し、成功した場合は整数に変換します。

'1 'が整数であるかどうかについて、PHP的には整数ということですね。
検証としてはどうなんだろうと思うところであります。

Laravelにおける落とし穴

Laravelのバリデーションルールとしてintegerを使ったときに呼ばれるメソッドに利用されています。
https://github.com/laravel/framework/blob/fe1ef6570d10c955da8e90c8be429d96ad5574ee/src/Illuminate/Validation/Concerns/ValidatesAttributes.php#L813-L823

    /**
     * Validate that an attribute is an integer.
     *
     * @param  string  $attribute
     * @param  mixed   $value
     * @return bool
     */
    protected function validateInteger($attribute, $value)
    {
        return filter_var($value, FILTER_VALIDATE_INT) !== false;
    }

つまり、Laravelではバリデーションルールintegerを使っても'1 'は整数であると認識されます。そして、バリデーションを通過した値を得るにしてもfilter_var関数を通した値が得られるわけではなく、元の入力値が得られます。
なので、たとえばCarbonオブジェクトのyearなどに代入しようとするとErrorException (A non well formed numeric value encountered)となります。

おわりに

いかにもPHPらしい感じです。気をつけましょう。

7
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?