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

问题描述 投票:0回答:5

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

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

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

php encoding utf-8 iconv
5个回答
77
投票

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

自 PHP 4.3.5 起,您可以使用

preg_match
[PHP 手册] 中提供的 UTF-8 有效性检查。如果给出无效字符串,它将返回 empty1(没有附加信息²):

$validUTF8 = (bool) preg_match('//u', $string);

另一种可能性是

mb_check_encoding
[PHP手册]:

$validUTF8 = mb_check_encoding($string, 'UTF-8');

您可以使用的另一个函数是

mb_detect_encoding
[PHP 手册]:

$validUTF8 = ! (false === mb_detect_encoding($string, 'UTF-8', true));

strict
参数设置为
true
非常重要。

此外,

iconv
[PHP 手册] 允许您动态更改/删除无效序列。 (但是,如果
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
手册页上的示例。


备注:

¹ preg_match() 返回值:

  • 0
    直到5.3.3(含)
  • false
    自5.3.4起。

(4.3.5 之前/直到 4.3.4:

//u
测试没有用,因为它在主题字符串
1
上返回
"\x80"
,这不是 UTF-8 中的完整二进制序列,最多只是一个连续字节)

² 没有附加信息:

原始

0
返回值本身不包含任何附加信息,preg_match() 也不产生诊断消息。

正如之前在评论中概述的那样,可以获得更多信息,特别是在匹配错误(不匹配)的情况下会出现 PREG_*_ERROR。

这是通过调用 preg_last_error()PHP >= 5.2 after preg_match() 并针对 PREG_BAD_UTF8_ERROR 测试返回整数值来识别主题字符串不是 UTF-8 来实现的。

对于诊断消息,请使用 preg_last_error_msg()PHP >= 8,它返回字符串“格式错误的 UTF-8 字符,可能编码错误”(不带引号),因为最后一个错误是 PREG_BAD_UTF8_ERROR。


1
投票

对于使用 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);

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

string(4) "null"
bool(true)

0
投票

您可以尝试使用

mb_detect_encoding
来检测是否有不同的字符集(与 UTF-8 不同),然后根据需要使用
mb_convert_encoding
转换为 UTF-8。 人们更有可能为您提供不同字符集的有效内容,而不是为您提供无效的 UTF-8。


-1
投票

UTF-8 中哪些字符无效的规范非常清楚。您可能想在尝试解析它之前将其删除。它们不应该在那里,所以如果您可以在生成 XML 之前避免它,那就更好了。

请参阅此处以获取参考:

http://www.w3.org/TR/xml/#charsets

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

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

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


-1
投票

在 iconv() 前面放置一个

@
以抑制 NOTICE,并在源编码 id 中的 UTF-8 后面放置一个 //IGNORE 以忽略无效字符:

@iconv('UTF-8//IGNORE', $destinationEncoding, $yourString);
© www.soinside.com 2019 - 2024. All rights reserved.