一身上の都合で文字エンコーディングと戦った時のメモ
PHPにおける文字列のエンコーディングはphp-mbstringモジュール
で提供されている。
mb_detect_encoding
はデフォルトではASCIIとUTF-8しかチェックしてくれない。
mb_detect_order
でチェックするエンコーディング形式を指定することができる。
だがしかし、対して検出精度はよくない。
不適切なエンコーディングで変換された場合、脆弱性になり得る。
テスト環境
- OS : CentOS7
- PHP : 7.0.11
エンコードテスト
UTF-8の文字列をmb_convert_encoding
で各文字エンコーディングで変換し、mb_detect_encoding
とmb_check_encoding
で検出させる。
$str = 'てすと';
$enc = [
'UTF-8',
'UTF-7',
'ASCII',
'EUC-JP',
'SJIS',
'eucJP-win',
'SJIS-win',
'JIS',
'ISO-2022-JP',
'Unicode',
];
mb_detect_order($enc);
foreach ($enc as $e) {
$encoded = mb_convert_encoding($str, $e, 'UTF-8');
var_dump(
$e,
$encoded,
mb_detect_encoding($encoded),
mb_check_encoding($encoded)
);
}
結果
エンコード | var_dump | mb_detect_encoding | mb_check_encoding |
---|---|---|---|
UTF-8 | てすと | UTF-8 | true |
UTF-7 | +MGYwWTBo- | UTF-8 | true |
ASCII | ??? | UTF-8 | true |
EUC-JP | "" | EUC-JP | true |
eucJP-win | "" | EUC-JP | true |
SJIS | "" | SJIS | true |
SJIS-win | "" | SJIS | true |
JIS | $B$F$9$H(B | UTF-8 | true |
ISO-2022-JP | $B$F$9$H(B | UTF-8 | true |
Unicode | 0f0Y0h | UTF-8 | true |
SJISとかは一部表示されていない(バイナリとして解釈されている?)けどエンコーディングは取得できていた。
mb_check_encoding
はすべての場合で検出できていた。
しかし適切に検出できているのか、とにかくtrueを返す残念な子なのか調べてみる。
エンコード検出テスト
$str = 'てすと';
$enc = [
'UTF-8',
'UTF-7',
'ASCII',
'EUC-JP',
'eucJP-win',
'SJIS',
'SJIS-win',
'JIS',
'ISO-2022-JP',
'Unicode',
];
mb_detect_order($enc);
foreach ($enc as $e) {
$s = mb_convert_encoding($str, $e, 'UTF-8');
$arr = [];
foreach ($enc as $e2) {
$arr[$e2] = mb_check_encoding($s, $e2);
}
var_dump($e, $arr);
}
結果
チェック\エンコ | UTF-8 | UTF-7 | ASCII | EUC-JP | eucJP-win | SJIS | SJIS-win | JIS | ISO-2022-JP | Unicode |
---|---|---|---|---|---|---|---|---|---|---|
UTF-8 | o | o | o | o | o | o | ||||
UTF-7 | o | o | o | |||||||
ASCII | o | o | o | o | o | |||||
EUC-JP | o | o | o | o | o | o | o | |||
eucJP-win | o | o | o | o | o | o | o | |||
SJIS | o | o | o | o | o | o | o | o | o | o |
SJIS-win | o | o | o | o | o | o | o | o | o | o |
JIS | o | o | o | o | o | |||||
ISO-2022-JP | o | o | o | o | o | |||||
Unicode | o | o | o | o | o | o | o | o |
o…trueが返ってきたところ
縦がチェックしたエンコード、横が検出対象のエンコード。
予想以上にアテにならないようです。