Pourquoi la fonction PHP json_encode convertit-elle les chaînes UTF-8 en entités hexadécimales?

148

J'ai un script PHP qui traite une grande variété de langages. Malheureusement, chaque fois que j'essaie d'utiliser json_encode, toute sortie Unicode est convertie en entités hexadécimales. Est-ce le comportement attendu? Existe-t-il un moyen de convertir la sortie en caractères UTF-8?

Voici un exemple de ce que je vois:

CONTRIBUTION

echo $text;

PRODUCTION

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

CONTRIBUTION

json_encode($text);

PRODUCTION

"\u0411\u0430\u0437\u0430 \u0434\u0430\u043d\u043d\u0438 \u0433\u0440\u0435\u0448\u043a\u0430."
David Jones
la source

Réponses:

355

Depuis PHP / 5.4.0, il existe une option appelée "JSON_UNESCAPED_UNICODE". Vérifiez-le:

http://se2.php.net/json_encode

Par conséquent, vous devriez essayer:

json_encode( $text, JSON_UNESCAPED_UNICODE );
John Severinson
la source
3
Aha. Merci! J'aurais dû lire la documentation plus attentivement. Merci.
David Jones
3
JSON_UNESCAPED_UNICODE a été introduit dans PHP 5.4.0 et n'est pas disponible dans les versions antérieures. Lorsque vous l'utilisez dans des versions antérieures, vous obtiendrez cette erreur: "Attention: json_encode () s'attend à ce que le paramètre 2 soit long, chaîne donnée dans ...". Voir la réponse de CertaiN ci-dessous pour la solution 5.3.
Octavian Naicu
Cela fonctionne également avec les lettres danoises Æ, æ, Ø, ø, Å, å Merci!
ymerdrengene
Fantastique, c'était la réponse que je cherchais!
randomizer
2
Tu viens de me sauver la vie. MERCI.
Jon Zangitu
57

JSON_UNESCAPED_UNICODE est disponible sur PHP version 5.4 ou ultérieure.
Le code suivant est pour la version 5.3.

ACTUALISÉ

  • html_entity_decodeest un peu plus efficace que pack+ mb_convert_encoding.
  • (*SKIP)(*FAIL)saute les barres obliques inverses et les caractères spécifiés par des JSON_HEX_*indicateurs.

 

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
la source
1
Le \ u ne devrait-il pas être \ U c'est-à-dire majuscule?
malhal
4
Belle solution pour PHP <5.4;)
qdev
Je cherchais 3 jours pour trouver cette solution pour la version 5.3 car mon hôte n'a pas mis à niveau vers la version 5.4. Pour moi, vous êtes un sauveur de vie et pour être si complet, je préfère marquer cela comme une réponse acceptée!
Laci
Correction d'un bug lorsque la chaîne contient \\ . La nouvelle version obtient \\ une priorité plus élevée que \u.
mpyw
Cela devrait être ajouté dans la bibliothèque php. Bon travail.
Beraki
7

Vous aimez définir un jeu de caractères et unicode sans échappement

 header('Content-Type: application/json;charset=utf-8');  
 json_encode($data,JSON_UNESCAPED_UNICODE|JSON_PRETTY_PRINT);
Adrian Romero
la source
4

Une solution consiste à encoder d'abord les données, puis à les décoder dans le même fichier:

$string =json_encode($input, JSON_UNESCAPED_UNICODE) ; 
echo $decoded = html_entity_decode( $string );
Steffo Dimfelt
la source
1

Voici ma solution combinée pour différentes versions de PHP.

Dans mon entreprise, nous travaillons avec différents serveurs avec différentes versions de PHP, j'ai donc dû trouver une solution qui fonctionne pour tous.

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

Les crédits doivent aller à Marco Gasi & abu . La solution pour PHP> = 5.4 est fournie dans la documentation json_encode.

gaba
la source
0

La fonction raw_json_encode () ci - dessus ne m'a pas résolu le problème (pour une raison quelconque, la fonction de rappel a soulevé une erreur sur mon serveur PHP 5.2.5).

Mais cette autre solution a fonctionné.

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

Les crédits devraient aller à Marco Gasi . J'appelle juste sa fonction au lieu d'appeler 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
la source
0
json_encode($text, JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES);
Hoàng Vũ Tgtt
la source
-2

Depuis que vous avez demandé:

Existe-t-il un moyen de convertir la sortie en caractères UTF-8?

Une autre solution consiste à utiliser utf8_encode .

Cela encodera votre chaîne en UTF-8.

par exemple

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

echo json_encode($rows);
Robin Carlo Catacutan
la source
2
N'utilisez pas ça. Comme indiqué dans la page de documentation PHP, utf8_encode n'est approprié que si votre chaîne d'origine est encodée ISO-8859-1 (Latin1). Ce n'est pas une fonction polyvalente "assurez-vous que cette chaîne est encodée en utf-8".
telomere