Dlaczego json_encode miałby zwrócić pusty ciąg


108

Mam prostą strukturę php z 3 zagnieżdżonymi tablicami.

Nie używam konkretnych obiektów i sam buduję tablice z 2 zagnieżdżonymi pętlami.

Oto przykład zmiennej var_dump tablicy, którą chcę przekonwertować na 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

W innym skrypcie mam podobną strukturę i json_encodedziała dobrze. Więc nie rozumiem, dlaczego json_encodetu nie zadziała.

Edycja: wydaje się, że wystąpił problem z kodowaniem. Kiedy mb_detect_encodingzwraca ASCII, json_encodedziała, ale kiedy zwraca UTF8, już nie działa.

Edit2: json_last_error()zwraca, JSON_ERROR_UTF8co oznacza: zniekształcone znaki UTF-8, prawdopodobnie nieprawidłowo zakodowane .


Podręcznik PHP mówi This function only works with UTF-8 encoded data., że nie powinno być żadnych problemów z kodowaniem.
MahanGM,

13
Spróbuj użyć utf8_encode()na swoich namepolach tablicy przed przekazać ciąg json_encode().
MahanGM,

Dzięki ! Właśnie doszedłem do tego rozwiązania, które rozwiązało mój problem.
Matthieu Riegler

Tak, widziałem odpowiedź. Powodzenia.
MahanGM,

3
Użyj JSON_PARTIAL_OUTPUT_ON_ERRORopcji, aby zobaczyć problem (np. Pole z UTF8 będzie puste).
Peter Krauss

Odpowiedzi:


255

Dobrze po 2 godzinach kopania (por. Edycje)

Dowiedziałem się, co następuje:

  • W moim przypadku jest to problem z kodowaniem
  • mb_detect_encoding zwraca prawdopodobnie błędną odpowiedź, niektóre łańcuchy prawdopodobnie nie były w UTF-8
  • użycie utf8_encode()na tych ciągach rozwiązało mój problem, ale patrz uwaga poniżej

Oto funkcja rekurencyjna, która może wymusić konwersję do UTF-8 wszystkich ciągów zawartych w tablicy:

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

Użyj go po prostu w ten sposób:

echo json_encode(utf8ize($data));

Uwaga: utf8_encode () koduje ciąg ISO-8859-1 do UTF-8 zgodnie z dokumentacją, więc jeśli nie masz pewności co do kodowania wejściowego iconv () lub mb_convert_encoding (), mogą być lepsze opcje, jak zauważono w komentarzach i innych rozwiązaniach.


4
Dzięki za rozwiązaniem ... Jednak jeden marginesie: zmiana } else {celu } else if (is_string ($d)) {; w przeciwnym razie zmienisz wszystko na łańcuchy (np. INTstanie się a STRING).
Paul Peelen

3
Właśnie uratowałeś mi życie. Miałem już wszystko zakończyć, dopóki nie znalazłem tej funkcji! Dziękuję Ci.
silversunhunter

2
WTF! Dziękujemy za udostępnienie rozwiązania. Widzę, że zajęłoby to dużo czasu, aby to rozgryźć, i jestem wdzięczny za to, że to zrobiłeś i udostępniłeś.
kris

1
Po trzech dniach debugowania mógłbym cię teraz pocałować.
AJB,

2
Jeśli czytasz z bazy danych, po prostu użyj, $ conn-> set_charset ("utf8");
Andrew Briggs

36

Matthieu Riegler zaprezentował naprawdę dobre rozwiązanie, ale musiałem je nieco zmodyfikować, aby obsługiwać obiekty:

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

Jeszcze jedna uwaga: json_last_error () może być pomocna w debugowaniu funkcji json_encode () / json_encode ().


Czy nie powinno być elseifzamiast tego else if? (tj. nie puste).
Uwe Keim

2
@UweKeim zgodnie z dokumentacją PHP „elseif i else if będzie traktowane dokładnie tak samo, gdy używasz nawiasów klamrowych”, co oznacza, że ​​są one równoważne, o ile nie używasz notacji z dwukropkiem, np.if(): elseif:
Adam Bubela

1
Dobra robota. PHP to śmieć i ludzie tacy jak ty nie pozwalają mu trafić na śmietnik.
Lonnie Best

Powinieneś wstawić else if(is_int($d)||is_bool($d)) return $d;przed ostatnią inną, ponieważ:{"success":true, "message":"Ⲃⲟⲟ𝓵ⲉⲁⲛ ⲁⲛⲇ Ⲓⲛϯⲉ𝓰ⲉꞅ𝛓"}
David Refoua

Tak jak @ paul-peelen polecono @ matthieu-riegler: Zmień ostatnie elsena else if(is_string ($d)); w przeciwnym razie zmienisz wszystko na łańcuchy (np. INTstanie się a STRING).
Bruno Serrano

30

Dla mnie odpowiedzią na ten problem było ustawienie charset=utf8w moim połączeniu PDO.

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

2
Lub w funkcjach mysqli: mysqli_set_charset ($ connection, "utf8");
user18099

To była wskazówka do mojego rozwiązania. Trochę inna przyczyna połączenia msqli. Po prostu zadzwoń $mysqli->set_charset("utf8");po wykonaniu obsługi bazy danych.
MaggusK

Użyj utf8mb4w najnowszych wersjach MySQL. utf8jest przestarzały.
Dharman

10

Adam Bubela również zaprezentował naprawdę dobre rozwiązanie, który pomógł mi rozwiązać mój problem, a oto uproszczona funkcja:

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

    return $d;
}

