Warum sollte json_encode eine leere Zeichenfolge zurückgeben?

107

Ich habe eine einfache PHP-Struktur mit 3 verschachtelten Arrays.

Ich verwende keine bestimmten Objekte und baue mir die Arrays mit 2 verschachtelten Schleifen.

Hier ist ein Beispiel für den var_dump des Arrays, das ich in Json konvertieren möchte.

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 einem anderen Skript habe ich eine ähnliche Struktur und json_encodefunktioniert gut. Ich verstehe also nicht, warum json_encodehier nicht funktioniert.

Bearbeiten: Es scheint ein Problem mit der Codierung zu geben. Wenn mb_detect_encodingASCII zurückgegeben wird, json_encodefunktioniert dies, aber wenn UTF8 zurückgegeben wird, funktioniert es nicht mehr.

Edit2: gibt json_last_error()zurück, JSON_ERROR_UTF8was bedeutet: Fehlerhafte UTF-8-Zeichen, möglicherweise falsch codiert .

Matthieu Riegler
quelle
Das PHP-Handbuch besagt, This function only works with UTF-8 encoded data.dass es kein Problem mit der Codierung geben sollte.
MahanGM
13
Versuchen Sie, utf8_encode()Ihre nameArray-Felder zu verwenden, bevor Sie die Zeichenfolge übergeben json_encode().
MahanGM
Vielen Dank ! Ich bin gerade zu dieser Lösung gekommen, die mein Problem gelöst hat.
Matthieu Riegler
Ja, habe die Antwort gesehen. Viel Glück.
MahanGM
3
Verwenden Sie die JSON_PARTIAL_OUTPUT_ON_ERROROption , um das Problem anzuzeigen (z. B. ist das Feld mit UTF8 null).
Peter Krauss

Antworten:

255

Gut nach 2 Stunden Graben (vgl. Bearbeitungen)

Ich fand folgendes heraus:

  • In meinem Fall handelt es sich um ein Codierungsproblem
  • mb_detect_encoding Gibt wahrscheinlich eine fehlerhafte Antwort zurück, einige Zeichenfolgen waren wahrscheinlich nicht UTF-8
  • Die Verwendung utf8_encode()dieser Zeichenfolge hat mein Problem gelöst, aber siehe Hinweis unten

Hier ist eine rekursive Funktion, die die Konvertierung aller in einem Array enthaltenen Zeichenfolgen in UTF-8 erzwingen kann:

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

Verwenden Sie es einfach so:

echo json_encode(utf8ize($data));

Hinweis: utf8_encode () codiert die ISO-8859-1-Zeichenfolge gemäß den Dokumenten in UTF-8. Wenn Sie sich bei der Eingabecodierung nicht sicher sind, sind iconv () oder mb_convert_encoding () möglicherweise bessere Optionen, wie in Kommentaren und anderen Lösungen angegeben.

Matthieu Riegler
quelle
4
Vielen Dank für Ihre Lösung ... jedoch eine Randnotiz: Ändern Sie die } else {zu } else if (is_string ($d)) {; Andernfalls ändern Sie alles in Zeichenfolgen (z. B. INTwird a STRING).
Paul Peelen
3
Du hast mir gerade das Leben gerettet. Ich wollte gerade alles beenden, bis ich diese Funktion gefunden habe !! Danke dir.
Silversunhunter
2
WTF! Vielen Dank, dass Sie Ihre Lösung geteilt haben. Ich kann sehen, dass es viel Zeit gekostet hätte, dies herauszufinden, und ich bin Ihnen dankbar, dass Sie das getan und geteilt haben.
Kris
1
Nach drei Tagen Debuggen konnte ich dich jetzt küssen.
AJB
2
Wenn Sie nur aus der Datenbank lesen, verwenden Sie $ conn-> set_charset ("utf8");
Andrew Briggs
36

Matthieu Riegler präsentierte eine wirklich gute Lösung, aber ich musste sie leicht modifizieren, um auch Objekte zu handhaben:

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

Noch ein Hinweis: json_last_error () kann beim Debuggen der Funktionen json_encode () / json_encode () hilfreich sein.

Adam Bubela
quelle
Sollte es nicht elseifstatt sein else if? (dh kein Leerzeichen).
Uwe Keim
2
@UweKeim gemäß der PHP-Dokumentation "elseif und else if wird nur bei Verwendung von geschweiften Klammern als genau gleich angesehen", was bedeutet, dass sie äquivalent sind, solange Sie nicht die Doppelpunktnotation verwenden, z. B.if(): elseif:
Adam Bubela
1
Gut gemacht. PHP ist Müll und Leute wie Sie halten es davon ab, auf die Müllkippe zu gehen.
Lonnie Best
Sie sollten ein else if(is_int($d)||is_bool($d)) return $d;vor dem letzten einfügen , weil:{"success":true, "message":"Ⲃⲟⲟ𝓵ⲉⲁⲛ ⲁⲛⲇ Ⲓⲛϯⲉ𝓰ⲉꞅ𝛓"}
David Refoua
Genau wie @ paul-peelen @ matthieu-riegler empfohlen hat: Ändern Sie das letzte elsefür else if(is_string ($d)); Andernfalls ändern Sie alles in Zeichenfolgen (z. B. INTwird a STRING).
Bruno Serrano
30

Für mich war die Antwort auf dieses Problem das Einstellen charset=utf8meiner PDO-Verbindung.

$dbo = new PDO('mysql:host=localhost;dbname=yourdb;charset=utf8', $username, $password);
fayd
quelle
2
Oder in mysqli-Funktionen: mysqli_set_charset ($ connection, "utf8");
user18099
Dies war der Hinweis auf meine Lösung. Wenig andere Ursache für die msqli-Verbindung. Rufen $mysqli->set_charset("utf8");Sie einfach an, nachdem Sie Ihre Datenbank bearbeitet haben.
MaggusK
Bitte verwenden Sie utf8mb4in neueren MySQL-Versionen. utf8ist obsolet.
Dharman
10

Adam Bubela präsentierte auch eine wirklich gute Lösung, die mir bei der Lösung meines Problems half, und hier ist die vereinfachte Funktion:

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

    return $d;
}
Alex
quelle
1
Ich mag dieses, da es die Schlüssel bewahrt.
dev0
7

