utf8 - PHP: convierte cualquier cadena en UTF-8 sin conocer el conjunto de caracteres original, o al menos prueba
utf8 php (10)
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 (usarlo solo es útil si el usuario realmente envió el formulario), o podría ser desde un archivo de texto cargado, así que realmente no tengo control sobre la entrada.
No creo que sea un problema Una aplicación conoce la fuente de la entrada. Si proviene 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 se trata de un archivo, no lo guardará UTF-8 codificado en la base de datos, sino en forma binaria. Cuando vuelva a generar el archivo, use también salida binaria, entonces esto es totalmente transparente.
Su idea es agradable que un usuario pueda contar la codificación, ya sea que pueda decirlo de todos modos después de descargar el archivo, ya que es binario.
Debo admitir que no veo un problema específico que plantees con tu pregunta. Pero tal vez puedas agregar más detalles sobre tu problema.
Tengo una aplicación que trata con clientes de todo el mundo, y, naturalmente, quiero que todo lo que va a mis bases de datos tenga codificación 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 (usando <form accept-charset="utf-8">
solo es útil si el usuario realmente envió 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 asegure que todo lo que ingresa en mi base de datos es, en la medida de lo posible, codificado en UTF-8. Intenté con iconv(mb_detect_encoding($text), "UTF-8", $text);
pero eso tiene problemas (si la entrada es ''prometida'', devuelve ''fianc''). He intentado muchas cosas = /
Para las cargas de archivos, me gusta la idea de pedirle al usuario final que especifique la codificación que usa, y mostrarles vistas previas de cómo se verá la salida, pero esto no ayuda contra los hackers desagradables (de hecho, podría hacer que sus vidas un poco más fácil).
He leído las otras preguntas sobre el tema, pero parecen tener diferencias sutiles como "Necesito analizar fuentes RSS" o "Borro datos de sitios web" (o, de hecho, "No puedes").
¡Pero debe haber algo que al menos tenga un buen intento !
En la patria Rusia tenemos 4 codificaciones populares, por lo que su pregunta tiene una gran demanda aquí.
Solo mediante códigos de símbolos de caracteres no puede detectar la codificación, ya que 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. Entonces, no queremos responder la pregunta "¿qué es la codificación de este texto?", Estamos tratando de entender " ¿qué es lo más probable de la codificación de este texto? ".
Un tipo aquí en el popular blog de tecnología ruso inventó este enfoque:
Construya el rango de probabilidad de códigos de char en cada codificación que quiera soportar. Puedes construirlo usando algunos textos grandes en tu idioma (por ejemplo, algunos de ficción, usa Shakespeare para inglés y Tolstoy para ruso, jaja). Conseguirás algo así:
encoding_1:
190 => 0.095249209893009,
222 => 0.095249209893009,
...
encoding_2:
239 => 0.095249209893009,
207 => 0.095249209893009,
...
encoding_N:
charcode => probabilty
Siguiente. Tomas texto en una codificación desconocida y para cada codificación en tu "diccionario de probabilidad" buscas la frecuencia de cada símbolo en texto codificado desconocido. Sumas de probabilidades de símbolos. La codificación con mayor calificación es probable que el ganador. Mejores resultados para textos más grandes.
Si estás interesado , te puedo ayudar con gusto en esta tarea. Podemos aumentar la precisión aumentando la lista de probabilidades de dos caracteres.
Por cierto. mb_detect_encoding certanly no funciona. Sí, en absoluto. Por favor, eche un vistazo al código fuente mb_detect_encoding en "ext / mbstring / libmbfl / mbfl / mbfl_ident.c".
Hay algunas respuestas realmente buenas e intenta responder 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 codificación utf8mb4
de MySQL para tablas, campos y conexiones.
Mi situación se redujo a "Solo quiero que mis desinfectantes, validadores, lógica comercial y declaraciones preparadas se ocupen de UTF-8 cuando los datos provienen de formularios HTML o enlaces de registro por correo electrónico". Entonces, en mi manera simple, comencé con esta idea:
- Intento de detectar la codificación:
$encodings = [''UTF-8'', ''ISO-8859-1'', ''ASCII''];
- Si la codificación no se puede detectar,
throw new RuntimeException
- Si la entrada es
UTF-8
, continúe. De lo contrario, si es
ISO-8859-1
oASCII
a. Intento de conversión a UTF-8 (espera, no terminado)
segundo. Detecta la codificación del valor convertido
do. Si la codificación informada y el valor convertido son ambos
UTF-8
, continúe.re. De lo contrario,
throw new RuntimeException
De mi clase abstracta Sanitizer
private function isUTF8($encoding, $value)
{
return (($encoding === ''UTF-8'') && (utf8_encode(utf8_decode($value)) === $value));
}
private function utf8tify(&$value)
{
$encodings = [''UTF-8'', ''ISO-8859-1'', ''ASCII''];
mb_internal_encoding(''UTF-8'');
mb_substitute_character(0xfffd); //REPLACEMENT CHARACTER
mb_detect_order($encodings);
$stringEncoding = mb_detect_encoding($value, $encodings, true);
if (!$stringEncoding) {
$value = null;
throw new /RuntimeException("Unable to identify character encoding in sanitizer.");
}
if ($this->isUTF8($stringEncoding, $value)) {
return;
} else {
$value = mb_convert_encoding($value, ''UTF-8'', $stringEncoding);
$stringEncoding = mb_detect_encoding($value, $encodings, true);
if ($this->isUTF8($stringEncoding, $value)) {
return;
} else {
$value = null;
throw new /RuntimeException("Unable to convert character encoding from ISO-8859-1, or ASCII, to UTF-8 in Sanitizer.");
}
}
return;
}
Se podría argumentar que debería separar los problemas de codificación de mi clase abstracta Sanitizer
y simplemente inyectar un objeto Encoder
en una instancia hija concreta de Sanitizer
. 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 estoy confiando en las funciones PHP mb_ *). Sin más estudios, no puedo saber si eso perjudica a algunas poblaciones o no (o si pierdo información importante). Entonces, necesito aprender más. Encontré este artículo.
Además, ¿qué sucede cuando los datos cifrados se agregan a mis enlaces de registro de correo electrónico (usando OpenSSL
o mcrypt
)? ¿Podría esto interferir con la decodificación? ¿Qué hay de Windows-1252? ¿Y las implicaciones de seguridad? El uso de utf8_decode()
y utf8_encode()
en Sanitizer::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_ *, házmelo saber.
Lo que estás pidiendo es extremadamente difícil. Si es posible, lograr que el usuario especifique la codificación es lo mejor. Evitar 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:
iconv(mb_detect_encoding($text, mb_detect_order(), true), "UTF-8", $text);
Establecerlo en estricto podría ayudarlo a obtener un mejor resultado.
No hay forma de identificar el juego de caracteres de una cadena que sea completamente precisa. Hay formas de intentar 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 ocurrencias 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 personajes diferentes, y para empeorar, están representados por los mismos bytes. No hay forma de detectar, recibir una cadena sin saber su codificación, si se supone que el byte 0xA4 significa ¤ o € en su cadena, por lo que no hay forma de saber cuál es el juego de caracteres exacto.
(Nota: puede agregar un factor humano, o una técnica de escaneo aún más avanzada (por ejemplo, lo que Oroboros102 sugiere), para tratar de averiguar en función del contexto circundante, si el personaje debe ser ¤ o €, aunque esto parece un puente Muy lejos)
Hay más diferencias distinguibles entre, por ejemplo, UTF-8 e ISO-8859-1, por lo que vale la pena tratar de averiguarlo 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, existen otras formas de garantizar el juego de caracteres correcto. En cuanto a los formularios, trate de aplicar UTF-8 tanto como sea posible (revise el 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 ). http://intertwingly.net/blog/2010/07/29/Rails-and-Snowmen esto, al menos puedes estar seguro de que cada texto enviado a través de tus formularios es utf_8. Con respecto a los archivos cargados, intente ejecutar el comando ''archivar -i'' de unix a través de, por ejemplo, exec () (si es posible en su servidor) para ayudar a la detección (utilizando la lista de materiales del documento.) En cuanto a raspar datos, podría leer los encabezados HTTP. que generalmente especifica 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ágicamente el juego de caracteres, primero debes tratar de asegurarte de un cierto conjunto de caracteres cuando sea posible, o intentar obtener una definición de la fuente de la que la recibes (si corresponde) antes de recurrir a la detección.
Parece que su pregunta está respondida, pero tengo un enfoque que puede simplificar su caso:
Tuve un problema similar al tratar de devolver datos de cadena de mysql, incluso configurando tanto la base de datos como php para devolver cadenas formateadas para utf-8. La única forma en que obtuve el error fue devolviéndolos de la base de datos.
Finalmente, navegando a través de la web encontré una forma 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 único que necesita hacer es, directamente en su archivo de conexión php, establecer la intercalación a utf-8, como esta:
$connection = new mysqli($server, $user, $pass, $db);
$connection->set_charset("utf8");
Lo que significa que primero guarda los datos en cualquier formato o intercalación y lo convierte solo a la vuelta de su archivo php.
Espero que haya sido útil!
Probablemente haya intentado esto, pero ¿por qué no simplemente 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, traté de ejecutar:
$text = "fiancée";
echo mb_convert_encoding($text, "UTF-8");
echo "<br/><br/>";
echo iconv(mb_detect_encoding($text), "UTF-8", $text);
y los resultados son los mismos para ambos. ¿Cómo ves que tu texto se trunca a ''fianc''? ¿está en la base de datos o en un navegador?
Puede configurar un conjunto de métricas para tratar de adivinar qué codificación se está utilizando. De nuevo, no es perfecto, pero podría detectar algunas de las fallas de mb_detect_encoding ().
Si estás dispuesto a "llevar esto a la consola", te recomendaría enca
. A diferencia de la mb_detect_encoding
, bastante simplista, usa "una mezcla de análisis sintáctico, análisis estadístico, adivinanzas y magia negra para determinar sus codificaciones" (lol - ver página de manual ). Sin embargo, generalmente debe pasar el idioma del archivo de entrada si desea detectar codificaciones específicas de cada país. (Sin embargo, mb_detect_encoding
tiene esencialmente el mismo requisito, ya que la codificación debería aparecer "en el lugar correcto" en la lista de codificaciones pasadas 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)
public function convertToUtf8($text) {
if(!$this->html)
$this->html = cURL(''http://''.$this->url, array(''timeout'' => 15));
$html = $this->html;
preg_match(''/<meta.*?charset=(|/")(.*?)("|/")/i'', $html, $matches);
$charset = $matches[2];
if($charset)
return mb_convert_encoding($text, ''UTF-8'', $charset);
else
return $text;
}
opciones predeterminadas de cURL:
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
Intenté algo como esto. Me ayudó. Si se encuentra en la información meta charset, estoy convirtiendo, de lo contrario no hago nada.