¿Por qué la función PHP json_encode convierte cadenas UTF-8 en entidades hexadecimales?

148

Tengo un script PHP que trata con una amplia variedad de idiomas. Desafortunadamente, cada vez que intento usar json_encode, cualquier salida Unicode se convierte en entidades hexadecimales. ¿Es este el comportamiento esperado? ¿Hay alguna forma de convertir la salida a caracteres UTF-8?

Aquí hay un ejemplo de lo que estoy viendo:

ENTRADA

echo $text;

SALIDA

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

ENTRADA

json_encode($text);

SALIDA

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

Respuestas:

355

Desde PHP / 5.4.0, hay una opción llamada "JSON_UNESCAPED_UNICODE". Echale un vistazo:

http://se2.php.net/json_encode

Por lo tanto, debes probar:

json_encode( $text, JSON_UNESCAPED_UNICODE );
John Severinson
fuente
3
Ajá. ¡Gracias! Debería haber leído la documentación con más cuidado. Gracias.
David Jones
3
JSON_UNESCAPED_UNICODE se introdujo en PHP 5.4.0 y no está disponible en versiones anteriores. Al usarlo en versiones anteriores, obtendrá este error: "Advertencia: json_encode () espera que el parámetro 2 sea largo, la cadena se da en ...". Vea la respuesta de CertaiN a continuación para la solución 5.3.
Octavian Naicu 01 de
Esto también funciona con letras danesas Æ, æ, Ø, ø, Å, å ¡Gracias!
ymerdrengene
¡Fantástico, esta fue la respuesta que estaba buscando!
aleatorizador
2
Acabas de salvarme la vida. GRACIAS.
Jon Zangitu
57

JSON_UNESCAPED_UNICODE está disponible en PHP Versión 5.4 o posterior.
El siguiente código es para la versión 5.3.

ACTUALIZADO

  • html_entity_decodees un poco más eficiente que pack+ mb_convert_encoding.
  • (*SKIP)(*FAIL)omite las barras invertidas y los caracteres especificados por JSON_HEX_*banderas.

 

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
fuente
1
¿No debería ser \ u be \ U, es decir, mayúscula?
malhal
44
Buena solución para PHP <5.4;)
qdev
Estuve buscando 3 días para encontrar esta solución para la Versión 5.3 ya que mi host no se actualizó a 5.4. ¡Para mí eres un salvavidas y por ser tan completo prefiero marcar esto como respuesta aceptada!
Laci
Se corrigió el error cuando la cadena contiene \\ . La versión más nueva toma \\ mayor prioridad que \u.
mpyw
Esto debe agregarse en la biblioteca php. Buen trabajo.
Beraki
7

Te gusta establecer charset y unicode sin escape

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

Una solución es codificar primero los datos y luego decodificarlos en el mismo archivo:

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

Aquí está mi solución combinada para varias versiones de PHP.

En mi empresa estamos trabajando con diferentes servidores con varias versiones de PHP, así que tuve que encontrar una solución que funcione para todos.

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

Los créditos deben ir a Marco Gasi y Abu . La solución para PHP> = 5.4 se proporciona en los documentos json_encode.

gaba
fuente
0

La función raw_json_encode () anterior no me resolvió el problema (por alguna razón, la función de devolución de llamada provocó un error en mi servidor PHP 5.2.5).

Pero esta otra solución realmente funcionó.

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

Los créditos deben ir a Marco Gasi . Acabo de llamar a su función en lugar de llamar a 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
fuente
0
json_encode($text, JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES);
Hoàng Vũ Tgtt
fuente
-2

Desde que preguntaste:

¿Hay alguna forma de convertir la salida a caracteres UTF-8?

Otra solución es usar utf8_encode .

Esto codificará su cadena a UTF-8.

p.ej

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

echo json_encode($rows);
Robin Carlo Catacutan
fuente
2
No uses esto. Como se indica en la página de documentación de PHP, utf8_encode solo es apropiado si su cadena original está codificada en ISO-8859-1 (Latin1). No es una función de uso general "asegúrese de que esta cadena esté codificada en utf-8".
telómero