mysql - online - ¿Cómo desinfectar la entrada del usuario para una codificación adecuada del contenido antes de guardarlo?
icd 10 online (3)
Tengo una aplicación donde los usuarios ingresan texto en formularios.
Los datos se guardan en una base de datos MySQL (intercalación: utf8_general_ci
) y luego utf8_general_ci
como XML (codificación: UTF-8).
El problema es que las personas tienden a cortar y pegar su información de otras fuentes, por ejemplo, documentos de Microsoft Word o archivos PDF, por ejemplo.
Este texto de entrada a menudo tiene caracteres que son incorrectos para la codificación de salida, cosas como "citas inteligentes", que provienen de un documento en la codificación de Windows-1252
Esto causa problemas, obviamente, al transformar o trabajar en XML porque los caracteres son ilegales.
Entonces, ¿cómo desinfectar la entrada?
Anteriormente, he usado algunos métodos de fuerza bruta, como el script "de-moronize", que consiste en una larga lista de operaciones de búsqueda y reemplazo.
¿Sigue siendo esta la mejor manera de hacerlo? ¿Hay alguna otra manera?
¿Puedo simplemente configurar el atributo accept-charset en el formulario y hacer que el navegador lo haga por mí?
Si es así, ¿qué navegadores harán eso y es probable que haya algún problema?
Además, ¿cómo es que mi base de datos está aceptando estos caracteres, que son caracteres reservados / de control en UTF-8?
Como puede ver, sé lo suficiente sobre las codificaciones como para saber que tengo un problema, pero ahora estoy un poco fuera de mi alcance ...
TIA
Este texto de entrada a menudo tiene caracteres que son incorrectos para la codificación de salida, cosas como "citas inteligentes", que provienen de un documento en la codificación de Windows-1252
Las "citas inteligentes" (bytes 147 y 148 en cp1252) son caracteres Unicode perfectamente válidos, U + 201C y U + 201D. Su aplicación debe ser capaz de manejarlos sin problemas; si no, estás haciendo algo mal y muy probablemente todos los caracteres que no sean ASCII fallarán.
Independientemente de si los caracteres provienen de alguien que los escribe o alguien que los pega desde Word, el navegador debe enviar caracteres codificados en UTF-8 a su aplicación, que debe almacenar los mismos bytes UTF-8 en la base de datos.
Si el navegador no se envía en UTF-8, es probable que no establezca el juego de caracteres de la página HTML que contiene el formulario. Esto se puede hacer usando:
Content-Type: text/html;charset=utf-8
Encabezado HTTP y / o el:
<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
elemento en <cabeza>.
¿Puedo simplemente configurar el atributo accept-charset en el formulario y hacer que el navegador lo haga por mí?
No, accept-charset es básicamente inútil gracias a IE, que lo malinterpreta como "intenta usar este juego de caracteres si el de la página no puede codificar los caracteres que queremos", en lugar de "usar siempre este juego de caracteres". Esto significa que si usa accept-charset puede terminar con una mezcla de codificaciones enviadas a la vez, sin forma de averiguar cuál es cuál. ¡Bonito!
¿Cómo es que mi base de datos está aceptando estos caracteres, que son caracteres reservados / de control en UTF-8?
En MySQL UTF-8 es solo una intercalación, utilizada para comparación y pedidos. Todavía está almacenando los datos como bytes y realmente no le importa si no son secuencias UTF-8 válidas.
Es una buena idea decodificar y verificar las secuencias UTF-8 entrantes en su aplicación de todos modos, porque "secuencias cortas", inválidas en Unicode moderno, pueden ocultar un carácter ''<'' que todavía será reconocido por navegadores anteriores (al menos IE6 pre SP2, Opera 7).
ETA:
Entonces, ingresé una cadena que contiene el byte 146
No, ingresaste un carácter Unicode U + 201B. El navegador trata con caracteres Unicode, no con bytes, hasta el momento en que debe enviar el formulario serializado al servidor. Es entonces cuando decide cómo convertir los caracteres en bytes, y si la página se maneja como UTF-8, siempre elegirá UTF-8.
(Si no es UTF-8, los navegadores tienden a hacer trampa de una manera que no cumple con los estándares: para todos los caracteres que no caben en la codificación, los codificará para referencias de caracteres HTML como ''& # 8217;''. Esto es incorrecto porque ahora no se puede distinguir entre un "y" escapado en el navegador y un "y" real, escrito por el usuario, y es insidiosamente incorrecto porque si luego se hace eco de la referencia como HTML no escaneado, parece que usted está haciendo las cosas bien, que de hecho acabas de hacer un gran agujero de seguridad viejo.)
Fue a la base de datos como 146
Realmente, un byte ''/ x92'', no ''/ xC2 / x92'', ''/ xE2 / x80 / x99'' o ''& # 146;''?
salió cuando produje el XML (codificado en UTF-8), como 146. No tengo quejas del navegador
Entonces no salió como un solo 146 bytes. Un navegador se quejará cuando se le presente un ''/ x92'' desnudo en un archivo XML. (No es un archivo HTML, en el que las secuencias UTF-8 no válidas aparecen como un glifo de caracteres perdidos).
Sospecho que está saliendo como un ''& # 146;'' referencia de personaje, que está bien formada (aunque el carácter U + 0092 es parte del conjunto de control C1, por lo que no se representará como algo útil). Si esto es lo que está sucediendo, la página de su formulario no está siendo recogida como UTF-8 después de todo, y usted está sufriendo el problema de presentación automática de escaneo del navegador descrito anteriormente.
"¿Puedo simplemente configurar el atributo accept-charset en el formulario y hacer que el navegador lo haga por mí?"
Solo si estás dispuesto a confiar en "el navegador", eso podría ser adecuado en algunas aplicaciones, pero en general te deja abierto a la malicia (o algo peor).
(También vea las advertencias de bobince sobre IE ...)
Iain
Puede probar el módulo Perl Encode . Admite la conversión entre varios conjuntos de caracteres, incluido UTF-8 de couse. Acabo de comprobar mi instalación de Perl y también admite "cp1252", que es solo otro nombre para Windows-1252 según Wikipedia. Puede verificar su propia instalación con el siguiente trazador de líneas:
perl -MEncode -e ''print map {"$_/n"} Encode->encodings(":all");''