UTF-16(BOM 付き Little Endian) を mb_convert_encoding() で変換すると文字列が壊れる

前の項目からの続きです。
基本的に、PHP 5.2 1 以降(正確には 5.2.8 以降)では、mb_check_encoding() が false を返す場合、以下も false を返します。

<?php
// テスト(UTF-16: BOM 付き Little Endian の文字列)
$str = "\xFF\xFE\xC6\x30\xB9\x30\xC8\x30";
var_dump( $str === mb_convert_encoding( $str, "UTF-16", "UTF-16" ) );
bool(false)

これは、上記の mb_convert_encoding() で文字列が変化していることになります。実際のバイト列と、UTF-8 変換後の文字列を表示させると以下のようになります。

<?php
// テスト(UTF-16: BOM 付き Little Endian の文字列)
$str = "\xFF\xFE\xC6\x30\xB9\x30\xC8\x30";
var_dump( bin2hex( mb_convert_encoding( $str, "UTF-16", "UTF-16" ) ) );
var_dump( mb_convert_encoding( $str, "UTF-8", "UTF-16" ) );
string(16) "feffffc630b930c8"
string(12) "・スト"

UTF-16 から UTF-16 への変換では文字列が BOM とバイト列の並びを見ると Big Endian に変換されてしまっています。UTF-16(Big Endian)に変換するなら、"feff30c630b930c8" となるはずですが、一文字目の上位バイトが ff になっています。
このため、先頭の1文字が壊れてしまいます。SJISEUC-JP などへの変換でも同様に一文字目が壊れます。

Windows のメモ帳などで Unicode としてテキストを保存すると UTF-16(BOM 付き Little Endian)になります。このため、そのようなファイルの文字コードを変換する際には注意が必要です。

それ以外にあまり PHPUTF-16 の文字列を扱う状況は思い浮びませんので、それほど影響は大きくないと思います。