为啥 json_encode 会返回一个空字符串

Posted

技术标签:

【中文标题】为啥 json_encode 会返回一个空字符串【英文标题】:Why would json_encode return an empty string为什么 json_encode 会返回一个空字符串 【发布时间】:2013-10-22 01:55:46 【问题描述】:

我有一个带有 3 个嵌套数组的简单 php 结构。

我不使用特定对象,而是使用 2 个嵌套循环构建自己的数组。

这是我要转换为 Json 的数组的 var_dump 示例。

array (size=2)
  'tram B' => 
    array (size=2)
      0 => 
        array (size=3)
          'name' => string 'Ile Verte' (length=9)
          'distance' => int 298
          'stationID' => int 762
      1 => 
        array (size=3)
          'name' => string 'La Tronche Hôpital' (length=18)
          'distance' => int 425
          'stationID' => int 771
  16 => 
    array (size=4)
      0 => 
        array (size=3)
          'name' => string 'Bastille' (length=8)
          'distance' => int 531
          'stationID' => int 397
      1 => 
        array (size=3)
          'name' => string 'Xavier Jouvin' (length=13)
          'distance' => int 589
          'stationID' => int 438

在另一个脚本中,我有类似的结构,json_encode 工作正常。 所以我不明白为什么json_encode 在这里不起作用。

编辑:编码似乎有问题。当mb_detect_encoding 返回 ASCII 时,json_encode 可以工作,但是当它返回 UTF8 时,它就不再工作了。

Edit2 : json_last_error() 返回 JSON_ERROR_UTF8 这意味着:Malformed UTF-8 characters, possibly incorrectly encoded。

【问题讨论】:

PHP 手册说This function only works with UTF-8 encoded data. 所以编码应该没有问题。 在将字符串交给json_encode() 之前,尝试在name 数组字段上使用utf8_encode() 谢谢!我刚刚来到这个解决我的问题的解决方案。 是的,看到了答案。祝你好运。 使用JSON_PARTIAL_OUTPUT_ON_ERROR option 来查看问题(例如,UTF8 的字段将为空)。 【参考方案1】:

经过 2 小时的挖掘(cf Edits)

我发现了以下内容:

就我而言,这是一个编码问题 mb_detect_encoding 可能返回错误响应,某些字符串可能不是 UTF-8 在这些字符串上使用utf8_encode() 解决了我的问题,但请参阅下面的注释

这是一个递归函数,可以强制将数组中包含的所有字符串转换为 UTF-8:

function utf8ize($d) 
    if (is_array($d)) 
        foreach ($d as $k => $v) 
            $d[$k] = utf8ize($v);
        
     else if (is_string ($d)) 
        return utf8_encode($d);
    
    return $d;

像这样简单地使用它:

echo json_encode(utf8ize($data));

注意:utf8_encode() 根据文档将 ISO-8859-1 字符串编码为 UTF-8,因此如果您不确定输入编码 iconv() 或 mb_convert_encoding() 可能是更好的选择,如 cmets 和其他解决方案中所述.

【讨论】:

感谢您的解决方案...但是,请注意:将 else 更改为 else if (is_string ($d)) ;否则你会将所有内容都更改为字符串(例如,INT 将变为 STRING)。 你刚刚救了我的命。我正要结束一切,直到我找到这个功能!谢谢。 WTF!感谢您分享您的解决方案。我可以看到这需要大量的挖掘才能弄清楚,我很感谢你这样做和分享。 经过三天的调试,我现在可以亲你了。 如果从数据库中读取就用$conn->set_charset("utf8");【参考方案2】:

mb_detect_encoding的返回可能不正确:

$data = iconv('UTF-8', 'ISO-8859-1', 'La Tronche Hôpital');
var_dump(
    mb_detect_encoding($data),
    mb_detect_encoding($data, array('ISO-8859-1', 'UTF-8'))
);

