Tengo una aplicación que trata con clientes de todo el mundo y, naturalmente, quiero que todo lo que ingrese a mis bases de datos esté codificado en UTF-8.
El principal problema para mí es que no sé qué codificación va a ser la fuente de cualquier cadena; podría ser desde un cuadro de texto (el uso <form accept-charset="utf-8">
solo es útil si el usuario realmente envía el formulario), o podría ser de un archivo de texto cargado, por lo que realmente no tengo control sobre la entrada.
Lo que necesito es una función o clase que se asegure de que todo lo que vaya a mi base de datos esté, en la medida de lo posible, codificado en UTF-8. Lo he intentado iconv(mb_detect_encoding($text), "UTF-8", $text);
pero eso tiene problemas (si la entrada es 'prometida', devuelve 'prometido'). He intentado muchas cosas = /
Para la carga de archivos, me gusta la idea de pedirle al usuario final que especifique la codificación que usan y les muestre vistas previas de cómo se verá la salida, pero esto no ayuda contra los piratas informáticos desagradables (de hecho, podría hacerles la vida un poco más fácil)
He leído las otras preguntas SO sobre el tema, pero parece que todas tienen diferencias sutiles como "Necesito analizar fuentes RSS" o "Raspar datos de sitios web" (o, de hecho, "No se puede").
¡Pero debe haber algo que al menos tenga un buen intento !
fuente
UTF-8//IGNORE
como el segundo parámetro eniconv
?Respuestas:
Lo que estás pidiendo es extremadamente difícil. Si es posible, lograr que el usuario especifique la codificación es lo mejor. Prevenir un ataque no debería ser mucho más fácil o más difícil de esa manera.
Sin embargo, podrías intentar hacer esto:
Establecerlo en estricto podría ayudarlo a obtener un mejor resultado.
fuente
mb_detect_encoding
código fuente en su distribución de php (en algún lugar aquí: ext / mbstring / libmbfl / mbfl / mbfl_ident.c). Esta función no funciona correctamente en absoluto. Para algunas codificaciones incluso tiene "return true", lol. Otros están en las funciones Ctrl + c Ctrl + v. Esto se debe a que no puede detectar la codificación sin algún tipo de diccionario o enfoque estadístico (como el mío).mb_detect_encoding
revisa la lista de codificaciones suministradas y acepta la primera que no tiene secuencias de bytes no válidas en la cadena ... Para codificaciones que no tienen secuencias de bytes no válidas como ISO-8859-1, siempre es cierto . No hay heurísticas "inteligentes", y los resultados varían mucho con la lista (y el orden) de las codificaciones que pasa.mb_detect_order()
aunque es el valor predeterminado para este parámetro, porque quería establecer la detección de codificación estricta en verdadero (el tercer parámetro) :)En la patria de Rusia tenemos 4 codificaciones populares, por lo que su pregunta tiene una gran demanda aquí.
Solo mediante códigos de caracteres de símbolos no puede detectar la codificación, porque las páginas de códigos se cruzan. Algunas páginas de códigos en diferentes idiomas tienen incluso una intersección completa. Entonces, necesitamos otro enfoque .
La única forma de trabajar con codificaciones desconocidas es trabajar con probabilidades. Por lo tanto, no queremos responder la pregunta "¿qué es la codificación de este texto?", Estamos tratando de entender " ¿qué es lo más probable la codificación de este texto? ".
Un tipo aquí en el popular blog ruso de tecnología inventó este enfoque:
Cree el rango de probabilidad de los códigos char en cada codificación que desee admitir. Puedes construirlo usando algunos textos grandes en tu idioma (por ejemplo, algo de ficción, usa Shakespeare para inglés y Tolstoi para ruso, jajaja). Obtendrás algo así:
Próximo. Toma texto en codificación desconocida y para cada codificación en su "diccionario de probabilidad" busca la frecuencia de cada símbolo en texto codificado desconocido. Suma de probabilidades de símbolos. La codificación con mayor calificación es probablemente el ganador. Mejores resultados para textos más grandes.
Si está interesado , con gusto puedo ayudarlo con esta tarea. Podemos aumentar enormemente la precisión mediante la creación de una lista de probabilidades de dos códigos.
Por cierto. mb_detect_encoding certanly no funciona. Si, en absoluto. Por favor, eche un vistazo al código fuente mb_detect_encoding en "ext / mbstring / libmbfl / mbfl / mbfl_ident.c".
fuente
Probablemente haya intentado esto, pero ¿por qué no usar la función mb_convert_encoding? Intentará detectar automáticamente el conjunto de caracteres del texto proporcionado o puede pasarle una lista.
Además, intenté ejecutar:
y los resultados son los mismos para ambos. ¿Cómo ves que tu texto está truncado a 'novio'? ¿Está en la base de datos o en un navegador?
fuente
iconv
. Traté de hacer una forma casi pura mb_ *. Que te pareceNo hay forma de identificar el conjunto de caracteres de una cadena que es completamente precisa. Hay formas de tratar de adivinar el juego de caracteres. Una de estas formas, y probablemente / actualmente la mejor en PHP, es mb_detect_encoding (). Esto escaneará su cadena y buscará ocurrencias de cosas únicas para ciertos conjuntos de caracteres. Dependiendo de su cadena, puede que no haya tales eventos distinguibles.
Tome el juego de caracteres ISO-8859-1 vs ISO-8859-15 ( http://en.wikipedia.org/wiki/ISO/IEC_8859-15#Changes_from_ISO-8859-1 )
Solo hay un puñado de caracteres diferentes, y para empeorar, están representados por los mismos bytes. No hay forma de detectar, recibir una cadena sin saber que está codificando, ya sea que el byte 0xA4 signifique ¤ o € en su cadena, por lo que no hay forma de saber si es un juego de caracteres exacto.
(Nota: podría agregar un factor humano, o una técnica de escaneo aún más avanzada (por ejemplo, lo que sugiere Oroboros102), para tratar de averiguar en función del contexto circundante, si el personaje debe ser ¤ o €, aunque esto parece un puente Muy lejos)
Hay diferencias más distinguibles entre, por ejemplo, UTF-8 e ISO-8859-1, por lo que vale la pena intentar resolverlo cuando no estás seguro, aunque puedes y nunca debes confiar en que sea correcto.
Lectura interesante: http://kore-nordmann.de/blog/php_charset_encoding_FAQ.html#how-do-i-determine-the-charset-encoding-of-a-string
Sin embargo, hay otras formas de garantizar el juego de caracteres correcto. Con respecto a los formularios, intente aplicar UTF-8 tanto como sea posible (consulte muñeco de nieve para asegurarse de que su envío será UTF-8 en cada navegador: http://intertwingly.net/blog/2010/07/29/Rails-and -Snowmen ) Una vez hecho esto, al menos puede estar seguro de que cada texto enviado a través de sus formularios es utf_8. Con respecto a los archivos cargados, intente ejecutar el comando 'file -i' de unix a través de, por ejemplo, exec () (si es posible en su servidor) para ayudar a la detección (usando la lista de materiales del documento). En cuanto a los datos de raspado, puede leer los encabezados HTTP, que generalmente especifican el juego de caracteres. Al analizar archivos XML, vea si los metadatos XML contienen una definición de conjunto de caracteres.
En lugar de tratar de adivinar automáticamente el conjunto de caracteres, primero debe intentar asegurarse de que un cierto conjunto de caracteres usted mismo sea posible, o tratar de obtener una definición de la fuente de la que lo obtiene (si corresponde) antes de recurrir a la detección.
fuente
Hay algunas respuestas realmente buenas e intenta responder a su pregunta aquí. No soy un maestro de codificación, pero entiendo su deseo de tener una pila UTF-8 pura hasta su base de datos. He estado usando la
utf8mb4
codificación de MySQL para tablas, campos y conexiones.Mi situación se redujo a "Solo quiero que mis desinfectantes, validadores, lógica de negocios y declaraciones preparadas se ocupen de UTF-8 cuando los datos provienen de formularios HTML o enlaces de registro por correo electrónico". Entonces, de manera simple, comencé con esta idea:
$encodings = ['UTF-8', 'ISO-8859-1', 'ASCII'];
throw new RuntimeException
UTF-8
, continúe.De lo contrario, si es
ISO-8859-1
oASCII
a. Intento de conversión a UTF-8 (espera, no terminado)
si. Detectar la codificación del valor convertido.
C. Si la codificación informada y el valor convertido son ambos
UTF-8
, continúe.re. Más,
throw new RuntimeException
De mi clase abstracta
Sanitizer
Se podría argumentar que debería separar las preocupaciones de codificación de mi
Sanitizer
clase abstracta y simplemente inyectar unEncoder
objeto en una instancia secundaria concreta deSanitizer
. Sin embargo, el principal problema con mi enfoque es que, sin más conocimiento, simplemente rechazo los tipos de codificación que no quiero (y confío en las funciones PHP mb_ *). Sin más estudios, no puedo saber si eso perjudica a algunas poblaciones o no (o si estoy perdiendo información importante). Entonces, necesito aprender más. Encontré este artículo.Lo que todo programador debe saber de manera absoluta y positiva sobre las codificaciones y los conjuntos de caracteres para trabajar con texto
Además, ¿qué sucede cuando se agregan datos cifrados a mis enlaces de registro de correo electrónico (usando
OpenSSL
omcrypt
)? ¿Podría esto interferir con la decodificación? ¿Qué pasa con Windows-1252? ¿Qué pasa con las implicaciones de seguridad? El uso deutf8_decode()
yutf8_encode()
enSanitizer::isUTF8
es dudoso.La gente ha señalado fallas en las funciones PHP mb_ *. Nunca me tomé el tiempo para investigar
iconv
, pero si funciona mejor que las funciones mb_ *, avíseme.fuente
No creo que sea un problema. Una aplicación conoce la fuente de la entrada. Si es de un formulario, use la codificación UTF-8 en su caso. Eso funciona. Simplemente verifique que los datos proporcionados estén codificados correctamente (validación). Tenga en cuenta que no todas las bases de datos admiten UTF-8 en su rango completo.
Si es un archivo, no lo guardará codificado en UTF-8 en la base de datos sino en forma binaria. Cuando vuelva a generar el archivo, use también la salida binaria, entonces esto es totalmente transparente.
Su idea es buena para que un usuario pueda decir la codificación, ya que él / ella puede decirlo de todos modos después de descargar el archivo, ya que es binario.
Así que debo admitir que no veo un problema específico que plantees con tu pregunta. Pero tal vez pueda agregar más detalles sobre cuál es su problema.
fuente
Puede configurar un conjunto de métricas para tratar de adivinar qué codificación se está utilizando. Nuevamente, no es perfecto, pero podría detectar algunos de los errores de mb_detect_encoding ().
fuente
mb_detect_encoding()
fallas, ¿crees que mi respuesta tiene una posibilidad de bola de nieve en verano en el Sahara?Si está dispuesto a "llevar esto a la consola", lo recomendaría
enca
. A diferencia del más bien simplistamb_detect_encoding
, utiliza "una mezcla de análisis estadístico, análisis estadístico, adivinanzas y magia negra para determinar sus codificaciones" (risas, vea la página del manual ). Sin embargo, generalmente debe pasar el idioma del archivo de entrada si desea detectar tales codificaciones específicas del país. (Sin embargo,mb_detect_encoding
esencialmente tiene el mismo requisito, ya que la codificación debería aparecer "en el lugar correcto" en la lista de codificaciones aprobadas para que sea detectable).enca
también apareció aquí: Cómo encontrar la codificación de un archivo en Unix a través de script (s)fuente
Parece que su pregunta está bastante respondida, pero tengo un enfoque que puede simplificar su caso:
Tuve un problema similar al intentar devolver datos de cadena de mysql, incluso configurando tanto la base de datos como php para devolver cadenas formateadas a utf-8. La única forma en que obtuve el error fue en realidad devolviéndolos de la base de datos.
Finalmente, navegando por la web encontré una manera realmente fácil de manejarlo:
Dado que puede guardar todos esos tipos de datos de cadena en su mysql en diferentes formatos y colaciones, lo que solo necesita hacer es, directamente en su archivo de conexión php, establecer la colación en utf-8, así:
Lo que significa que primero guarda los datos en cualquier formato o clasificación y los convierte solo al regresar a su archivo php.
¡Espero que haya sido útil!
fuente
Si el texto se recupera de una base de datos mysql, puede intentar agregar esto después de la conexión BD.
mysqli_set_charset ($ con, "utf8");
https://www.php.net/manual/en/mysqli.set-charset.php
fuente
opciones predeterminadas de cURL:
Intenté algo como esto. Me ayudó. Si se encuentra en la información del conjunto de caracteres meta, estoy convirtiendo, de lo contrario no haré nada.
fuente