1
Podoba mi się ten, ponieważ zachowuje klucze.
dev0,

7

Mam dokładnie ten sam problem w PHP 5.6. Używam Open Server + Nginx w Windows 7. Wszystkie zestawy znaków są ustawione na UTF-8. Teoretycznie według oficjalnej dokumentacji flaga

JSON_UNESCAPED_UNICODE

powinien rozwiązać ten problem. Niestety nie jest to mój przypadek. Nie wiem dlaczego. Wszystkie powyższe fragmenty nie rozwiązują mojego problemu, dlatego znalazłem własną implementację. Myślę, że to mogłoby komuś pomóc. Przynajmniej rosyjskie litery zdają egzamin.

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

4

Ta zaakceptowana odpowiedź działa. Ale w przypadku, gdy otrzymujesz dane z MySQL (tak jak ja), jest łatwiejszy sposób.

Po otwarciu bazy danych przed zapytaniem możesz ustawić zestaw znaków za pomocą mysqli w następujący sposób:

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

LUB

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


4

Napotkałem ten problem na serwerze ze starszą wersją PHP (5.2). Używałem flagi JSON_FORCE_OBJECT i najwyraźniej nie jest ona obsługiwana do 5.3

Więc jeśli używasz tej flagi, sprawdź swoją wersję!

Wydaje się, że obejście polega na rzutowaniu na obiekt przed kodowaniem, na przykład:

json_encode((object)$myvar);

3

Zwrot mb_detect_encodingmoże być nieprawidłowy:

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

W zależności od domyślnej kolejności wykrywania powyższe może zwracać różne wyniki, więc kodowanie jest fałszywie zgłaszane jako UTF-8. ( Oto większy przykład .)

Prawdopodobnie Twoje dane nie są zakodowane jako UTF-8, więc json_encodepowracają false. Powinieneś spojrzeć na konwersję ciągów do UTF-8 przed kodowaniem 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

Otrzymywałem dane z ob_get_clean () i miałem ten sam problem, ale powyższe rozwiązania nie działają dla mnie. W moim przypadku rozwiązanie było takie, może komuś pomoże.

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

2

użycie utf8_encode () na tych ciągach rozwiązało mój problem.


1

Poprawiłem odpowiedź Adama Bubeli. Po prostu nienawidzę, kiedy bloki nie są zamykane przez {i}. Jest czystszy i nie wprowadzasz błędów, a może to dlatego, że używałem Perla w przeszłości :)

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

?>

0

Jeśli otrzymujesz te dane z bazy danych, użyj mysqli_set_charset($connection, "utf8");w połączeniu, gdy pobierzesz parametry z bazy danych


0

ten problem pojawia się czasami - nie przekazujesz kontroli dostępu do nagłówka.

W moim przypadku, jeśli dodano jakiekolwiek echo przed json_encode. Pokazał wynik, w przeciwnym razie nadchodziła pusta strona.

dodałem

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

i mój problem został rozwiązany.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.