PHP で h() を書くなら一緒に echo しよう。
名前が長い関数 htmlspecialchars() を h() と書けるようにすると便利、という話がある。
- PHP: htmlspecialchars - Manual
- htmlspecialchars関数を簡単に扱えるようにする
- 第1回 CakePHPを使いたくなる5つの特徴:CakePHPで高速Webアプリ開発|gihyo.jp … 技術評論社
htmlspecialchars() なんて長い名前は絶対忘れるし、ENT_QUOTESだのUTF-8だのも書き忘れるに決まっている。
h() は CakePHP でも使われていて、いいと思う。いいと思うんだけど、もうちょっといける。
<?php /** 改善前のエスケープ関数 */ function h($str) { return htmlspecialchars($str, ENT_QUOTES, 'UTF-8') }
このようにエスケープした結果をreturnで返すと、エスケープと出力を離して書けてしまう。
$name = h($name); : // 長い長い処理の後に : <?php echo $name; // たしかエスケープ済だったかな ?> <?php echo h($address); // こっちはエスケープしてなかったかも ?>
これだとぜったいエスケープし忘れる。もしくは二重にエスケープする。
エスケープが常に出力の直前になるように h() の中で echo も実行するといい。エスケープしていない(echoが直に書かれた)箇所を目立たせる結果にもなる。
<?php /** * HTMLの特殊文字をエスケープして結果を出力します。 */ function h($str) { echo htmlspecialchars($str, ENT_QUOTES, 'UTF-8'); }
次のように使う。
<?php h($name); ?> <?php h($address); ?>
htmlspecialchars() を実行した文字列に対して更に何か加工するのは例外的なケースだが、よくあるのは改行を<br/>にする処理で、これは hbr() として定義する。
<?php /** * HTMLの特殊文字をエスケープして改行の前にbrタグを追加し、結果を出力します。 */ function hbr($str) { echo nl2br(htmlspecialchars($str, ENT_QUOTES, 'UTF-8')); }
それ以外は頑張って htmlspecialchars() と書く、と言いたいけど、ENT_QUOTES、'UTF-8'を忘れそうなので、やはり関数を定義しておいたほうが安心かも。h() を使いたくなるように、名前は長めにする。
<?php /** * HTMLの特殊文字をエスケープして結果を返します。通常は h() を使います。 */ function htmlescape($str) { return htmlspecialchars($str, ENT_QUOTES, 'UTF-8'); }
配列をまとめてエスケープといった話はすっぱり忘れる。やるなら htmlescapeArray(array $array) を定義して、処理内容を明確にする。
参考
「出力の直前に」「例外なく」「エスケープしていることがわかるように」
セキュリティ云々以前に、プログラムの開発方法論として、できるだけ局所的な視点でコードの正当性を確認できるように書くのが、近代プログラミングの基本だ。つまり、このコード断片だけ見て、問題がないとわかるように書くべきである。
高木浩光@自宅の日記 - プログラミング解説書籍の脆弱性をどうするか, 「サニタイズ言うなキャンペーン」とは何か, ASPとかJSPとかPHPとかERBとか、逆だ..
:
たとえば、echo を全面的に使用禁止として次のように書くのもよいだろう。
PHP で何かを出力する際には,それが人の目に触れる形で表示されるかどうかにかかわらず,出力の直前に htmlspecialchars() を必ず通すようにしましょう。
セキュリティ上の配慮
以下の文字列をサニタイズする。サニタイズするタイミングは、データ受付時ではなく、HTML出力直前に例外なく行うこと。
セキュリティ指針/クロスサイトスクリプティング - ゼンド・ジャパン株式会社 技術情報コンテンツ
はまちちゃん先生の記事に触発されて書きました。