🦝

【php】HTML-ENTITIESの文字化けが気になる

2024/11/21に公開

【旧】mb_encode_numericentity

今までmb_convert_encodingを使っていたんだけど、ソースコードの文字が記号になってしまうのが少し気になっていた。

$dom = new DOMDocument('1.0','UTF-8');
$dom->loadHTML(mb_convert_encoding($content, 'HTML-ENTITIES', 'UTF-8'));

どうやらHTML-ENTITIESに変換してしまうと文字列は数値文字参照(エンティティ化)されてしまうらしい。

【新】mb_encode_numericentity

ブラウザでの表示上は普通だけど気になる……ので、別の関数を使ってみた。

 $dom = new DOMDocument('1.0','UTF-8');
 $dom->loadHTML(mb_encode_numericentity($content,[0x80, 0x10ffff, 0, 0x1fffff]));

https://www.php.net/manual/ja/function.mb-encode-numericentity.php
第一引数には変換する文字列、第二引数には変換するコード領域が入る。
正直よくわからないのでこの記事からコピペしてきた。
https://qiita.com/takaram/items/79bf513694025f737d07

コード領域の解読

コピペエンジニアの称号は不名誉であり、正しく設定できているか不安もあったから調べてみた。

変換マップの構造

Copilotによると、第二引数の変換マップの構造は以下のとおり。

  • 範囲の開始(コードポイント):
    変換対象となる文字コードの開始値です。この値は16進数で指定されます。
  • 範囲の終了(コードポイント):
    変換対象となる文字コードの終了値です。この値も16進数で指定されます。
  • 基数オフセット:
    数値エンティティを生成する際の基数オフセットです。この値は変換時に使用する追加の基数を指定します。例えば、オフセットが0の場合、単純にそのままの数値エンティティが生成されます。
  • エンコード方式:
    数値エンティティのエンコード方法に関する追加情報を指定します。通常はそのままの形式を保持するため、0x1fffffが使用されますが、必要に応じて変更することができます。

というわけで、それぞれの数値の根拠を探しに行く。

範囲の開始(0x80)

0x80は10進数で128に相当する。
(0xは16進数であることを表し、8016*8+16*0で128)
0~127に該当する文字は互換性があり、エンコード無しでも問題なく表示できる……らしい。
この部分はASCIIコード(7bit)に該当していて、アルファベット・数字・記号が表現されている。
https://e-words.jp/w/ASCII.html
これってキーボードの割り当てにも使用されてるのかな。

範囲の終了(0x10ffff)

0x10ffffはUnicodeのコードポイントの最大値で、文字はここまでということになっている。
https://zenn.dev/kumamoto/scraps/39de5184a96f48

基数オフセット(0)

文字通りオフセットなので、0以外だと対応文字がズレていくんじゃないかな。

エンコード方式(0x1fffff)

Unicodeは21ビットまで表現できることになっていて、エンコード方式に0x1fffffを設定すると概ねすべての文字を解釈できることになる……らしい(?)。
0xは16進数を表し、1fffff1 1111 1111 1111 1111 1111となり21ビットを表す)
https://sites.google.com/view/kilin/lecture/UTF-8table


調べた感じコード領域の設定はこれで問題なさそうだけど、文字コードって難しいね。

Discussion