如何防止 json_encode() 丢弃包含无效字符的字符串

新手上路,请多包涵

对于包含无效(非 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 字符串对此没有帮助。

原文由 Pekka 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 487
2 个回答

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

这里有一些代码可以证明这一点:

 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

这种奇怪和不幸的行为与这个 bug 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() 不应该得到任何它会阻塞和失败的东西。我还没有验证带有 //IGNORE 标志的 iconv 的输出是否与 json_encodes 的有效 utf8 字符的概念完全兼容,所以买家要小心……因为可能存在它仍然失败的边缘情况。呃,我讨厌字符集问题。

编辑

在 php 7.2+ 中,似乎有一些新标志 json_encodeJSON_INVALID_UTF8_IGNOREJSON_INVALID_UTF8_SUBSTITUTE

目前还没有太多文档,但就目前而言,此测试应该可以帮助您了解预期的行为: https ://github.com/php/php-src/blob/master/ext/json/tests/json_encode_invalid_utf8.phpt

而且,在 php 7.3+ 中有新标志 JSON_THROW_ON_ERROR 。请参阅 http://php.net/manual/en/class.jsonexception.php

原文由 goat 发布,翻译遵循 CC BY-SA 4.0 许可协议

此函数将从字符串中删除所有无效的 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 替换无效字符,U+FFFD 是 unicode 替换字符,方法是转动上面的正则表达式,但这并不能提供比仅删除无效字符更好的用户体验。

原文由 Danack 发布,翻译遵循 CC BY-SA 3.0 许可协议

推荐问题
logo
Stack Overflow 翻译
子站问答
访问
宣传栏