如何防止json_encode() 删除包含无效字符的字符串

2022-08-30 11:20:44

有没有办法防止返回包含无效(非 UTF-8)字符的字符串?json_encode()null

在复杂的系统中进行调试可能是一件痛苦的事情。实际看到无效字符或至少省略它更合适。就目前而言,将静静地放下整根弦。json_encode()

示例(在 UTF-8 中):

$string = 
  array(utf8_decode("Düsseldorf"), // Deliberately produce broken string
        "Washington",
        "Nairobi"); 

print_r(json_encode($string));

结果在

[null,"Washington","Nairobi"]

期望结果:

["D�sseldorf","Washington","Nairobi"]

注意:我不想让破碎的字符串在json_encode()中工作。我正在寻找更容易诊断编码错误的方法。字符串对此没有帮助。null


答案 1

php确实会尝试喷出错误,但前提是您关闭display_errors。这很奇怪,因为该设置仅用于控制是否将错误打印到标准输出,而不是控制是否触发错误。我想强调的是,当你打开时,即使你可能会看到各种其他的php错误,php不仅会隐藏这个错误,它甚至不会触发它。这意味着它不会显示在任何错误日志中,也不会调用任何自定义error_handlers。错误永远不会发生。display_errorsdisplay_errors

下面是一些演示这一点的代码:

error_reporting(-1);//report all errors
$invalid_utf8_char = chr(193);

ini_set('display_errors', 1);//display errors to standard output
var_dump(json_encode($invalid_utf8_char));
var_dump(error_get_last());//nothing

ini_set('display_errors', 0);//do not display errors to standard output
var_dump(json_encode($invalid_utf8_char));
var_dump(error_get_last());// json_encode(): Invalid UTF-8 sequence in argument

这种奇怪而不幸的行为与这个错误 https://bugs.php.net/bug.php?id=47494 和其他一些错误有关,并且看起来永远不会被修复。

解决方法:

在将字符串传递给json_encode之前对其进行清洁可能是一个可行的解决方案。

$stripped_of_invalid_utf8_chars_string = iconv('UTF-8', 'UTF-8//IGNORE', $orig_string);
if ($stripped_of_invalid_utf8_chars_string !== $orig_string) {
    // one or more chars were invalid, and so they were stripped out.
    // if you need to know where in the string the first stripped character was, 
    // then see http://stackoverflow.com/questions/7475437/find-first-character-that-is-different-between-two-strings
}
$json = json_encode($stripped_of_invalid_utf8_chars_string);

http://php.net/manual/en/function.iconv.php

手册说

//IGNORE以静默方式丢弃目标字符集中的非法字符。

因此,通过首先删除有问题的字符,理论上json_encode()不应该得到任何东西,它会窒息并失败。我还没有验证带有标志的iconv的输出是否与有效utf8字符的概念完全兼容json_encodes,所以买家要小心......因为可能存在仍然失败的边缘情况。呃,我讨厌字符集问题。//IGNORE

在 php 7.2+ 中编辑
,似乎有一些新的标志:并且
还没有太多的文档,但现在,这个测试应该可以帮助您了解预期的行为:https://github.com/php/php-src/blob/master/ext/json/tests/json_encode_invalid_utf8.phptjson_encodeJSON_INVALID_UTF8_IGNOREJSON_INVALID_UTF8_SUBSTITUTE

而且,在 php 7.3+ 中,有一个新的标志 。查看 http://php.net/manual/en/class.jsonexception.phpJSON_THROW_ON_ERROR


答案 2

此函数将从字符串中删除所有无效的 UTF8 字符:

function removeInvalidChars( $text) {
    $regex = '/( [\x00-\x7F] | [\xC0-\xDF][\x80-\xBF] | [\xE0-\xEF][\x80-\xBF]{2} | [\xF0-\xF7][\x80-\xBF]{3} ) | ./x';
    return preg_replace($regex, '$1', $text);
}

我在将Excel文档转换为json后使用它,因为Excel文档不能保证采用UTF8。

我不认为有一种特别明智的方法可以将无效字符转换为可见但有效的字符。您可以通过转动上面的正则表达式来将无效字符替换为U + FFFD,这是Unicode替换字符,但这实际上并不能提供比删除无效字符更好的用户体验。


推荐