Ya sea para usar “ESTABLECER NOMBRES”

6 minutos de lectura

Ya sea para usar "ESTABLECER NOMBRES"
usuario187291

Al leer “MySQL de alto rendimiento” de O’Reilly, me topé con lo siguiente

Otra consulta basura común es SET NAMES UTF8, que es la forma incorrecta de hacer las cosas de todos modos (no cambia el conjunto de caracteres de la biblioteca del cliente; solo afecta al servidor).

Estoy un poco confundido, porque solía poner “ESTABLECER NOMBRES utf8” en la parte superior de cada secuencia de comandos para que la base de datos supiera que mis consultas están codificadas en utf8.

¿Alguien puede comentar la cita anterior o, para decirlo de manera más formal, cuáles son sus sugerencias/mejores prácticas para garantizar que el flujo de trabajo de mi base de datos sea compatible con Unicode?

Mis idiomas de destino son php y python si esto es relevante.

  • ¿Qué técnica terminaste implementando?

    – meder omuraliev

    11 de noviembre de 2009 a las 09:56

Ya sea para usar "ESTABLECER NOMBRES"
Stefan Gehrig

mysql_set_charset() sería una opción, pero una opción limitada a la ext/mysql. Para ext/mysqli está mysqli_set_charset y para PDO::mysql necesita especificar un parámetro de conexión.

Como el uso de esta función da como resultado una llamada a la API de MySQL, debe considerarse mucho más rápido que emitir una consulta.

Con respecto al rendimiento, la forma más rápida de garantizar una comunicación basada en UTF-8 entre su script y el servidor MySQL es configurar el servidor MySQL correctamente. Como SET NAMES x es equivalente a

SET character_set_client = x;
SET character_set_results = x;
SET character_set_connection = x;

mientras que SET character_set_connection = x internamente también ejecuta SET collation_connection = <<default_collation_of_character_set_x>> también puedes configurar estas variables del servidor estáticamente en su my.ini/cnf.

Tenga en cuenta los posibles problemas con otras aplicaciones que se ejecutan en la misma instancia del servidor MySQL y que requieren algún otro juego de caracteres.

  • yo mencione mysql_set_charset() – esa es una función incluida en el antiguo ext/mysql. Como se dijo anteriormente, tampoco PDO ni ext/mysqli proporcionar cualquier apoyo para esta operación directamente.

    – Stefan Gehrig

    26 ene.

  • Parece que el enlace que publiqué no es confiable. Aquí hay uno mejor: php.net/manual/en/mysqli.set-charset.php No estoy seguro de cómo quiere decir que mysqli no admite esta operación.

    – xofer

    26 ene.

  • Ah, está bien, lo siento… No me di cuenta de que hay un mysqli_set_charset función disponible. Gracias por la aclaración.

    – Stefan Gehrig

    26 ene.

Ya sea para usar "ESTABLECER NOMBRES"
cabra

TLDR

// The key is the "charset=utf8" part.
$dsn = 'mysql:host=localhost;dbname=testdb;charset=utf8';
$dbh = new PDO($dsn, 'user', 'pass');

Esta respuesta tiene un énfasis en la biblioteca pdo de php porque es muy omnipresente.

Un breve recordatorio: mysql es una arquitectura cliente-servidor. Esto es significativo porque no solo está el servidor mysql donde está la base de datos real, sino que también está el controlador de cliente mysql separado, que es lo que se comunica con el servidor mysql (son entidades separadas). Se podría decir que el cliente mysql y el pdo están mezclados.

cuando usas set names utf8, emite una consulta sql estándar a mysql. Si bien la consulta SQL pasa a través de pdo, y luego a través de la biblioteca del cliente mysql, y finalmente llega al servidor mysql, SOLO el servidor mysql analiza e interpreta esa consulta sql. Esto es importante porque el servidor mysql no envía ningún mensaje a pdo o al cliente mysql para informarle que el conjunto de caracteres y la codificación han cambiado, por lo que el cliente mysql y pdo ignoran por completo el hecho de que sucedió.

Es importante no hacer esto porque la biblioteca del cliente no puede manejar correctamente las cadenas si no conoce el juego de caracteres actual. La mayoría de las operaciones comunes funcionarán correctamente sin que el cliente conozca el conjunto de caracteres correcto, pero una que no funcionará es el escape de cadenas, como DOP::cita. Puede pensar que no necesita preocuparse por el escape manual de cadenas primitivas porque usa declaraciones preparadas, pero la verdad es que la gran mayoría de los usuarios de pdo: mysql usan sin saberlo declaraciones preparadas emuladas porque ha sido la configuración predeterminada para el controlador pdo: mysql durante mucho tiempo. Una declaración preparada emulada no utiliza declaraciones preparadas mysql nativas reales, tal como lo proporciona mysql api; en cambio, php hace el equivalente de llamar PDO::quote() en todos sus valores, y str_replaceing’ing todos sus marcadores de posición con los valores citados para usted.

Dado que no puede escapar correctamente de una cadena a menos que conozca el conjunto de caracteres que está utilizando, estas declaraciones preparadas emuladas son vulnerables a la inyección de sql si ha cambiado a ciertos conjuntos de caracteres a través de set names. Independientemente de la posibilidad de inyección de sql, aún puede romper sus cadenas si usa un esquema de escape destinado a un conjunto de caracteres diferente.

Para el controlador pdo mysql, puede especificar el conjunto de caracteres cuando se conecta, por especificándolo en el DSN. Tanto la biblioteca del cliente como el servidor conocerán el conjunto de caracteres si hace esto, por lo que las cosas funcionarán como deberían.

// The key is the "charset=utf8" part.
$dsn = 'mysql:host=localhost;dbname=testdb;charset=utf8';
$dbh = new PDO($dsn, 'user', 'pass');

Pero el escape inadecuado de cadenas no es el único problema. Por ejemplo, también puede tener problemas con el uso PDO::bindColumn porque los nombres de las columnas se especifican como cadenas, por lo que nuevamente la codificación es importante. Un ejemplo podría ser un nombre de columna llamado ütube(tenga en cuenta la diéresis), y cambia de latin a utf8 a través de nombres establecidos, y luego intentas $stmt->bindColumn('ütube', $var); con ütube siendo una cadena codificada en utf8 porque su archivo php está codificado en utf8. No funcionará, necesitarías codificar la cadena como una variante latin1… y ahora tienes todo tipo de locuras.

  • Como hoy en día (septiembre de 2014) PDO es la forma más nueva y robusta de conectar PHP con una base de datos, creo que esta respuesta es la que debe tomarse como aceptada.

    – rogeriopradoj

    13 sep.

No estoy seguro acerca de py, pero php tiene mysql_set_charset ahora, que establece que esta es la “forma preferida de cambiar el conjunto de caracteres [and] No se recomienda usar mysql_query() para ejecutar SET NAMES”. Tenga en cuenta que esta función se introdujo para MySQL 5.0.7, por lo que no funcionará con versiones anteriores.

mysql_set_charset('utf8', $link);

Donde $link es una conexión creada con mysql_connect

.

¿Ha sido útil esta solución?