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

时间:2012-04-17 20:55:30

标签: php json parsing jsonp

我正在尝试此代码

$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”。

我该如何解决这个问题?

6 个答案:

答案 0 :(得分:68)

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()

效果更好

答案 1 :(得分:52)

您需要简单的代码行:

$input = iconv('UTF-8', 'UTF-8//IGNORE', utf8_encode($input));
$json = json_decode($input);
信用:桑乐,我的同伴给了我这个代码。呀!

答案 2 :(得分:11)

除非您能保证输入有效,否则iconv功能毫无价值。改为使用mb_convert_encoding。

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

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

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

答案 3 :(得分:0)

用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字符串,直到现在(除了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起)。 有了这些信息,我们可以编写一个快速解析帮助器方法,该方法将在发现错误时引发描述性异常。

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

答案 4 :(得分:0)

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

object IEnumerable.Current

答案 5 :(得分:0)

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

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

如果你只知道一个字符串“不是 UTF-8”你不能把它变成 UTF-8 因为你不知道第一个字符是否应该是一个“a ”,或“?️”。

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

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

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