🦔
【PHP】往復変換の安全性が保証されていないレガシーエンコーディングの文字を調べる
レガシーエンコーディングの文字のなかには Unicode との往復変換(ラウンドトリップ)で別の文字に変わってしまうものがあります。
例として NEC、IBM の機種依存文字を挙げます。ほとんど等しいをあらわす近似記号(≒、U+2252)は Shift_JIS では2つ定義されます(0x81E0
、0x8790
)。往復変換すると 0x8790
は ox81E0
に置き換わっています。
var_dump(
"\x81\xE0" === roundtrip("\x87\x90", 'cp932')
);
function roundtrip($char, $enc) {
return mb_convert_encoding(mb_convert_encoding($char, 'utf-8', $enc), $enc, 'utf-8');
}
往復変換で置き換わってしまう文字をすべて調べてみます。
count_unsafe_chars('cp932');
function roundtrip($char, $enc) {
return mb_convert_encoding(mb_convert_encoding($char, 'utf-8', $enc), $enc, 'utf-8');
}
function tohexupper($char) {
return strtoupper(bin2hex($char));
}
function count_unsafe_chars($enc) {
$count = 0;
for ($cp = 0x1000; $cp < 0x10000; ++$cp) {
$c = chr($cp >> 8).chr($cp & 0xff);
if (!mb_check_encoding($c, $enc)) {
continue;
}
$ret = roundtrip($c, $enc);
if ($c !== $ret) {
echo '[', tohexupper($c), ' ', tohexupper($ret), ']';
++$count;
}
}
echo PHP_EOL, PHP_EOL;
echo $enc, PHP_EOL;
echo 'count:', $count, PHP_EOL;
}
実行すると398文字が変換されたことがわかります。
Discussion