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 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 http://php.net/manual/en/function.iconv.php
手册说
//IGNORE
默默地丢弃目标中非法的字符
字符集。
因此,通过首先删除有问题的字符,理论上 json_encode() 不应该得到任何会阻塞并失败的内容。我还没有验证 iconv 的输出//IGNORE
flag 与有效 utf8 字符是什么的 json_encodes 概念完全兼容,因此买家要小心......因为可能存在仍然失败的边缘情况。呃,我讨厌字符集问题。
Edit
在 php 7.2+ 中,似乎有一些新标志json_encode
:
JSON_INVALID_UTF8_IGNORE
and JSON_INVALID_UTF8_SUBSTITUTE
目前还没有太多文档,但就目前而言,此测试应该可以帮助您了解预期的行为:https://github.com/php/php-src/blob/master/ext/json/tests/json_encode_invalid_utf8.phpt https://github.com/php/php-src/blob/master/ext/json/tests/json_encode_invalid_utf8.phpt
而且,在 php 7.3+ 中,有一个新标志JSON_THROW_ON_ERROR
. See http://php.net/manual/en/class.jsonexception.php http://php.net/manual/en/class.jsonexception.php