121

我有一个带有 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返回 ASCIIjson_encode时,它可以工作,但当它返回 UTF8 时,它不再工作了。

Edit2 :json_last_error()返回JSON_ERROR_UTF8这意味着:格式错误的 UTF-8 字符,可能编码不正确

4

13 回答 13

281

经过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()可能是更好的选择,如注释和其他解决方案中所述。

于 2013-10-14T18:43:30.070 回答
38

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() 函数。

于 2015-02-02T23:37:01.657 回答
33

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

$dbo = new PDO('mysql:host=localhost;dbname=yourdb;charset=utf8', $username, $password);
于 2015-11-15T16:28:51.510 回答
10

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;
}
于 2015-09-29T08:10:41.447 回答
7

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

JSON_UNESCAPED_UNICODE

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

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;
}
于 2018-01-16T21:38:11.633 回答
6

这个接受的答案有效。但是,如果您从 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

于 2015-10-23T09:55:41.547 回答
4

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

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

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

json_encode((object)$myvar);
于 2016-04-15T16:03:12.637 回答
4

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

$var = mb_convert_encoding($var, 'UTF-8');
于 2017-09-14T13:54:44.087 回答
3

的返回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。(这是一个更大的例子。)

您的数据很可能未编码为 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);
于 2013-10-14T18:47:42.210 回答
1

我改进了亚当布贝拉的回答。当{和}没有关闭块时,我只是讨厌它。它更干净,您不会引入错误,或者可能是我过去确实使用过 Perl :)

<?php

class App_Updater_String_Util {    
    /**
     * Usage: App_Updater_String_Util::utf8_encode( $data );
     *
     * @param mixed $d
     * @return mixed
     * @see http://stackoverflow.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;
    }
}

?>
于 2016-10-13T16:40:58.200 回答
1

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

于 2016-12-22T07:38:53.707 回答
0

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

于 2019-01-15T09:25:55.403 回答
0

由于无论如何输出都会以 JSON(字符串)形式结束,这里有一个可以处理各种变量类型的函数:

    function utf8ize($arg)
    {
        if (is_array($arg))
            foreach ($arg as $k => $v)
                $arg[$k] = utf8ize($v);
         else if(is_object($arg))
            return utf8ize((array) $arg);
         else
            return utf8_encode(strval($arg));
        return $arg;
    }

这个答案是对 Matthieu Riegler 和 Adam Bubela 的答案的改进,但是这个答案可以处理所有类型的变量/数据类型(例如:文件句柄/流/phpgd/sql 连接等资源)

当参数为对象时,我将强制转换为数组,以防止在对象属性为只读或私有/受保护时出错。

另外,在else情况下,我strval可以处理其他数据类型,例如resource

我正在使用此函数将变量“强制”为字符串(例如:当 var_dump-ing 或记录到文本文件时)

于 2022-02-21T04:45:31.487 回答