根据默认的检测顺序,上面可能会返回不同的结果,所以编码被误报为UTF-8。 (Here's a larger example.)

您的数据很可能未编码为 UTF-8,因此json_encode 将返回false。在 JSON 编码之前,您应该考虑将字符串转换为 UTF-8:

$fromEncoding = 'ISO-8859-1'; // This depends on the data

array_walk_recursive($array, function (&$value, $key, $fromEncoding) 
    if (is_string($value)) 
        $value = iconv($fromEncoding, 'UTF-8', $value);
    
, $fromEncoding);

【讨论】:

【参考方案3】:

Matthieu Riegler 提出了非常好的解决方案,但是我不得不稍微修改它来处理对象:

function utf8ize($d) 
    if (is_array($d)) 
        foreach ($d as $k => $v) 
            $d[$k] = utf8ize($v);

     else if(is_object($d))
        foreach ($d as $k => $v) 
            $d->$k = utf8ize($v);

     else 
        return utf8_encode($d);

    return $d;

另外一点:json_last_error() 可能有助于调试 json_encode()/json_encode() 函数。

【讨论】:

不应该是elseif而不是else if吗? (即没有空白)。 @UweKeim 根据 PHP 文档“elseif 和 else if 仅在使用大括号时才会被认为是完全相同的”,这意味着只要您不使用冒号,它们就是等价的,例如if(): elseif: 干得好。 PHP 是垃圾,像你这样的人不要让它去垃圾场。 你应该在最后一个 else 之前插入一个 else if(is_int($d)||is_bool($d)) return $d;,因为:"success":true, "message":"Ⲃⲟⲟ?ⲉⲁⲛ ⲁⲛⲇ Ⲓⲛϯⲉ?ⲉꞅ?" 就像@paul-peelen 向@matthieu-riegler 推荐的那样:将最后一个else 更改为else if(is_string ($d));否则你会将所有内容都更改为字符串(例如,INT 将变为 STRING)。【参考方案4】:

Adam Bubela 还提出了非常好的解决方案,帮助我解决了我的问题,这是简化的功能:

function utf8ize($d)
 
    if (is_array($d) || is_object($d))
        foreach ($d as &$v) $v = utf8ize($v);
    else
        return utf8_encode($d);

    return $d;

【讨论】:

我喜欢这个,因为它保留了密钥。【参考方案5】:

这个接受的答案有效。但是,如果您从 mysql 获取数据(就像我一样),有一种更简单的方法。

一旦你打开你的数据库,在你查询之前你可以使用mysqli设置字符集如下:

/* change character set to utf8 | Procedural*/
if (!mysqli_set_charset($link, "utf8")) 
    printf("Error loading character set utf8: %s\n", mysqli_error($link));
    exit();

/* change character set to utf8 | Object Oriented*/
if (!$mysqli->set_charset("utf8")) 
        printf("Error loading character set utf8: %s\n", $mysqli->error);
        exit();
 

链接: http://php.net/manual/en/mysqli.set-charset.php

【讨论】:

注意:$mysqli 是您在创建 mysql 连接时填充的变量的名称。您的变量名称可能会有所不同。示例 $mysqli = new mysqli($host, $user, $password, $db, $port);另外,如上面cmets中提到的,对于较新版本的MySql,推荐使用utf8mb4而不是utf8。【参考方案6】:

对我来说,这个问题的答案是在我的 PDO 连接中设置 charset=utf8

$dbo = new PDO('mysql:host=localhost;dbname=yourdb;charset=utf8', $username, $password);

【讨论】:

或者在mysqli函数中:mysqli_set_charset($connection, "utf8"); 这是我解决方案的提示。 msqli 连接的原因略有不同。完成数据库处理后只需致电$mysqli->set_charset("utf8"); 请在最近的 MySQL 版本中使用utf8mb4utf8 已过时。【参考方案7】:

我在运行旧版本 PHP (5.2) 的服务器上遇到了这个问题。我使用的是 JSON_FORCE_OBJECT 标志,显然直到 5.3 才支持它

因此,如果您使用该标志,请务必检查您的版本!

一种解决方法似乎只是在编码之前强制转换为一个对象,例如:

json_encode((object)$myvar);

【讨论】:

【参考方案8】:

我改进了 Adam Bubela 的答案。 当块没有被 和 关闭时,我只是讨厌它。 它更干净,你不会引入错误,或者可能是我过去确实使用过 Perl :)

<?php

class App_Updater_String_Util     
    /**
     * Usage: App_Updater_String_Util::utf8_encode( $data );
     *
     * @param mixed $d
     * @return mixed
     * @see http://***.com/questions/19361282/why-would-json-encode-returns-an-empty-string
     */
    public static function utf8_encode($d) 
        if (is_array($d)) 
            foreach ($d as $k => $v) 
                $d[$k] = self::utf8_encode($v);
            
         elseif (is_object($d)) 
            foreach ($d as $k => $v) 
                $d->$k = self::utf8_encode($v);
            
         elseif (is_scalar($d)) 
            $d = utf8_encode($d);
        

        return $d;
    


?>

【讨论】:

【参考方案9】:

在这些字符串上使用 utf8_encode() 解决了我的问题。

【讨论】:

【参考方案10】:

我从 ob_get_clean() 获取数据并且遇到了同样的问题,但上述解决方案对我不起作用。在我的情况下,解决方案是这样的,也许它会对某人有所帮助。

$var = mb_convert_encoding($var, 'UTF-8');

【讨论】:

【参考方案11】:

我在 PHP 5.6 上遇到了完全相同的问题。 我在 Windows 7 上使用 Open Server + nginx。所有字符集都设置为 UTF-8。 理论上,根据official documentation,flag

JSON_UNESCAPED_UNICODE

应该解决这个问题。 不幸的是,这不是我的情况。我不知道为什么。上面所有的 sn-ps 都不能解决我的问题,因此我找到了自己的实现。我相信它可以帮助某人。至少,俄语字母通过了测试。

function utf8ize($d) 
    if (is_array($d) || is_object($d)) 
        foreach ($d as &$v) $v = utf8ize($v);
     else 
        $enc   = mb_detect_encoding($d);

        $value = iconv($enc, 'UTF-8', $d);
        return $value;
    

    return $d;

【讨论】:

【参考方案12】:

如果您从数据库中获取此数据,请在从数据库中获取参数时使用mysqli_set_charset($connection, "utf8"); 连接

【讨论】:

以上是关于为啥 json_encode 会返回一个空字符串的主要内容,如果未能解决你的问题,请参考以下文章

为啥 json_encode 添加反斜杠?

json_encode 的斜线问题。为啥以及如何解决它?

PHP json_encode($arr) 为啥会改变数组的顺序,怎么解决。在线等

解决php使用json_encode在前端返回字符串的问题

对数组内容使用了json_encode返回汉字内容返回了空值

json_encode 返回“ [重复]