一身上の都合で文字エンコーディングと戦った時のメモ
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が返ってきたところ
縦がチェックしたエンコード、横が検出対象のエンコード。
予想以上にアテにならないようです。