RitoLabo

PHPのhtmlentities()とhtmlspecialchars()の違いと適切なエンティティ変換

  • 公開:
  • カテゴリ: PHP Basics
  • タグ: PHP,Entity,Basics

アジェンダ
  1. htmlentities
  2. htmlspecialchars
  3. 共通オプション
    1. フラグ定数(第二引数オプション)
    2. エンコーディング(第三引数オプション)
    3. 既存のhtmlエンティティ取扱い(第四引数オプション)
  4. htmlentities関数とhtmlspecialchars関数の違い
    1. デフォルト処理
    2. シングルクォーテーションも変換対象に含む
    3. エンティティ変換をデコードする
    4. get_html_translation_table()

HTMLに用いられる文字列には「特殊文字」と呼ばれるものがあります。代表的なものは「<」大なりや「>」小なり、「”」ダブルクオートや「’」シングルクオート、そして「&」アンパサンドなどの一般的な記号がありますが、他にも、数学記号やギリシャ文字など、OSやWebブラウザの種類によっては正しく表示できないものもこれに当たります。

特殊文字をHTML上に展開する場合、そのまま出力すると文字化けを起こしたりHTML構造が壊れたりしてしまう場合があるので、適宜エンティティ変換を行う事が推奨されます。

PHPではこれらのエンティティ変換用にhtmlentities関数とhtmlspecialchars関数が用意されています

htmlentities

適用可能な文字を全てHTMLエンティティに変換する(PHP 4, PHP 5, PHP 7)

htmlentities(string $string, int $flags, string $encoding, bool $double_encode);
$string
変換対象文字列
$flags
フラグ定数(デフォルト:ENT_COMPAT | ENT_HTML401)
$encoding
エンコーディング(デフォルト:ini_get("default_charset"))
$double_encode
既存のhtmlエンティティ取扱い(デフォルト:TRUE)

[公式]htmlentities
http://php.net/manual/ja/function.htmlentities.php

htmlspecialchars

特殊文字をHTMLエンティティに変換する(PHP 4, PHP 5, PHP 7)

htmlspecialchars(string $string, int $flags, string $encoding, bool $double_encode);
$string
変換対象文字列
$flags
フラグ定数(デフォルト:ENT_COMPAT | ENT_HTML401)
$encoding
エンコーディング(デフォルト:ini_get("default_charset"))
$double_encode
既存のhtmlエンティティ取扱い(デフォルト:TRUE)

[公式]htmlspecialchars
http://php.net/manual/ja/function.htmlspecialchars.php

共通オプション

htmlentities関数とhtmlspecialchars関数の引数項目は全て共通になっています。

フラグ定数(第二引数オプション)

ダブルクオート変換 シングルクオート変換
1. ENT_COMPAT ×
2. ENT_QUOTES
3. ENT_NOQUOTES × ×

※デフォルトはENT_COMPAT

無効な符号単位シーケンスを含む文字列 備考
4. ENT_IGNORE 無効な部分を切り捨て セキュリティに問題があり使用は非推奨
5. ENT_SUBSTITUTE Unicodeの置換文字に置き換える UTF-8なら「U+FFFD」それ以外は「&#FFFD」
6. ENT_DISALLOWED
無効な符号位置をUnicodeの代替文字である U+FFFD (UTF-8) もしくは &#FFFD; で置き換える。
設定しない場合は無効な符号位置をそのまま残す。
外部コンテンツを埋め込んだXML文書を整形式に保つために有効。
コード処理書式
7. ENT_HTML401 HTML 4.01
8. ENT_XML1 XML 1
9. ENT_XHTML XHTML
10. ENT_HTML5 HTML 5

エンコーディング(第三引数オプション)

エンコーディングは、セットしない場合デフォルトでphp.iniのdefault_charsetで設定されている文字セットが適用されます。(設定値は公式ページを参照してください。)

既存のhtmlエンティティ取扱い(第四引数オプション)

このオプションは、エンティティ変換に二重処理を防止する為のオプションで、デフォルトではON(true)に設定されています。つまりは、既にエンティティ変換が行われているものについては変換処理を行わない為の設定です。

例えばこのオプションをOFF(false)に設定した場合、重ねてエンティティ変換が行われると以下のようになります。

&
// 1回目のエンティティ変換
&
// 2回目のエンティティ変換
&
// 3回目のエンティティ変換
&

「&」部分が何重にもエンティティ変換されていってしまい、文字参照・実体参照として成立しなくなります。

htmlentities関数とhtmlspecialchars関数の違い

結論から言うと、両者の違いは「エンティティ変換として取り扱う対象の違い」です。

htmlspecialchars()で変換対象となる文字は以下になります。

  • 「& (アンパサンド)」
  • 「" (ダブルクォート) 」(※オプションによる)
  • 「' (シングルクォート)」(※オプションによる)
  • 「< (小なり)」
  • 「> (大なり) 」

HTMLタグなどコードの一部として機能するものが変換対象となっています。

一方、htmlentities()に関しては、エンティティ変換可能なもの全てが変換対象となっています。(こちらもオプションによって変動があります)

以下に、両者の処理の違いを示しますが、まず前提として、変換対象として渡すテキストは以下のようになっています。

// 元となるテキスト
$text = '<あいう&"えおか"&\'きくけ\'> 記号 ⇒「c」「≠」「£」「→」「⇔」';

わかりやすいように、ひらがな・漢字、そして「」が全角で、あとは全て半角です。 シングルクオーテーションのみ、変数への代入の関係でエスケープシーケンスで記述しています。

デフォルト処理

オプションは設定せず、デフォルトでの変換の場合です。

