[PHP-dev 1491] Re: mbstring の文字列変換、文字エンコーディング検出の関連の問題について

Moriyoshi Koizumi mozo @ mozo.jp
2009年 8月 20日 (木) 02:11:39 JST


小泉です。

2009/8/20 komura <komura.db2r1e @ gmail.com>:

>> 1. mb_convert_encoding() で UTF-16(Little Endian) の文字列を変換すると結果が
>>   壊れる
>>
>>   UTF-16(Little Endian) で作成した文字列を変換すると、1文字目が壊れます。
>>   Shift_JIS や EUC-JP に変換した場合でも、1文字目が壊れます。
>>   変換元文字列が UTF-16(Big Endian) の場合は問題ありません。
>>
>> エンコーディング名 "UTF-16" は "UTF-16BE" や "UTF-16LE" と違い、BOM
>> によってエンディアンを判定します。手元で試したところ、BOM が \xff \xfe でも \xfe \xff
>> でも問題が発生することが確認できました。
>
> 以下のテストコードで、BOM 付きの Big Endian では、正しく変換されている
> ように見えましたので、問題ないと書いたのですが、私の勘違いでしょうか?

いえ、私の勘違いでした。余計なお手間をおかけしてすみません。

ところで、関連する別の問題を発見してしまいました。本来であれば U+FEFF は先頭にあるときのみ BOM
としての役割を果たすため、挙動としては明らかにバグなのですが、コード列の中のいずれの箇所でも U+FFFE が出現すると、U+FEFF
が出力された後、エンディアンが切り替わってしまうのです。

<?php
var_dump(bin2hex(mb_convert_encoding("\xfe\xff\xff\xfe\xfe\xff\x41\x00\x42\x00\x41\x00",
"UTF-16BE", "UTF-16")));
?>

パッチ適用後の出力結果:
string(20) "fefffeff004100420041"

ちなみにパッチ適用前は以下のようになっていました:
string(20) "fefffefffefffefffeff"


>> > 4. mb_check_encoding() で UTF-16(Little Endian) を判定すると、必ず false を
>> >   返す
>>
>> これは先にも書きましたが、BOM を見てエンディアンを判定することによるものなので問題はないように思えます。
>
> すみません。これは、少し複雑な問題です。
> 実際には、1. の Patch を適用しても、以下の結果になります。
(snip)
> このため、mb_check_encoding() では、UTF-16(BOM 付き Little Endian)の
> 文字列は、false になります。この問題を修正するには、UTF-16 -> UTF-16
> の変換で、エンディアンを保持する必要があります。

すみません、言葉足らずで、斜め読みでよく問題を理解していないのではないかと疑われても仕方ないのですが、
これについては、仕様、という認識です。

# いろいろな意見があるかと思いますが、個人的には、mb_check_encoding() 自体の有用性を疑っています。

なお、ICU への移行は決まったわけではないので、保守は続けていきます。


PHP-dev メーリングリストの案内