LoginSignup
6
9

More than 5 years have passed since last update.

filter_input_array / filter_var_array の挙動がマニュアルの表記と違う件

Posted at

3行で

filter_input_arrayとかfilter_var_array
使い物にならないと思ってたけど実はそうでもなかった
ちゃんと確認せず記事書いてごめんなさい

問題

以下の記事を既に読まれている人向けです.

マニュアルの表記

filter_input_arrayのマニュアルの記述を見ると,以下のようなものがある.

例1 filter_input_array() の例

<?php
error_reporting(E_ALL | E_STRICT);
/* データは、実際には POST リクエストでやってきます
$_POST = array(
    'product_id'    => 'libgd<script>',
    'component'     => '10',
    'versions'      => '2.0.33',
    'testscalar'    => array('2', '23', '10', '12'),
    'testarray'     => '2',
);
*/

$args = array(
    'product_id'   => FILTER_SANITIZE_ENCODED,
    'component'    => array('filter'    => FILTER_VALIDATE_INT,
                            'flags'     => FILTER_REQUIRE_ARRAY, 
                            'options'   => array('min_range' => 1, 'max_range' => 10)
                           ),
    'versions'     => FILTER_SANITIZE_ENCODED,
    'doesnotexist' => FILTER_VALIDATE_INT,
    'testscalar'   => array(
                            'filter' => FILTER_VALIDATE_INT,
                            'flags'  => FILTER_REQUIRE_SCALAR,
                           ),
    'testarray'    => array(
                            'filter' => FILTER_VALIDATE_INT,
                            'flags'  => FILTER_REQUIRE_ARRAY,
                           )

);

$myinputs = filter_input_array(INPUT_POST, $args);

var_dump($myinputs);
echo "\n";
?>
上の例の出力は以下となります。
array(6) {
  ["product_id"]=>
  array(1) {
    [0]=>
    string(17) "libgd%3Cscript%3E"
  }
  ["component"]=>
  array(1) {
    [0]=>
    int(10)
  }
  ["versions"]=>
  array(1) {
    [0]=>
    string(6) "2.0.33"
  }
  ["doesnotexist"]=>
  NULL
  ["testscalar"]=>
  bool(false)
  ["testarray"]=>
  array(1) {
    [0]=>
    int(2)
  }
}

実際の出力

ところが実際はこうはならない.

実際の出力
array(6) {
  ["product_id"]=>
  string(17) "libgd%3Cscript%3E"
  ["component"]=>
  bool(false)
  ["versions"]=>
  string(5) "2.2.3"
  ["doesnotexist"]=>
  NULL
  ["testscalar"]=>
  bool(false)
  ["testarray"]=>
  bool(false)
}

疑問点

testarrayが配列キャストではなくbool(false)となる点

FILTER_FORCE_ARRAYと書こうとして,誤ってFILTER_REQUIRE_ARRAYと書いてしまっているから,であると推測できる.これは単なるドキュメントの不備として見てもいい.この点に関しては,今まで特に感じていたことは無かった.

product_idversionsが配列ではなく文字列になる点

この記事の本題.バリデーション成功時に配列になるのがfilter_input_arrayfilter_var_array特有の挙動ということで納得していた.自分の記憶では,実際にこれを動作させて確認したことになっていた.

…ところが,今確認してみると自分の記憶と矛盾した出力が発生した.さすがにおかしいぞ,と思ってPHP5.2.17という太古の環境をわざわざ用意して確認してみたが,おかしいのは自分の記憶のほうだった.

これからどうすればいいか

「そもそもバリデータとか普通フレームワークで用意されたやつ使うしこんな関数使わないっしょw」

…というのは尤もな意見だが,あくまでそういったものに頼らないという前提で書くと

filter_inputでスカラーを処理
$params = [
    'nickname' => filter_input(INPUT_POST, 'nickname'),
    'email' => filter_input(INPUT_POST, 'nickname', FILTER_VALIDATE_EMAIL),
    'age' => filter_input(INPUT_POST, 'age', FILTER_VALIDATE_INT, [
        'options' => [
            'min_range' => 0,
            'max_range' => 100,
        ],
    ]),
];
filter_input_arrayでスカラーを処理
$params = filter_input_array(INPUT_POST, [
    'nickname' => [],
    'email' => FILTER_VALIDATE_EMAIL,
    'age' => [
        'filter' => FILTER_VALIDATE_INT,
        'options' => [
            'min_range' => 0,
            'max_range' => 100,
        ],
    ],
]);

このようなコードは書ける.(string)キャストのようなものを入れない場合は後者のほうがいいかもしれない.しかし,配列の処理になると…

filter_inputで配列を処理
$params = [
    'hobbies' => filter_input(INPUT_POST, 'hobbies', FILTER_DEFAULT, FILTER_REQUIRE_ARRAY)
];
filter_input_arrayで配列を処理
$params = filter_input_array(INPUT_POST, [
    'hobbies' => ['flags' => FILTER_REQUIRE_ARRAY],
]);

これらのコードはいずれとも

  • 配列の強制ができない
    (FILTER_FORCE_ARRAYにしても未定義時にはNULLにされてしまう)
  • 配列の階層数の指定ができない

など大きな欠点があるため,実用的ではない.結局,

というところに落ち着くのである.

6
9
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
6
9