観察 コマ7・8・23

入力と出力の可視化

入力例: HTMLタグ スクリプト 属性値を抜け出す 数字+末尾の改行 nullバイト UTF-8として不正なバイト列

① サーバーが受け取ったもの

バイト列(16進・先頭64バイト)3c 62 3e e5 a4 aa e5 ad 97 3c 2f 62 3e
バイト数 strlen()13
文字数 mb_strlen()9
UTF-8として正しいか mb_check_encoding()正しい
nullバイト(00)を含むか含まない

画面の入力欄に見えている文字と、サーバーに届いたバイト列は同じとは限らない。 改行・nullバイト・不正なバイト列は画面では見えにくいが、バイト列を見れば分かる。

② 検証(バリデーション):「数字だけか?」

preg_match('/^[0-9]+$/', $v)弾く
preg_match('/\A[0-9]+\z/', $v)弾く

$ は「末尾の改行の直前」にも一致するため、123+改行 を通してしまう。 文字列全体を検査するなら \A と \z を使う(「数字+末尾の改行」で試す)。

③ 出力:同じ値を、エスケープのしかただけ変えて表示する

下の枠は、サーバーが作った HTML をブラウザがどう解釈するかを見るための表示枠 (sandbox 付き iframe)。枠の中でスクリプトが動いても、演習サイトの Cookie には触れない。

エスケープなし

入力がそのまま HTML として解釈される。

<p>こんにちは、<b>太字</b> さん</p>
<input value='<b>太字</b>' size='40'>

htmlspecialchars($v, ENT_COMPAT)

< > & " は変換されるが ' は変換されない。シングルクォートの属性値では足りない。

<p>こんにちは、&lt;b&gt;太字&lt;/b&gt; さん</p>
<input value='&lt;b&gt;太字&lt;/b&gt;' size='40'>

htmlspecialchars($v, ENT_QUOTES, 'UTF-8')

正しい出し方。' も変換される。

<p>こんにちは、&lt;b&gt;太字&lt;/b&gt; さん</p>
<input value='&lt;b&gt;太字&lt;/b&gt;' size='40'>

保存前にもエスケープした(二重)

DB に入れる前にエスケープし、表示時にもエスケープした状態。&lt; のように二重に変換され、画面に記号がそのまま出る。

<p>こんにちは、&amp;lt;b&amp;gt;太字&amp;lt;/b&amp;gt; さん</p>
<input value='&amp;lt;b&amp;gt;太字&amp;lt;/b&amp;gt;' size='40'>

「UTF-8として不正なバイト列」を送ると、htmlspecialchars() は 空文字列を返す(不正な入力を黙って消す)。入力の段階で mb_check_encoding() で弾いておく理由の一つ。

まとめ

あなたの座席ID: 327b1a489cb2 この演習をリセット 演習一覧へ