如何解决 php json_decode 中的 JSON_ERROR_UTF8 错误?

Posted

技术标签:

【中文标题】如何解决 php json_decode 中的 JSON_ERROR_UTF8 错误?【英文标题】:How to solve JSON_ERROR_UTF8 error in php json_decode? 【发布时间】:2012-04-29 06:03:15 【问题描述】:

我正在尝试这段代码

$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 和 decode、解码十六进制代码,但我总是收到错误“JSON_ERROR_UTF8”。

我该如何解决这个问题?

【问题讨论】:

我不确定为什么错误会以 UTF8 错误的形式出现。该 URL 返回的 JSON 无效,因为它在应该使用双引号的地方使用单引号。它不通过 JSON LINT (jsonlint.com)。也就是说,我假设您代码第 2 行的 $x 应该是 $json? 是的,我正在清理代码并忘记更改 $x,您是否尝试过使其有效然后尝试对其进行解码?我不知道如何使它有效。 我尝试用双引号替换所有单引号,但随后遇到了其他验证问题。还在看。 我最终使用了正则表达式,无法让 json 工作。 【参考方案1】:

你需要简单的一行代码:

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

学分:桑乐,我的队友给了我这个密码。对!

【讨论】:

对我不起作用PHP Notice: iconv(): Detected an illegal character in input string in /tmp/parse_json.php on line 4。并返回 false 谢谢,伙计!你拯救了我的一天! Warning: iconv(): Wrong encoding, conversion from "UTF-8" to "UTF-8//IGNORE" is not allowed 返回 false PHP 8.0.0 此代码是 mumbo-jumbo,它不会“修复”UTF-8。尽管它的名字,utf8_encode 不是某种“修复我所有的 UTF-8 问题”功能。它只是从 ISO-8859-1 转换为 UTF-8——如果你有 iconv 可用,可以更清楚地写为iconv('ISO-8859-1', 'UTF-8', $input)。在实际上不是 ISO-8859-1 编码的字符串上运行它会给你“有效”但完全无意义的 UTF-8。以下对 iconv 的调用绝对不会执行任何操作,因为 utf8_encode 的输出将始终是有效的 UTF-8。【参考方案2】:

除非你能保证输入是有效的,否则 iconv 函数是毫无价值的。请改用 mb_convert_encoding。

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

您可以获得比“自动”更明确的信息,甚至可以指定以逗号分隔的预期输入编码列表。

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

【讨论】:

【参考方案3】:

There is a good function 清理您的阵列。

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

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() 效果更好

【讨论】:

谢谢。为我工作。 几个月后,这导致我的代码出现严重的内存峰值。不过,它的工作率为 99.99%。 @SteveB 我认为你的内存循环是由于这个函数可以进入递归循环,因为它调用自己。如果它继续收到错误 JSON_ERROR_UTF8 它会卡住。我添加了第四个参数,如果该参数为真,则允许 JSON_ERROR_UTF8 案例调用自身,但如果再次失败,我将 false 传递给自身,如果它再次失败,它将不会继续调用自身。它将防止无限循环,甚至只是一个高内存循环。缺点是您只能“尝试一次”,但根据我的编码风格,这就是您所需要的,否则我希望收到错误通知。 康斯坦丁你可能是指@Travis :) 我已经应用了他的评论并提交了编辑。颠倒了逻辑,因为它在没有否定的情况下感觉更“明显”。 尽管有它的名字,但 utf8_encode 并不是某种“修复我所有的 UTF-8 问题”的功能。它只是从 ISO-8859-1 转换为 UTF-8。在实际上不是 ISO-8859-1 编码的字符串上运行它会给你“有效”但完全无意义的 UTF-8。【参考方案4】:

在 PHP 中解码 JSON 解码 JSON 就像编码它一样简单。 PHP 为您提供了一个方便的 json_decode 函数,可以为您处理所有事情。如果你只是将一个有效的 JSON 字符串传递给方法,你会得到一个 stdClass 类型的对象。这是一个简短的例子:

<?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:

<?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 并停止解析。

<?php
$string = '"foo": "bar": "cool": "value"';
$result = json_decode($string, true, 2);

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

最后一个参数的工作方式与 json_encode 中的相同,但目前只支持一个位掩码(它允许您将 bigints 转换为字符串,并且仅在 PHP 5.4 及更高版本中可用)。我们一直在使用有效的 JSON 字符串,直到现在(除了空深度错误)。下一部分将向您展示如何处理错误。

错误处理和测试 如果无法解析 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 起)。 有了这些信息,我们就可以编写一个快速解析辅助方法,在发现错误时引发描述性异常。

<?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()]);
    


?>

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

// 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。

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

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

source

【讨论】:

【参考方案5】:

我解决了在@Konstantin 的“utf8ize”函数中添加另一个“if”来管理对象(我没有使用其他函数):

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);
     else if (is_object($mixed)) 
        $a = (array)$mixed; // from object to array
        return utf8ize($a);
    
    return $mixed;

【讨论】:

【参考方案6】:

没有“解决”编码问题的灵丹妙药;你必须了解你有什么编码,然后转换它。

计算机最终传输和存储二进制数据;为了使二进制数据有用,我们设计了这样的代码:“这个二进制字符串代表一个'a',一个代表一个'b',另一个代表商务西装悬浮表情符号?️”。 UTF-8(稍微简化一点)只是这些编码之一。其他名称有 ASCII、ISO-8859-1、Windows Code Page 1252 和 Shift-JIS。

如果您只知道一个字符串不是“非 UTF-8”您无法将其转换为 UTF-8,因为您不知道第一个字符是否应该是“a ”,或“?️”。

如果你确实知道你的字符串是什么编码,你可以使用 PHP 中的三个函数中的任何一个;根据您安装的 PHP,部分或全部可能不可用,但它们是您想要的。

iconv mb_convert_encoding UConverter::transcode

请注意,mb_convert_encoding 允许您省略说明当前编码的参数。这不会自动计算出正确的编码,它只是使用您控制的全局设置。

PHP 中还提供了另外两个名称错误的函数:utf8_encode 和 utf8_decode。这些只是上述三个函数的极其有限的版本:它们只能从 ISO-8859-1 转换为 UTF-8 并返回。如果您的字符串不在该编码中(并且您不希望它是)这些函数将无济于事。它们可能会使您的错误消失,但这与修复您的数据不同。

【讨论】:

以上是关于如何解决 php json_decode 中的 JSON_ERROR_UTF8 错误?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 PHP 中解决“调用未定义函数 Composer\Json\json_decode()”?

PHP json_encode json_decode UTF-8

当json_decode、stripslashes等解决方案都不起作用时,如何在php中解析json?

PHP 获取JSON json_decode返回NULL解决办法

PHP 获取JSON json_decode返回NULL解决办法

json_decode() (PHP 7) 中的新行和标签