mb_detect_encoding() は文字コード判定として使用できるか(その1)
最近、mb_detect_encoding() について調べていたので、そのメモです。mb_detect_encoding() は文字コード検出を行う関数です(mb_detect_encoding() - PHP マニュアル)。
結論としては、以下の問題があるため、mb_detect_encoding() を文字コード判定には向いていないように思います。
UTF-16, UTF-32, UCS2, UCS4 の場合、 エンコーディング検出は常に失敗します。
http://php.net/mb_detect_order
これらの問題をもう少し改善できるように、PHP 5.2.9 に対する Patch を作ってみました(上記の1.と 2-1)。
- mb_detect_encoding() の第3引数に TRUE を渡すと文字コード判定をもう少し厳格にする Patch です。
diff -ru php-5.2.9.orig/ext/mbstring/libmbfl/mbfl/mbfilter.c php-5.2.9/ext/mbstring/libmbfl/mbfl/mbfilter.c --- php-5.2.9.orig/ext/mbstring/libmbfl/mbfl/mbfilter.c 2009-02-15 16:11:23.000000000 +0900 +++ php-5.2.9/ext/mbstring/libmbfl/mbfl/mbfilter.c 2009-06-14 17:03:10.601591122 +0900 @@ -622,7 +622,7 @@ if (!encoding) { for (i = 0; i < num; i++) { filter = &flist[i]; - if (!filter->flag) { + if (!filter->flag && (!strict || !filter->status)) { encoding = filter->encoding; break; }
- UTF-8 の判定で不正だと思われる文字列(\xc0\x00, \xd0\x00, ..., \xfd\x00)を通さないようにする Patch です。
diff -ru php-5.2.9.orig/ext/mbstring/libmbfl/filters/mbfilter_utf8.c php-5.2.9/ext/mbstring/libmbfl/filters/mbfilter_utf8.c --- php-5.2.9.orig/ext/mbstring/libmbfl/filters/mbfilter_utf8.c 2009-02-25 00:09:42.000000000 +0900 +++ php-5.2.9/ext/mbstring/libmbfl/filters/mbfilter_utf8.c 2009-06-14 20:24:31.088574372 +0900 @@ -215,7 +215,7 @@ if (c < 0x80) { if (c < 0) { filter->flag = 1; /* bad */ - } else if (c != 0 && filter->status) { + } else if (filter->status) { filter->flag = 1; /* bad */ } filter->status = 0;
PHP 5.2.9 に上記の Patch を適用すると、mb_detect_encoding() は以下のような正規表現とほぼ同じになります(ISO-2022-JP と ISO-2022-JP-MS は怪しいですが)。
ASCII | \A[\x00\x09\x0a\x0d\x20-\x7f]*\z |
---|---|
SJIS | \A([\x00-\x7f]|[\xa1-\xdf]|[\x81-\x9f\xe0-\xef][\x40-\x7e\x80-\xfc])*\z |
SJIS-win | \A([\x00-\x7f]|[\xa1-\xdf]|[\x81-\x9f\xe0-\xfc][\x40-\x7e\x80-\xfc])*\z |
EUC-JP | \A([\x00-\x7f]|[\xa1-\xfe][\xa1-\xfe]|\x8e[\xa1-\xdf]|\x8f[\xa1-\xfe][\xa1-\xfe])*\z |
eucJP-win | \A([\x00-\x7f]|[\xa1-\xfe][\xa1-\xfe]|\x8e[\xa1-\xdf]|\x8f[\xa1-\xfe][\xa1-\xfe])*\z |
CP51932 | \A([\x00-\x7f]|[\xa1-\xfe][\xa1-\xfe]|\x8e[\xa1-\xdf])*\z |
ISO-2022-JP | \A([\x00-\x1a\x1c-\x7f]|\x1b\x24[\x40\x42](?:[\x21-\x7e][\x21-\x7e])+|\x1b\x24\x28[\x40\x42\x44](?:[\x21-\x7e][\x21-\x7e])+|\x1b\x28\x42)*\z |
ISO-2022-JP-MS | \A([\x00-\x1a\x1c-\x7f]|\x1b\x24[\x40\x42](?:[\x21-\x7e][\x21-\x7e])+|\x1b\x24\x28[\x40\x42\x44](?:[\x21-\x7e][\x21-\x7e])+|\x1b\x28\x42|\x1b\x28\x4a[\x00-\x1a\x1c-\x7f]+|\x1b\x28\x49[\x00-\x1a\x1c-\x7f]+\x1b\x28\x42)*\z |
UTF-8 | \A([\x00-\x7f]|[\xc0-\xdf][\x80-\xbf]|[\xe0-\xef][\x80-\xbf]{2}|[\xf0-\xf7][\x80-\xbf]{3}|[\xf8-\xfb][\x80-\xbf]{4}|[\xfc-\xfd][\x80-\xbf]{5})*\z |
UTF-16 | 判定不可(常に FALSE) |
UTF-16BE | 判定不可(常に FALSE) |
UTF-16LE | 判定不可(常に FALSE) |
以下は続きです。