3行で
filter_input_arrayとかfilter_var_arrayが
使い物にならないと思ってたけど実はそうでもなかった
ちゃんと確認せず記事書いてごめんなさい
問題
以下の記事を既に読まれている人向けです.
マニュアルの表記
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_id
やversions
が配列ではなく文字列になる点
この記事の本題.バリデーション成功時に配列になるのがfilter_input_array
やfilter_var_array
特有の挙動ということで納得していた.自分の記憶では,実際にこれを動作させて確認したことになっていた.
…ところが,今確認してみると自分の記憶と矛盾した出力が発生した.さすがにおかしいぞ,と思ってPHP5.2.17という太古の環境をわざわざ用意して確認してみたが,おかしいのは自分の記憶のほうだった.
これからどうすればいいか
「そもそもバリデータとか普通フレームワークで用意されたやつ使うしこんな関数使わないっしょw」
…というのは尤もな意見だが,あくまでそういったものに頼らないという前提で書くと
$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,
],
]),
];
$params = filter_input_array(INPUT_POST, [
'nickname' => [],
'email' => FILTER_VALIDATE_EMAIL,
'age' => [
'filter' => FILTER_VALIDATE_INT,
'options' => [
'min_range' => 0,
'max_range' => 100,
],
],
]);
このようなコードは書ける.(string)
キャストのようなものを入れない場合は後者のほうがいいかもしれない.しかし,配列の処理になると…
$params = [
'hobbies' => filter_input(INPUT_POST, 'hobbies', FILTER_DEFAULT, FILTER_REQUIRE_ARRAY)
];
$params = filter_input_array(INPUT_POST, [
'hobbies' => ['flags' => FILTER_REQUIRE_ARRAY],
]);
これらのコードはいずれとも
- 配列の強制ができない
(FILTER_FORCE_ARRAY
にしても未定義時にはNULLにされてしまう) - 配列の階層数の指定ができない
など大きな欠点があるため,実用的ではない.結局,
- filter_input_array_recursiveのような関数を作る
- フレームワークのバリデータを信じてそちらに丸投げする
というところに落ち着くのである.