Why would json_encode return an empty string

2019-01-01 09:05发布

问题:

I have a simple php structure with 3 nested arrays.

I do not use particular objects and I build myself the arrays with 2 nested loops.

Here is a sample of the var_dump of the array I want to convert to Json.

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

In another script I have a similar structure and json_encode works fine. So I don\'t understand why json_encode won\'t work here.

Edit : there seems to be a problem with the encoding. When mb_detect_encoding returns ASCII, the json_encode works but when it returns UTF8, it doesn\'t work anymore.

Edit2 : json_last_error() returns JSON_ERROR_UTF8 which means : Malformed UTF-8 characters, possibly incorrectly encoded.

回答1:

Well after 2 hours of digging (cf Edits)

I found out following :

  • In my case it\'s a encoding problem
  • mb_detect_encoding returns probably a faulty response, some strings were probably not UTF-8
  • using utf8_encode() on those string solved my problem.

Here is a recursive function that can force convert to UTF-8 all the strings contained in an array:

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;
}

Use it simply like this:

echo json_encode(utf8ize($data));


回答2:

Matthieu Riegler presented really good solution however I had to slightly modify it to handle objects too:

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;
}

One more note: json_last_error() may be helpful in debugging json_encode()/json_encode() functions.



回答3:

For me, the answer to this problem was setting charset=utf8 in my PDO connection.

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



回答4:

Adam Bubela also presented really good solution who helped me solved my problem, and here is the simplified function :

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:

I ran into this issue on a server running an older version of PHP (5.2). I was using the JSON_FORCE_OBJECT flag, and apparently that isn\'t supported until 5.3

So if you\'re using that flag be sure to check your version!

A workaround appears to be just casting to an object before encoding, like:

json_encode((object)$myvar);


回答6:

The return of mb_detect_encoding may not be correct:

$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\'))
);

Depending on the default detection order, the above may return different results, so the encoding is falsely being reported as UTF-8. (Here\'s a larger example.)

It is likely that your data is not encoded as UTF-8, so json_encode is returning false. You should look at converting your strings to UTF-8 before JSON-encoding:

$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);


回答7:

This accepted answer works. But in case you are getting your data from MySQL (as I was) there is an easier way.

Once you open you database, before you query you can set the character set using mysqli as follows:

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

OR

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

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



回答8:

using utf8_encode() on those string solved my problem.



回答9:

I have exactly the same problem on PHP 5.6. I use Open Server + Nginx on Windows 7. All charsets are set to UTF-8. In theory, according the official documentation, flag

JSON_UNESCAPED_UNICODE

should solve this. Unfortunately this is not my case. I do not know, why. All snippets above do not solve my problem, thus I have found my own implementation. I believe it could help someone. At least, Russian letters pass the test.

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;
}


回答10:

I have improved Adam Bubela\'s answer. I just hate it when blocks are not closed by { and }. It\'s cleaner and you don\'t introduce bugs or maybe it\'s that I did use Perl in the past :)

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

?>


回答11:

I was getting data from ob_get_clean() and had the same problem, but above solutions don\'t work for me. In my case solution was this, maybe it will help somebody.

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


标签: php json