使用 ICU 的 PHP 的intl包装器中当前可用的功能,您将如何检查字符串编码的有效性?(例如检查有效的 UTF-8)
我知道它可以用 mbstring、iconv() 和 PCRE 来完成,但我对这个问题特别感兴趣。
自 PHP 5.5 起可以使用 UConverter。手册不存在。有关 API,请参阅https://wiki.php.net/rfc/uconverter。
function replace_invalid_byte_sequence($str)
{
return UConverter::transcode($str, 'UTF-8', 'UTF-8');
}
function replace_invalid_byte_sequence2($str)
{
return (new UConverter('UTF-8', 'UTF-8'))->convert($str);
}
function utf8_check_encoding($str)
{
return $str === UConverter::transcode($str, 'UTF-8', 'UTF-8');
}
function utf8_check_encoding2($str)
{
return $str === (new UConverter('UTF-8', 'UTF-8'))->convert($str);
}
// Table 3-8. Use of U+FFFD in UTF-8 Conversion
// http://www.unicode.org/versions/Unicode6.1.0/ch03.pdf)
$str = "\x61"."\xF1\x80\x80"."\xE1\x80"."\xC2"."\x62"."\x80"."\x63"
."\x80"."\xBF"."\x64";
$expected = 'a���b�c��d';
var_dump([
$expected === replace_invalid_byte_sequence($str),
$expected === replace_invalid_byte_sequence2($str)
],[
false === utf8_check_encoding($str),
false === utf8_check_encoding2($str)
]);
我做了一些挖掘,发现了ICU unorm2_normalize() 文档。它的 pErrorCode out 参数很有趣。标准 ICU 错误代码从utypes.h的第 620 行开始。所以我尝试了这个测试脚本:
$s = 'tête-à-tête';
echo "normalizer_normalize(\$s) >> "
. var_export(normalizer_normalize($s), 1) . "\n";
$s = "\xFF" . $s;
echo "normalizer_normalize(\$s) >> "
. var_export($r=normalizer_normalize($s), 1) . "\n";
if ($r===false)
echo "normalizer_normalize() error: "
. intl_get_error_message() . "\n";
// which outputs:
normalizer_normalize($s) >> 'tête-à-tête'
normalizer_normalize($s) >> false
normalizer_normalize() error: Error converting input string to UTF-16: U_INVALID_CHAR_FOUND
所以我想基于此的测试并寻找以下三个错误代码将是错误 UTF-8 编码的一个很好的指示:
U_INVALID_CHAR_FOUND 字符转换:不可映射的输入序列。U_TRUNCATED_CHAR_FOUND 字符转换:输入序列不完整。U_ILLEGAL_CHAR_FOUND 字符转换:非法输入序列/输入单元组合。
或者当我感到懒惰时,我可以使用
normalizer_normalize($s)===false
顺便说一句:我对 ICU API 规范的这一行感到困惑:
pErrorCode 标准 ICU 错误代码。它的输入值必须通过 U_SUCCESS () 测试,否则函数立即返回。检查输出上的 U_FAILURE () 或与函数链接一起使用。(有关详细信息,请参阅用户指南。)
“函数立即返回”短语鼓励我重新执行测试,但“函数”是指 unorm2_normalize() 还是 U_SUCCESS()?有任何想法吗?