如何防止json_encode()丢弃带有无效字符的字符串

Pek*_*ica 35 php json utf-8

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

在复杂的系统中调试可能会很麻烦.实际看到无效字符会更合适,或者至少省略它.就目前而言,json_encode()将默默地删除整个字符串.

示例(以UTF-8格式):

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

print_r(json_encode($string));
Run Code Online (Sandbox Code Playgroud)

结果是

[null,"Washington","Nairobi"]
Run Code Online (Sandbox Code Playgroud)

期望的结果:

["D?sseldorf","Washington","Nairobi"]
Run Code Online (Sandbox Code Playgroud)

注意:我打算在json_encode()中使断字符串工作.我正在寻找方法,以便更容易诊断编码错误.一个null字符串是不是该有所帮助.

goa*_*oat 42

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

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

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
Run Code Online (Sandbox Code Playgroud)

这个奇怪和不幸的行为与这个错误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);
Run Code Online (Sandbox Code Playgroud)

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

手册说

//IGNORE 默默地丢弃目标字符集中非法的字符.

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


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


mou*_*ubi 6

$s = iconv('UTF-8', 'UTF-8//IGNORE', $s);
Run Code Online (Sandbox Code Playgroud)

这解决了这个问题.我不确定为什么来自php的人没有通过修复让生活变得更轻松json_encode().

无论如何使用上面的内容允许json_encode()创建对象,即使数据包含特殊字符(例如瑞典字母).

然后,您可以使用该结果在JavaScript中,而不需要对数据进行解码回原来的编码(有escape(),unescape(),encodeURIComponent(),decodeURIComponent());

我在php(smarty)中使用它是这样的:

$template = iconv('UTF-8', 'UTF-8//IGNORE', $screen->fetch("my_template.tpl"));
Run Code Online (Sandbox Code Playgroud)

然后我将结果发送到javascript,并innerHTML在我的文档中发送准备好的模板(html peace).

简单地说上面的行应该以json_encode()某种方式实现,以便允许它使用任何编码.


Dan*_*ack 5

此函数将从字符串中删除所有无效的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);
}
Run Code Online (Sandbox Code Playgroud)

我将Excel文档转换为json后使用它,因为Excel文档不保证是UTF8.

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