PHPのフィルタ関数を使ったバリデーション&サニタイジング

PHPのフィルタ関数を使ったバリデーション&サニタイジング

こんにちは、春が来て嬉しいsagaraです。
フレームワークを使っていると、フレームワークに用意されている独自のバリデーション(入力検証)機能を用います。 例えばCakePHPでメールアドレスのバリデーションを行うメソッドは、 がっつり正規表現でやっています。

比較的単純なバリデーションであれば、今回紹介するPHPのフィルタ関数filter_var()で実現できます。 また、サニタイジング(コード無害化)向けの定数もあります。

というわけで、今回はPHPのフィルタ関数を使ったバリデーション&サニタイジングについてお話します。

フィルタとは

フィルタはPHPの拡張モジュールであり、PHP5.2以降デフォルトで有効になっています。
メールアドレス、IPアドレス、URLなどが適切な書式になっているかを判断するのに使えます。
バリデーションを行う検証フィルタと、不適切な文字列を消去したりエンコードしたりする除去フィルタが存在します。

filter_var()でフィルタ処理

filter_var($string, $filter, $options);

第1引数に対象の文字列、第2引数にフィルタの種類(定数)、第3引数にオプションを設定することができます。 検証に通過した場合はもとの文字列が返り値として返されます。そうでない場合はfalseが返されます。

配列をフィルタする場合はfilter_var_array()関数が用意されています。

filter_var_array($array, $filter);

検証フィルタを使ったバリデーション

メールアドレスの検証

文字列がe-mail形式であるかを確認する場合は、FILTER_VALIDATE_EMAILを使います。

//OKの場合は文字列をそのまま返す
$input = 'hoge@fuga.jp';
$output = filter_var($input, FILTER_VALIDATE_EMAIL); //→hoge@fuga.jp

//NGの場合はfalseを返す
$input = 'hoge@fuga';
$output = filter_var($input, FILTER_VALIDATE_EMAIL); //→bool(false)

//optionsにdefaultを指定すると、NGの場合にdefaultで指定した値を返す
$input = 'hoge@fuga';
$output = filter_var($input, FILTER_VALIDATE_EMAIL,
    ['options' =>
        ['default' => 'info@example.com']
    ]); //→info@example.com

IPアドレスの検証

文字列がIP形式であるかを確認する場合は、FILTER_VALIDATE_IPを使います。
デフォルトではIPv4とIPv6の両方が許可されています。 オプションにFILTER_FLAG_IPV4や、複数指定の場合は'flags' => [ FILTER_FLAG_IPV4 , FILTER_FLAG_IPV6 ]などと 指定することでIP形式を指定できます。

//文字列がIPv4形式かどうか検証
$ip = '192.168.33.10';
filter_var($ip, FILTER_VALIDATE_IP,
    ['options' =>
        ['flags' => FILTER_FLAG_IPV4]
    ]); //→192.168.33.10

URL形式の検証

文字列がURL形式であるかを確認する場合は、FILTER_VALIDATE_URLを使います。

//文字列が正しいURL形式かどうか検証
$url = 'http://bashalog.c-brains.jp';
filter_var($url, FILTER_VALIDATE_URL,
    ['options' => 
        ['default' => 'https://hoge.com']
    ]); //→http://bashalog.c-brains.jp

配列を検証

連想配列のキーによって各々の値に対して検証フィルタまたは除去フィルタを適用します。
検証フィルタと除去フィルタを混ぜて使用することもできます。

$input = ['mail' => 'hoge@fuga.jp', 'url' => 'http://fuga.jp/'];
$output = filter_var_array($input, [
    'mail' =>  FILTER_VALIDATE_EMAIL,
    'url' => [
        'filter' => FILTER_VALIDATE_URL,
        'flags' => FILTER_FLAG_PATH_REQUIRED  //URLにパス部分を求める
    ]]);//→['hoge@fuga.jp', false]

コールバックフィルタ

FILTER_CALLBACKを指定して、コールバック関数を利用することができます。

//入力が正の数の場合は通過させるコールバック用関数
function positive_number($num){
    return $num > 0 ? $num : false;
}

$input = -99;
$output = filter_var($input, FILTER_CALLBACK,
    ['options' => 'positive_number']); //→bool(false)

除去フィルタを使ったサニタイジング

文字列に不適切な文字が含まれている場合に、除去または変換(エンコード)してくれるのが除去フィルタです。 除去フィルタは除去後のデータの妥当性の確認は行わないので、 やや使いどころを選ぶかもしれません。

メールアドレスに除去フィルタ

FILTER_SANITIZE_EMAILを指定して、メールアドレスで許可されていない文字を取り除くことができます。

$address = 'hoge<HOGE>@fuga.jp';
filter_var($address, FILTER_SANITIZE_EMAIL); //→hogeHOGE@fuga.jp

URLに除去フィルタ

FILTER_SANITIZE_URLを指定して、URLで許可されていない文字を取り除くことができます。
とはいえ、引用符やセミコロンも通ってしまうので、これで無害化できるかと言えばかなり微妙。

$url = 'http://bashalog.c-brains.jp#?=&;';
filter_var($url, FILTER_SANITIZE_URL); //→http://bashalog.c-brains.jp#?=&;

文字列のエンコード

FILTER_SANITIZE_ENCODEDを指定して、文字列のエンコードができます。同等の処理がurlencode()でもできます。

$str = '<a href = "hoge">hoge</a>'
filter_var($str, FILTER_SANITIZE_ENCODED); //%3Ca%20href%3D%22hoge%22%3Ehoge%3C%2Fa%3E

おわりに

フィルタのバリデーションやサニタイジングは、文字列に対する機械的な処理ですので、サービスなどで入力値の検証を行う場合は注意が必要です。 ですので使いどころは限られますが、簡単にフォームの入力を検証したい場合に使える機会があるかもしれません。

参考

データのフィルタリング(PHP公式)

  • このエントリーをはてなブックマークに追加

この記事を読んだ人にオススメ