¿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."

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

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

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

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

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.


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


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

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

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.