如何在PHP中检测格式错误的UTF-8字符串?


How can I detect a malformed UTF-8 string in PHP?

iconv函数有时会给我一个错误:

Notice:
iconv() [function.iconv]:
Detected an incomplete multibyte character in input string in [...]

是否有一种方法可以检测在将数据发送到inconv()之前UTF-8字符串中是否存在非法字符?

首先,注意不可能检测文本是否属于特定的不希望的编码。您只能检查字符串在给定的编码中是否有效。

您可以使用自PHP 4.3.5以来preg_match [PHP Manual]中提供的UTF-8有效性检查。如果给定无效字符串,它将返回0(不含任何附加信息):

$isUTF8 = preg_match('//u', $string);

另一种可能是mb_check_encoding [PHP Manual]:

$validUTF8 = mb_check_encoding($string, 'UTF-8');
另一个可以使用的函数是mb_detect_encoding [PHP Manual]:
$validUTF8 = ! (false === mb_detect_encoding($string, 'UTF-8', true));

strict参数设置为true是很重要的。

另外,iconv [PHP Manual]允许您动态更改/删除无效序列。(但是,如果iconv遇到这样的序列,它会生成一个通知;)

echo 'TRANSLIT : ', iconv("UTF-8", "ISO-8859-1//TRANSLIT", $string), PHP_EOL;
echo 'IGNORE   : ', iconv("UTF-8", "ISO-8859-1//IGNORE", $string), PHP_EOL;

您可以使用@检查返回字符串的长度:

strlen($string) === strlen(@iconv('UTF-8', 'UTF-8//IGNORE', $string));

查看iconv手册页上的示例

使用json_encode,试试json_last_error

<?php
// An invalid UTF8 sequence
$text = "'xB1'x31";
$json  = json_encode($text);
$error = json_last_error();
var_dump($json, $error === JSON_ERROR_UTF8);
5.3.3

输出(例如PHP版本——5.3.13 5.3.15——5.3.29 5.4.0 - 5.4.45)

string(4) "null"
bool(true)

您可以尝试使用mb_detect_encoding来检测您是否有不同的字符集(而不是UTF-8),然后mb_convert_encoding在需要时转换为UTF-8。更有可能的是,人们给你的是不同字符集的有效内容,而不是无效的UTF-8。

对于哪些字符在UTF-8中无效的规范是非常清楚的。在尝试解析它之前,您可能希望去掉这些内容。它们不应该在那里,所以如果你能在生成XML之前就避免它,那就更好了。

参考:

http://www.w3.org/TR/xml/数据集

这不是一个完整的列表。许多解析器也不允许一些低编号的控制字符,但我现在找不到一个全面的列表。

但是,iconv可能有内置的支持:

http://www.zeitoun.net/articles/clear-invalid-utf8/start

在iconv()前加一个@来抑制NOTICE,在源编码id的UTF-8后加一个//IGNORE来忽略无效字符:

@iconv('UTF-8//IGNORE', $destinationEncoding, $yourString);