Dlaczego funkcja json_encode PHP konwertuje ciągi znaków UTF-8 na jednostki szesnastkowe?

148

Mam skrypt PHP, który obsługuje wiele różnych języków. Niestety, ilekroć próbuję użyć json_encode, każde wyjście Unicode jest konwertowane na jednostki szesnastkowe. Czy to jest oczekiwane zachowanie? Czy istnieje sposób na przekonwertowanie danych wyjściowych na znaki UTF-8?

Oto przykład tego, co widzę:

WEJŚCIE

echo $text;

WYNIK

База данни грешка.

WEJŚCIE

json_encode($text);

WYNIK

"\u0411\u0430\u0437\u0430 \u0434\u0430\u043d\u043d\u0438 \u0433\u0440\u0435\u0448\u043a\u0430."
David Jones
źródło

Odpowiedzi:

355

Od PHP / 5.4.0 dostępna jest opcja o nazwie "JSON_UNESCAPED_UNICODE". Sprawdź to:

http://se2.php.net/json_encode

Dlatego powinieneś spróbować:

json_encode( $text, JSON_UNESCAPED_UNICODE );
John Severinson
źródło
3
Aha. Dzięki! Powinienem był uważniej przeczytać dokumentację. Dzięki.
David Jones
3
JSON_UNESCAPED_UNICODE został wprowadzony w PHP 5.4.0 i jest niedostępny we wcześniejszych wersjach. Używając go we wcześniejszych wersjach, pojawi się ten błąd: "Ostrzeżenie: json_encode () oczekuje, że parametr 2 będzie długi, ciąg podany w ...". Zobacz odpowiedź CertaiN poniżej na rozwiązanie 5.3.
Octavian Naicu
Działa to również z duńskimi literami Æ, æ, Ø, ø, Å, å Dziękuję!
ymerdrengene
Fantastycznie, to była odpowiedź, której szukałem!
randomizer
2
Właśnie uratowałeś mi życie. DZIĘKI.
Jon Zangitu,
57

JSON_UNESCAPED_UNICODE jest dostępny w PHP w wersji 5.4 lub nowszej.
Poniższy kod dotyczy wersji 5.3.

AKTUALIZACJA

  • html_entity_decodejest nieco wydajniejszy niż pack+ mb_convert_encoding.
  • (*SKIP)(*FAIL)pomija ukośniki odwrotne i określone znaki przez JSON_HEX_*flagi.

 

function raw_json_encode($input, $flags = 0) {
    $fails = implode('|', array_filter(array(
        '\\\\',
        $flags & JSON_HEX_TAG ? 'u003[CE]' : '',
        $flags & JSON_HEX_AMP ? 'u0026' : '',
        $flags & JSON_HEX_APOS ? 'u0027' : '',
        $flags & JSON_HEX_QUOT ? 'u0022' : '',
    )));
    $pattern = "/\\\\(?:(?:$fails)(*SKIP)(*FAIL)|u([0-9a-fA-F]{4}))/";
    $callback = function ($m) {
        return html_entity_decode("&#x$m[1];", ENT_QUOTES, 'UTF-8');
    };
    return preg_replace_callback($pattern, $callback, json_encode($input, $flags));
}
mpyw
źródło
1
Czy \ u nie powinno być \ U tj. Dużymi literami?
malhal
4
Ładne rozwiązanie dla PHP <5.4;)
qdev
Szukałem 3 dni, aby znaleźć to rozwiązanie dla wersji 5.3, ponieważ mój host nie zaktualizował go do wersji 5.4. Dla mnie jesteś ratownikiem życia i za bycie tak kompletnym wolałbym oznaczyć to jako zaakceptowaną odpowiedź!
Laci,
Naprawiono błąd, gdy ciąg zawiera \\ . Nowsza wersja ma \\ wyższy priorytet niż \u.
mpyw
Należy to dodać do biblioteki php. Dobra robota.
Beraki,
7

Lubisz ustawiać zestaw znaków i kod Unicode bez zmiany znaczenia

 header('Content-Type: application/json;charset=utf-8');  
 json_encode($data,JSON_UNESCAPED_UNICODE|JSON_PRETTY_PRINT);
Adrian Romero
źródło
4

Jednym z rozwiązań jest najpierw zakodowanie danych, a następnie zdekodowanie ich w tym samym pliku:

$string =json_encode($input, JSON_UNESCAPED_UNICODE) ; 
echo $decoded = html_entity_decode( $string );
Steffo Dimfelt
źródło
1

Oto moje połączone rozwiązanie dla różnych wersji PHP.

W mojej firmie pracujemy z różnymi serwerami z różnymi wersjami PHP, więc musiałem znaleźć rozwiązanie działające dla wszystkich.

$phpVersion = substr(phpversion(), 0, 3)*1;

if($phpVersion >= 5.4) {
  $encodedValue = json_encode($value, JSON_UNESCAPED_UNICODE);
} else {
  $encodedValue = preg_replace('/\\\\u([a-f0-9]{4})/e', "iconv('UCS-4LE','UTF-8',pack('V', hexdec('U$1')))", json_encode($value));
}

Kredyty powinny trafić do Marco Gasi i abu . Rozwiązanie dla PHP> = 5.4 znajduje się w dokumentacji json_encode.

gaba
źródło
0

Funkcja raw_json_encode () powyżej nie rozwiązuje mi problemu (z jakiegoś powodu, funkcja zwrotna zgłosił błąd na mój serwer PHP 5.2.5).

Ale to inne rozwiązanie faktycznie zadziałało.

https://www.experts-exchange.com/questions/28628085/json-encode-fails-with-special-characters.html

Kredyty powinny trafić do Marco Gasi . Po prostu wywołuję jego funkcję zamiast wywoływać json_encode ():

function jsonRemoveUnicodeSequences( $json_struct )
{ 
    return preg_replace( "/\\\\u([a-f0-9]{4})/e", "iconv('UCS-4LE','UTF-8',pack('V', hexdec('U$1')))", json_encode( $json_struct ) );
}
abu
źródło
0
json_encode($text, JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES);
Hoàng Vũ Tgtt
źródło
-2

Ponieważ zapytałeś:

Czy istnieje sposób na przekonwertowanie danych wyjściowych na znaki UTF-8?

Innym rozwiązaniem jest użycie utf8_encode .

To zakoduje twój ciąg do UTF-8.

na przykład

foreach ($rows as $key => $row) {
  $rows[$key]["keyword"] = utf8_encode($row["keyword"]);
}

echo json_encode($rows);
Robin Carlo Catacutan
źródło
2
Nie używaj tego. Jak stwierdzono na stronie dokumentacji PHP, utf8_encode jest odpowiednie tylko wtedy, gdy oryginalny ciąg jest zakodowany w standardzie ISO-8859-1 (Latin1). Nie jest to uniwersalna funkcja „upewnij się, że ten ciąg jest zakodowany w formacie utf-8”.
telomere