php - una - Cómo evitar que json_encode() caiga cadenas con caracteres no válidos
php json example (5)
¿Hay alguna manera de evitar que json_encode()
devuelva null
para una cadena que contiene un carácter no válido (no UTF-8)?
Puede ser un dolor en el culo depurar en un sistema complejo. Sería mucho más apropiado ver realmente el carácter no válido, o al menos omitirlo. Tal como está, json_encode()
caerá silenciosamente toda la cadena.
Ejemplo (en UTF-8):
$string =
array(utf8_decode("Düsseldorf"), // Deliberately produce broken string
"Washington",
"Nairobi");
print_r(json_encode($string));
Resultados en
[null,"Washington","Nairobi"]
Resultado deseado:
["D�sseldorf","Washington","Nairobi"]
Nota : No estoy buscando hacer que las cadenas rotas funcionen en json_encode (). Estoy buscando formas de facilitar el diagnóstico de errores de codificación. Una cadena null
no es útil para eso.
En lugar de usar la función iconv, puede usar directamente el json_encode con la opción JSON_UNESCAPED_UNICODE (> = PHP5.4.0)
Asegúrate de poner "charset = utf-8" en el encabezado de tu archivo php:
encabezado (''Content-Type: application / json; charset = utf-8'');
Esta función eliminará todos los caracteres UTF8 no válidos de una cadena:
function removeInvalidChars( $text) {
$regex = ''/( [/x00-/x7F] | [/xC0-/xDF][/x80-/xBF] | [/xE0-/xEF][/x80-/xBF]{2} | [/xF0-/xF7][/x80-/xBF]{3} ) | ./x'';
return preg_replace($regex, ''$1'', $text);
}
Lo uso después de convertir un documento de Excel a json, ya que no se garantiza que los documentos de Excel estén en UTF8.
No creo que haya una manera particularmente sensata de convertir los caracteres inválidos en caracteres visibles pero válidos. Podría reemplazar los caracteres no válidos con U + FFFD, que es el carácter de reemplazo Unicode al girar la expresión regular de arriba, pero eso realmente no proporciona una mejor experiencia de usuario que solo eliminar los caracteres no válidos.
Necesitas saber la codificación de todas las cadenas con las que estás tratando o estás entrando en un mundo de dolor.
UTF-8 es una codificación fácil de usar. Además, JSON está definido para usar UTF-8 (http://www.json.org/JSONRequest.html). Entonces, ¿por qué no usarlo?
Respuesta corta: la forma de evitar que json_encode () pierda sus cadenas es asegurarse de que sean UTF-8 válidas.
php intenta arrojar un error, pero solo si desactiva display_errors . Esto es extraño porque la configuración display_errors
solo sirve para controlar si los errores se imprimen en la salida estándar, no si se desencadena o no un error. Quiero enfatizar que cuando tienes display_errors
, aunque puedas ver todo tipo de otros errores de php, php no solo oculta este error, ni siquiera lo activará . Eso significa que no se mostrará en ningún registro de errores, ni se llamará a ningún error_handlers personalizado. El error nunca ocurre.
Aquí hay un código que demuestra esto:
error_reporting(-1);//report all errors
$invalid_utf8_char = chr(193);
ini_set(''display_errors'', 1);//display errors to standard output
var_dump(json_encode($invalid_utf8_char));
var_dump(error_get_last());//nothing
ini_set(''display_errors'', 0);//do not display errors to standard output
var_dump(json_encode($invalid_utf8_char));
var_dump(error_get_last());// json_encode(): Invalid UTF-8 sequence in argument
Ese comportamiento extraño y desafortunado está relacionado con este error https://bugs.php.net/bug.php?id=47494 y algunos otros, y parece que nunca se solucionará.
solución:
Limpiar la cadena antes de pasarla a json_encode puede ser una solución viable.
$stripped_of_invalid_utf8_chars_string = iconv(''UTF-8'', ''UTF-8//IGNORE'', $orig_string);
if ($stripped_of_invalid_utf8_chars_string !== $orig_string) {
// one or more chars were invalid, and so they were stripped out.
// if you need to know where in the string the first stripped character was,
// then see http://.com/questions/7475437/find-first-character-that-is-different-between-two-strings
}
$json = json_encode($stripped_of_invalid_utf8_chars_string);
http://php.net/manual/en/function.iconv.php
El manual dice
//IGNORE
descarta silenciosamente los caracteres que son ilegales en el juego de caracteres objetivo.
Así que al eliminar primero los personajes problemáticos, en teoría, json_encode () no debería tener nada con lo que ahogarse y fallar. No he verificado que la salida de iconv con el indicador //IGNORE
sea perfectamente compatible con la noción json_encodes de los caracteres utf8 válidos, así que ten cuidado con el comprador ... ya que puede haber casos límite donde todavía falla. ugh, odio los problemas de conjunto de caracteres.
Editar
en php 7.2+, parece haber algunos nuevos indicadores para json_encode
: JSON_INVALID_UTF8_IGNORE
y JSON_INVALID_UTF8_SUBSTITUTE
Todavía no hay mucha documentación, pero por ahora, esta prueba debería ayudarte a comprender el comportamiento esperado: https://github.com/php/php-src/blob/master/ext/json/tests/json_encode_invalid_utf8.phpt
También existe la posibilidad de un indicador JSON_THROW_ON_ERROR
en una futura versión de php :)
$s = iconv(''UTF-8'', ''UTF-8//IGNORE'', $s);
Esto resolvió el problema. No estoy seguro de por qué los chicos de php no han hecho la vida más fácil al arreglar json_encode()
.
De todos modos, usar lo anterior le permite a json_encode () crear objetos incluso si los datos contienen caracteres especiales (por ejemplo, letras suecas).
A continuación, puede utilizar el resultado en javascript sin la necesidad de decodificar los datos a su codificación original (con unescape()
, encodeURIComponent()
, decodeURIComponent()
, decodeURIComponent()
);
Lo estoy usando así en php (smarty):
$template = iconv(''UTF-8'', ''UTF-8//IGNORE'', $screen->fetch("my_template.tpl"));
Luego envío el resultado a javascript y simplemente innerHTML
la plantilla lista (html peace) en mi documento.
Simplemente dicha línea arriba debería implementarse en json_encode()
alguna manera para permitir que funcione con cualquier codificación.