关于json:如何解决php json_decode中的JSON_ERROR_UTF8错误?

How to solve JSON_ERROR_UTF8 error in php json_decode?

我正在尝试此代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
$json = file_get_contents("http://www.google.com/alerts/preview?q=test&t=7&f=1&l=0&e");
print_r(json_decode(utf8_encode($json), true));

        //////////////

// Define the errors.
$constants = get_defined_constants(true);
$json_errors = array();
foreach ($constants["json"] as $name => $value) {
    if (!strncmp($name,"JSON_ERROR_", 11)) {
        $json_errors[$value] = $name;
    }
}

// Show the errors for different depths.
foreach (range(4, 3, -1) as $depth) {
    var_dump(json_decode($json, true, $depth));
    echo 'Last error: ', $json_errors[json_last_error()], PHP_EOL, PHP_EOL;
}

我尝试了很多函数,html_entities_decode,utf8_encode和解码,解码十六进制代码,但是我总是收到错误" JSON_ERROR_UTF8"。

我该如何解决?


有一个很好的功能可以清理阵列。

我建议您使用像这样的json_encode包装器:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
function safe_json_encode($value, $options = 0, $depth = 512, $utfErrorFlag = false) {
    $encoded = json_encode($value, $options, $depth);
    switch (json_last_error()) {
        case JSON_ERROR_NONE:
            return $encoded;
        case JSON_ERROR_DEPTH:
            return 'Maximum stack depth exceeded'; // or trigger_error() or throw new Exception()
        case JSON_ERROR_STATE_MISMATCH:
            return 'Underflow or the modes mismatch'; // or trigger_error() or throw new Exception()
        case JSON_ERROR_CTRL_CHAR:
            return 'Unexpected control character found';
        case JSON_ERROR_SYNTAX:
            return 'Syntax error, malformed JSON'; // or trigger_error() or throw new Exception()
        case JSON_ERROR_UTF8:
            $clean = utf8ize($value);
            if ($utfErrorFlag) {
                return 'UTF8 encoding error'; // or trigger_error() or throw new Exception()
            }
            return safe_json_encode($clean, $options, $depth, true);
        default:
            return 'Unknown error'; // or trigger_error() or throw new Exception()

    }
}

function utf8ize($mixed) {
    if (is_array($mixed)) {
        foreach ($mixed as $key => $value) {
            $mixed[$key] = utf8ize($value);
        }
    } else if (is_string ($mixed)) {
        return utf8_encode($mixed);
    }
    return $mixed;
}

在我的应用程序中,utf8_encode()比iconv()更好地工作


您需要简单的代码行:

1
2
$input = iconv('UTF-8', 'UTF-8//IGNORE', utf8_encode($input));
$json = json_decode($input);

信用:Sang Le,我的团队成员给了我这段代码。是的


除非您可以确保输入有效,否则iconv函数几乎一文不值。请改用mb_convert_encoding。

1
mb_convert_encoding($value,"UTF-8","auto");

您可以获得比" auto"更明确的信息,甚至可以指定期望输入编码的逗号分隔列表。

最重要的是,将处理无效字符而不会导致丢弃整个字符串(与iconv不同)。


用PHP解码JSON
解码JSON与对其进行编码一样简单。 PHP为您提供了一个方便的json_decode函数,可以为您处理所有事情。如果只是将有效的JSON字符串传递到方法中,则会返回一个stdClass类型的对象。这是一个简短的示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
<?php
$string = '{"foo":"bar","cool":"attr"}';
$result = json_decode($string);

// Result: object(stdClass)#1 (2) { ["foo"]=> string(3)"bar" ["cool"]=> string(4)"attr" }
var_dump($result);

// Prints"bar"
echo $result->foo;

// Prints"attr"
echo $result->cool;
?>

如果要取回关联数组,请将第二个参数设置为true:

1
2
3
4
5
6
7
8
9
10
11
12
13
<?php
$string = '{"foo":"bar","cool":"attr"}';
$result = json_decode($string, true);

// Result: array(2) { ["foo"]=> string(3)"bar" ["cool"]=> string(4)"attr" }
var_dump($result);

// Prints"bar"
echo $result['foo'];

// Prints"attr"
echo $result['cool'];
?>

如果您期望嵌套的JSON文档非常大,则可以将递归深度限制为一定水平。如果文档比给定深度深,该函数将返回null并停止解析。

1
2
3
4
5
6
7
<?php
$string = '{"foo": {"bar": {"cool":"value"}}}';
$result = json_decode($string, true, 2);

// Result: null
var_dump($result);
?>

最后一个参数与json_encode中的工作原理相同,但是当前仅支持一个位掩码(允许您将bigints转换为字符串,并且仅从PHP 5.4起可用)。到目前为止,我们一直在使用有效的JSON字符串(除了从null深度错误开始)。下一部分将向您展示如何处理错误。

错误处理与测试
如果无法解析JSON值或找到比给定(或默认)深度更深的嵌套级别,则从json_decode返回NULL。这意味着json_encode / json_deocde直接不会引发任何异常。

那么我们如何确定错误原因呢? json_last_error函数在这里有帮助。 json_last_error返回一个整数错误代码,该代码可以是以下常量之一(从此处获取):

JSON_ERROR_NONE:没有发生错误。
JSON_ERROR_DEPTH:已超过最大堆栈深度。
JSON_ERROR_STATE_MISMATCH:无效或格式错误的JSON。
JSON_ERROR_CTRL_CHAR:控制字符错误,可能编码错误。
JSON_ERROR_SYNTAX:语法错误。
JSON_ERROR_UTF8:格式错误的UTF-8字符,可能编码错误(自PHP 5.3.3起)。
有了这些信息,我们可以编写一个快速解析帮助器方法,该方法在发现错误时会引发描述性异常。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<?php
class JsonHandler {

    protected static $_messages = array(
        JSON_ERROR_NONE => 'No error has occurred',
        JSON_ERROR_DEPTH => 'The maximum stack depth has been exceeded',
        JSON_ERROR_STATE_MISMATCH => 'Invalid or malformed JSON',
        JSON_ERROR_CTRL_CHAR => 'Control character error, possibly incorrectly encoded',
        JSON_ERROR_SYNTAX => 'Syntax error',
        JSON_ERROR_UTF8 => 'Malformed UTF-8 characters, possibly incorrectly encoded'
    );

    public static function encode($value, $options = 0) {
        $result = json_encode($value, $options);

        if($result)  {
            return $result;
        }

        throw new RuntimeException(static::$_messages[json_last_error()]);
    }

    public static function decode($json, $assoc = false) {
        $result = json_decode($json, $assoc);

        if($result) {
            return $result;
        }

        throw new RuntimeException(static::$_messages[json_last_error()]);
    }

}
?>

现在,我们可以使用上一篇有关异常处理的文章中的异常测试功能来测试我们的异常是否正常工作。

1
2
3
4
5
// Returns"Correctly thrown"
assertException("Syntax error", function() {
    $string = '{"foo": {"bar": {"cool": NONUMBER}}}';
    $result = JsonHandler::decode($string);
});

请注意,自PHP 5.3.3起,在字符串中发现无效的UTF-8字符时,将返回JSON_ERROR_UTF8错误。这强烈表明使用的字符集与UTF-8不同。如果输入的字符串不受您的控制,则可以使用utf8_encode函数将其转换为utf8。

1
<?php echo utf8_encode(json_encode($payload)); ?>

过去,我一直在使用它来转换从不使用UTF-8的旧式MSSQL数据库加载的数据。

资源