Ich habe genau das gleiche Problem mit PHP 5.6. Ich verwende Open Server + Nginx unter Windows 7. Alle Zeichensätze sind auf UTF-8 eingestellt. Theoretisch laut offizieller Dokumentation Flagge

JSON_UNESCAPED_UNICODE

sollte dies lösen. Dies ist leider nicht mein Fall. Keine Ahnung warum. Alle obigen Schnipsel lösen mein Problem nicht, daher habe ich meine eigene Implementierung gefunden. Ich glaube, es könnte jemandem helfen. Zumindest bestehen russische Buchstaben den 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;
}
Wsewolod Asowski
quelle
4

Diese akzeptierte Antwort funktioniert. Aber falls Sie Ihre Daten von MySQL erhalten (wie ich es war), gibt es einen einfacheren Weg.

Sobald Sie Ihre Datenbank geöffnet haben, können Sie vor der Abfrage den Zeichensatz mit mysqli wie folgt festlegen:

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

ODER

/* 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

Kholofelo
quelle
4

Ich bin auf einem Server mit einer älteren Version von PHP (5.2) auf dieses Problem gestoßen. Ich habe das JSON_FORCE_OBJECT-Flag verwendet, und anscheinend wird dies erst in Version 5.3 unterstützt

Wenn Sie dieses Flag verwenden, überprüfen Sie unbedingt Ihre Version!

Eine Problemumgehung scheint darin zu bestehen, vor dem Codieren nur in ein Objekt umzuwandeln, z.

json_encode((object)$myvar);
Shane N.
quelle
3

Die Rücksendung von ist mb_detect_encodingmöglicherweise nicht korrekt:

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

Abhängig von der Standarderkennungsreihenfolge können die oben genannten Ergebnisse unterschiedlich ausfallen, sodass die Codierung fälschlicherweise als UTF-8 gemeldet wird. ( Hier ist ein größeres Beispiel .)

Es ist wahrscheinlich, dass Ihre Daten nicht als UTF-8 codiert sind und daher json_encodezurückkehren false. Sie sollten sich vor der JSON-Codierung die Konvertierung Ihrer Zeichenfolgen in UTF-8 ansehen:

$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);
cmbuckley
quelle
3

Ich habe Daten von ob_get_clean () erhalten und hatte das gleiche Problem, aber die oben genannten Lösungen funktionieren bei mir nicht. In meinem Fall war die Lösung dies, vielleicht hilft es jemandem.

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

Die Verwendung von utf8_encode () für diese Zeichenfolge hat mein Problem gelöst.

Mobizen
quelle
1

Ich habe Adam Bubelas Antwort verbessert. Ich hasse es einfach, wenn Blöcke nicht durch {und} geschlossen werden. Es ist sauberer und Sie führen keine Fehler ein oder vielleicht habe ich Perl in der Vergangenheit verwendet :)

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

?>
Svetoslav Marinov
quelle
0

Wenn Sie diese Daten aus einer Datenbank mysqli_set_charset($connection, "utf8");abrufen , verwenden Sie sie in Verbindung, wenn Sie die Parameter aus der Datenbank abrufen

raul garcia de la fuente
quelle
0

Dieses Problem tritt manchmal auf - Sie übergeben die Header-Zugriffskontrolle nicht.

In meinem Fall, wenn mir vor json_encode ein Echo hinzugefügt wurde. Es zeigte das Ergebnis, sonst kam eine leere Seite.

Ich fügte hinzu

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

und mein Problem gelöst.

Anup
quelle