経緯
ぼく「POSTされた値を受け取るときのフィルタってなにがええんやろな~」
ぼく「お、FILTER_SANITIZE_SPECIAL_CHARS
安全そうでええやん!」
~数日後~
ぼく「POSTで来た値をHTMLに出力するときにはhtmlspecialchars
!常識だよね!」
~半年後~
お客様「'
って入力したら'
に文字化けするんだけど!!」
ぼく「ふええええ」
原因
FILTER_SANITIZE_SPECIAL_CHARS
'"<>& および ASCII 値が 32 未満の文字を HTML エスケープします。オプションで、 特殊文字を取り除いたりエンコードしたりします。
ENT_QUOTES
シングルクオートとダブルクオートを共に変換します。
つまり、
$input = filter_input(INPUT_POST,"hoge",FILTER_SANITIZE_SPECIAL_CHARS);
echo htmlspecialchars($input,ENT_QUOTES,'UTF-8');
とすると、
'"<>&
が多重エスケープされてしまいます。
本来なら、入力の受け取り時はバリデーションのみ、出力時にエスケープとするのが妥当(らしい)なのですが、
PHPの除去フィルタのうちの一部が除去するだけでなくエスケープまで行っているので、こうなってしまいました。
おまけ
ヌル文字とかを弾きたかったら、FILTER_SANITIZE_STRING
とFILTER_FLAG_STRIP_LOW
を使って以下のようにするのをおススメします。(フィルタ名にはサニタイズが入っているが、エンコードじゃなくて除去をしてくれる。)
$input = filter_input(INPUT_POST,"hoge",FILTER_SANITIZE_STRING,FILTER_FLAG_STRIP_LOW);
注意点としては、\n
などの制御文字も弾かれてしまいます。(ASCIIで32未満なので。)
ちなみにFILTER_FLAG_STRIP_HIGH
を使うとマルチバイト文字が弾かれてしまいます。英数字のみ入力のときに使えます。
どうしてもサニタイズしてほしくない人は、FILTER_UNSAFE_RAW
と各種フラグを使えば良さそうです。
PHPマニュアルをよく読んで、自分に合った君だけの除去フィルタを手に入れよう!