mb_convert_encoding()
の第2引数にHTML-ENTITIES
を指定すると、文字列中の漢字やひらがななどをHTMLの文字実体参照・文字数値参照(
,€
みたいなやつ)に変換してくれます。
「漢字やひらがななど」とあえてふわっと書きましたが、正確にはASCII (0x00-0x7F) の範囲外の文字が変換対象のようです(このあたりドキュメントが見つからなかったのでおそらくですが)。
逆に、第3引数にHTML-ENTITIES
を指定すれば、文字実体参照などをデコードできます。
<?php
$string = 'あいうえお';
$encoded = mb_convert_encoding($string, 'HTML-ENTITIES', 'UTF-8');
echo $encoded; // あいうえお
$decoded = mb_convert_encoding($encoded, 'UTF-8', 'HTML-ENTITIES');
echo $decoded; // あいうえお
上記のように、一度変換したあと逆向きに変換すれば元の文字列に戻せる……と思ってしまいそうですが、実はそうとは限りません。
先述したようにmb_convert_encoding($string, 'HTML-ENTITIES', 'UTF-8')
で変換されるのはASCII範囲外の文字のため、ASCIIの文字は変換されません。つまり、<
のような文字列をUTF-8→HTML-ENTITIES→UTF-8と変換すると、2回目のみ変換されて<
になってしまいます。
<?php
$string = '<div>あいう</div>';
$encoded = mb_convert_encoding($string, 'HTML-ENTITIES', 'UTF-8');
echo $encoded; // <div>あいう</div>
$decoded = mb_convert_encoding($encoded, 'UTF-8', 'HTML-ENTITIES');
echo $decoded; // <div>あいう</div>
対策
これを防ぐためには、&
を&
に変換すればいいはずです。変換のタイミングはmb_convert_encoding()
よりも前です。
<?php
$string = '<div>あいう</div>';
$encoded = str_replace('&', '&', $string);
$encoded = mb_convert_encoding($encoded, 'HTML-ENTITIES', 'UTF-8');
echo $encoded; // &lt;div&gt;あいう&lt;/div&gt;
$decoded = mb_convert_encoding($encoded, 'UTF-8', 'HTML-ENTITIES');
echo $decoded; // <div>あいう</div>
var_dump($string === $decoded); // bool(true)