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

有没有办法让 json_encode() 为包含无效(非 UTF-8)字符的字符串返回 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 字符串对此没有帮助。

最佳答案

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

这种奇怪而不幸的行为与此错误有关 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 silently discards characters that are illegal in the target charset.

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

编辑
在 php 7.2+ 中,json_encode 似乎有一些新标志: JSON_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

https://stackoverflow.com/questions/4663743/

相关文章:

python - 如何在 Django REST 框架中返回自定义 JSON

json - 雅虎财经全币种报价 API 文档

python - 使用 Scrapy 抓取 JSON 响应

json - 在 Play Framework JsObject 中解析 Json 数组

java - 将 InputStream 转换为 JSONObject

python - 如何在保留矩阵维度的同时序列化 numpy 数组?

java - 非空属性引用 transient 值 - transient 实例必须在当前操作之前保

python - 在 View 中强制应用程序/json MIME 类型(Flask)

c# - JavaScriptSerializer 可以排除具有空值/默认值的属性吗?

json - JSONObject 的 Jackson 2 等价物是什么?