HTML を壊す 5 つの文字
HTML パーサーは < をタグの開始、& をエンティティ参照の開始として読みます。コンテンツにこれらが含まれていると、パーサーはそこをテキストとして扱わなくなります。エスケープとは、その文字を参照に置き換えることで、パーサーが元の字形に復元しつつ構造上の意味を一切与えないようにする処理です。
HTML で本当にエスケープが必要な文字は 5 つだけです。
& → & — 最初に置換すること。さもないと他のエスケープが二重になります
< → <
> → >
" → " — 二重引用符の属性値の中では必須
' → ' — 一重引用符の属性値の中では必須
厳密には、要素のテキストでは & と < だけで足ります。残りの 3 つはテキストが属性値に入りうる場合に効いてきますが、エスケープする時点で行き先を制御できることはまれなので、5 つすべてを処理するのが安全な習慣です。
名前付き・10 進・16 進の参照
同じ文字を 3 通りに書けます。ノーブレークスペースは 、 、  のいずれでも表せます。名前付き参照が最も読みやすいものの、HTML5 の名前表は約 2,200 件あり、古いパーサーが知っているのははるかに少ないため、珍しい名前は移植性のリスクになります。数値参照は任意の Unicode コードポイントで使え、常に安全です。HTML5 では名前付き参照に末尾のセミコロンが必須です。& のような一部のレガシー名は後方互換のためセミコロンなしでも解析されますが、それに頼るのは事故のもとです。
エスケープはサニタイズではない
エスケープはクロスサイトスクリプティングを止める要です。<script> を含むユーザー入力が <script> にエスケープされれば、ブラウザは文字どおりのテキストを表示するだけで何も実行しません。ただし、エスケープは正しいコンテキストで行われて初めて機能します。<script> ブロック内、style 属性内、URL の中では HTML エスケープでは不十分で、それぞれ固有のエンコードが必要です。さらにエスケープは出力時に 1 回だけ適用します。入力時と出力時の両方でエスケープすると &lt; が生まれ、画面に文字化けが出ます。
拡張モードが必要な場面
非 ASCII 文字のエスケープを求める現代仕様はありません。UTF-8 文書は é や 中 をそのまま含められますし、通常はそのほうが望ましい選択です。短く、読みやすく、検索もしやすくなります。拡張モードは、バイト列が非 ASCII を壊すチャネルを通らなければならない場合のためにあります。レガシーなメールテンプレート、古い CMS のフィールド、宣言エンコーディングが不明瞭な XML パイプライン、Latin-1 のままのビルド工程などです。エンコーディングを端から端まで制御できるなら最小モードのままで構いません。
ノーブレークスペースの罠
は U+00A0 であり、通常の空白 U+0020 とは別の文字です。改行を防ぎ、連続する空白の圧縮も抑止するため、WYSIWYG エディタが多用します。見た目が同一なので、文字列比較、エンジンによっては \s で書いた正規表現、CSV の取り込みを静かに壊します。値が正しく見えるのにどうしても一致しないときは、紛れ込んだノーブレークスペースを疑ってください。