htmlentities
echo htmlentities($text);
// => &lt;あいう&amp;&quot;えおか&quot;&amp;'きくけ'&gt; 記号 &rArr;「&copy;」「&ne;」「&pound;」「&rarr;」「&hArr;」
htmlspecialchars
echo htmlspecialchars($text);
// => &lt;あいう&amp;&quot;えおか&quot;&amp;'きくけ'&gt; 記号 ⇒「c」「≠」「£」「→」「⇔」

htmlentities()の方はシングルクォーテーション以外は記号も含め根こそぎエンティティ変換されているのに対し、htmlspecialchars()の方は対象文字以外は変換されていないことが確認できます。

シングルクォーテーションも変換対象に含む

次は、第二引数を指定してシングルクォーテーションも変換対象に含みます。

htmlentities
echo htmlentities($text, ENT_QUOTES);
// => &lt;あいう&amp;&quot;えおか&quot;&amp;&#039;きくけ&#039;&gt; 記号 &rArr;「&copy;」「&ne;」「&pound;」「&rarr;」「&hArr;」
htmlspecialchars
echo htmlspecialchars($text, ENT_QUOTES);
// => &lt;あいう&amp;&quot;えおか&quot;&amp;&#039;きくけ&#039;&gt; 記号 ⇒「c」「≠」「£」「→」「⇔」

第二引数に「ENT_QUOTES」を指定する事で、両者ともシングルクォーテーションも変換された事が確認できます。

また、第二引数は複数指定する事も可能です。その場合は「|(パイプライン)」で区切ります。

htmlentities
echo htmlentities($text, ENT_QUOTES | ENT_HTML5);
// => &lt;あいう&amp;&quot;えおか&quot;&amp;&apos;きくけ&apos;&gt; 記号 &Implies;「&copy;」「&NotEqual;」「&pound;」「&srarr;」「&hArr;」
htmlspecialchars
echo htmlspecialchars($text, ENT_QUOTES | ENT_HTML5);
// => &lt;あいう&amp;&quot;えおか&quot;&amp;&apos;きくけ&apos;&gt; 記号 ⇒「c」「≠」「£」「→」「⇔」

エンティティ変換をデコードする

一度エンティティ変換を行ったものに対して、デコード(もとに戻す)事も出来ます。それぞれ、デコード用関数が用意されており、htmlentities()の場合はhtml_entity_decode()を、htmlspecialchars()の場合はhtmlspecialchars_decode()を用います。

htmlentities
$entity = htmlentities($text, ENT_QUOTES);
echo html_entity_decode($entity, ENT_QUOTES);
// => <あいう&"えおか"&'きくけ'> 記号 ⇒「c」「≠」「£」「→」「⇔」
htmlspecialchars
$entity = htmlspecialchars($text, ENT_QUOTES);
echo htmlspecialchars_decode($entity, ENT_QUOTES);
// => <あいう&"えおか"&'きくけ'> 記号 ⇒「c」「≠」「£」「→」「⇔」

デコードは両者ともエンティティ変換前の文字列に戻っている事が確認できます。ポイントは、デコードの際に、エンティティ変換を行った時と同じオプション(フラグ定数)を指定する事です。そうする事で、フラグ定数指示に則ってデコードが行われます。

get_html_translation_table()

おまけですが、デコード用関数を使わなくても手動で戻す事も可能です。

PHPにはget_html_translation_table()という関数があり、これを用いる事でhtmlspecialchars()やhtmlentities()で使用される変換テーブルを取得する事が出来るので、これを利用する事で手動でデコードが可能です。

htmlentities
// エンティティ変換
$entity = htmlentities($text, ENT_QUOTES);

// htmlentitiesの変換テーブルを取得する
$entity_table = get_html_translation_table(HTML_ENTITIES, ENT_QUOTES);

// KEY と VALUE を反転させる
$rev_entity_table = array_flip($entity_table);

// 文字列の置換を行う
echo strtr($entity, $rev_entity_table);
// => <あいう&"えおか"&'きくけ'> 記号 ⇒「c」「≠」「£」「→」「⇔」
htmlspecialchars
// エンティティ変換
$entity = htmlspecialchars($text, ENT_QUOTES);

// htmlentitiesの変換テーブルを取得する
$entity_table = get_html_translation_table(HTML_SPECIALCHARS, ENT_QUOTES);

// KEY と VALUE を反転させる
$rev_entity_table = array_flip($entity_table);

// 文字列の置換を行う
echo strtr($cng2, $rev_entity_table);
// => <あいう&"えおか"&'きくけ'> 記号 ⇒「c」「≠」「£」「→」「⇔」

get_html_translation_table関数の第一引数には変換テーブル指定の為の定数が渡されており、必要に応じてフラグ定数を第二引数に渡す事で、こちらの要求する変換テーブルセットを配列で取得する事が出来ます。htmlentitiesの変換テーブルは多いので割愛しますが、htmlspecialcharsの変換テーブルは、例えば以下のようになっています。

get_html_translation_table(HTML_SPECIALCHARS, ENT_QUOTES);
=> Array
(
["] => &quot;
[&] => &amp;
['] => &#039;
[<] => &lt;
[>] => &gt;
)

まとめ

昨今ではPHPフレームワークの進化でこれらの関数を直接的に使用する機会はかなり減りました。とはいえ、Laravelなどで使われているBladeテンプレートの{{}}記法やeヘルパーなどではhtmlspecialcharsやhtmlentitiesが使われており、レガシーながらも現在でも必要不可欠な関数である事には間違いありません。

両者の違いを理解できると、使いどころも迷わずにチョイスできるようになるので、覚えておくとどこかできっと役に立つはずです。