web-dev-qa-db-fra.com

Pourquoi json_encode renverrait-il une chaîne vide?

J'ai une structure php simple avec 3 tableaux imbriqués. 

Je n'utilise pas d'objets particuliers et je construis moi-même les tableaux avec 2 boucles imbriquées. 

Voici un exemple du var_dump du tableau que je veux convertir en 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

Dans un autre script, j'ai une structure similaire et json_encode fonctionne bien. Je ne comprends donc pas pourquoi json_encode ne fonctionne pas ici.

Edit: il semble y avoir un problème d’encodage. Lorsque mb_detect_encoding renvoie ASCII, le json_encode fonctionne mais lorsqu'il renvoie UTF8, il ne fonctionne plus. 

Edit2: json_last_error() renvoie JSON_ERROR_UTF8, ce qui signifie: Caractères UTF-8 mal formés, éventuellement codés de manière incorrecte .

90
Matthieu Riegler

Bien après 2 heures de creusement (cf Edits) 

J'ai découvert ce qui suit: 

  • Dans mon cas, c'est un problème d'encodage
  • mb_detect_encoding renvoie probablement une réponse erronée, certaines chaînes n'étaient probablement pas UTF-8 
  • utiliser utf8_encode() sur ces chaînes a résolu mon problème. 

Voici une fonction récursive qui peut forcer la conversion en UTF-8 de toutes les chaînes contenues dans un tableau:

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

Utilisez-le simplement comme ceci:

echo json_encode(utf8ize($data));
213
Matthieu Riegler

Matthieu Riegler a présenté une très bonne solution, mais je devais le modifier légèrement pour gérer les objets aussi: 

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

Encore une note: json_last_error () peut être utile pour le débogage des fonctions json_encode ()/json_encode ().

34
Adam Bubela

Pour moi, la réponse à ce problème était de définir charset = utf8 dans ma connexion PDO.

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

23
fayd

Adam Bubela a également présenté une très bonne solution qui m'a aidé à résoudre mon problème, et voici la fonction simplifiée:

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

    return $d;
}
7
Alex

J'ai rencontré ce problème sur un serveur exécutant une version plus ancienne de PHP (5.2). J'utilisais l'indicateur JSON_FORCE_OBJECT et, apparemment, il n'est pas pris en charge avant la version 5.3.

Donc, si vous utilisez ce drapeau, assurez-vous de vérifier votre version!

Une solution de contournement semble ne faire que transtyper un objet avant l'encodage, par exemple:

json_encode((object)$myvar);
4
Shane N

Cette réponse acceptée fonctionne. Mais si vous récupérez vos données depuis MySQL (comme j’étais), il existe un moyen plus simple.

Une fois que vous avez ouvert votre base de données, avant de lancer une requête, vous pouvez définir le jeu de caractères à l'aide de mysqli comme suit:

/* 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();
 }

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

3
Kholofelo

Le retour de mb_detect_encoding peut ne pas être 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'))
);

En fonction de l'ordre de détection par défaut, ce qui précède peut renvoyer des résultats différents, de sorte que le codage est faussement signalé comme UTF-8. ( Voici un exemple plus grand .)

Il est probable que vos données ne sont pas codées au format UTF-8. json_encode renvoie donc false. Vous devriez envisager de convertir vos chaînes en UTF-8 avant le codage JSON:

$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
cmbuckley

utiliser utf8_encode () sur ces chaînes a résolu mon problème. 

2
mobizen

J'ai exactement le même problème sous PHP 5.6 . J'utilise Open Server + Nginx sous Windows 7. Tous les jeux de caractères sont réglés sur UTF-8 . En théorie, selon le documentation officielle , drapeau 

JSON_UNESCAPED_UNICODE

devrait résoudre ce problème. Malheureusement ce n'est pas mon cas. Je ne sais pas pourquoi. Tous les extraits ci-dessus ne résolvent pas mon problème, j'ai donc trouvé ma propre implémentation. Je crois que cela pourrait aider quelqu'un. Au moins, les lettres russes réussissent le 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;
}
2
Vsevolod Azovsky

J'ai amélioré la réponse d'Adam Bubela… .. Je déteste ça quand les blocs ne sont pas fermés par {and}… .. C'est plus propre et vous n'introduisez pas de bugs ou c'est peut-être que j'ai déjà utilisé 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;
    }
}

?>
1
Svetoslav Marinov

J'obtenais des données de ob_get_clean () et j'avais le même problème, mais les solutions ci-dessus ne fonctionnent pas pour moi. Dans mon cas, la solution était la suivante: cela aiderait peut-être quelqu'un.

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

ce problème vient parfois - vous ne passez pas le contrôle d'accès en-tête.

Dans mon cas, si j’avais ajouté un écho avant json_encode. Il montrait le résultat sinon la page blanche arrivait.

J'ai ajouté

header('Access-Control-Allow-Origin: *'); 

et mon problème résolu.

0
Anup

Si vous obtenez ces données d'une base de données, utilisez mysqli_set_charset($connection, "utf8"); en connexion lorsque vous obtenez les paramètres de la base de données.

0