LoginSignup
23
17

More than 5 years have passed since last update.

PHPの文字エンコーディング検出はアテにならない

Posted at

一身上の都合で文字エンコーディングと戦った時のメモ

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_encodingmb_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が返ってきたところ
縦がチェックしたエンコード、横が検出対象のエンコード。
予想以上にアテにならないようです。

23
17
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
23
17