2011-04-30 10 views
16

después de configurar todas las opciones de archivo de configuración y tiempo de ejecución para el conjunto de caracteres que puedo encontrar en utf-8, las nuevas conexiones mysqli hechas con php todavía tienen su conjunto de caracteres en latin1, lo que significa que tengo que llamar al $mysqli->set_charset('utf8') cada vez que me conecto.una forma permanente de hacer mysqli-> set_charset()?

$mysqli = new mysqli(DB_HOST, DB_USER, DB_PASS, DB_NAME); 
if ($mysqli->connect_error) 
    err_handle("mysql connect error({$mysqli->connect_errno})."); 
if (!$mysqli->set_charset("utf8")) 
    err_handle("db error({$mysqli->errno})."); 

¿Me pregunto si hay una manera permanente de hacer esto?

se encontró un problema similar en this post.


un "show variables like 'character_set%'" consulta en el servidor MySQL antes de llamar $mysqli->set_charset('utf8') espectáculos:
(esta parte fue ambiguo en revoluciones anteriores)

character_set_client latin1 
character_set_connection latin1 
character_set_database utf8 
character_set_filesystem binary 
character_set_results latin1 
character_set_server utf8 
character_set_system utf8 

el cliente, la conexión y los resultados de juego de caracteres sólo se puede cambiar a utf8 con $mysqli->set_charset('utf8') en tiempo de ejecución. después de que se muestra:

character_set_client utf8 
character_set_connection utf8 
character_set_database utf8 
character_set_filesystem binary 
character_set_results utf8 
character_set_server utf8 
character_set_system utf8 

tengo

default_charset = "utf-8" 

conjunto en php.ini, y

[client] 
default-character-set=utf8 
... 
[mysqld] 
## This option is deprecated in favor of --character-set-server. 
#default-character-set=utf8 

conjunto en my.cnf.

el juego de caracteres predeterminado para mis tablas también es utf8.

parece que las opciones "[cliente]" solo afectan a la herramienta cmd "mysql" y no tienen nada que ver con php.

el valor de retorno de $mysqli->character_set_name() es siempre latin1 no importa lo que hago, hasta $mysqli->set_charset('utf8') se llama.

supongo que "latin1" es una cosa de mysql, ya que no puedo recordar nada más que por defecto es "latin1" en mi sistema.

^actualización: de acuerdo al manual de MySQL 9.1.4, 9.1.5 y 5.1.3, character_set_client debe ser proporcionada por el cliente. Supongo que php no lo proporciona en la conexión y mysql utiliza el juego de caracteres alternativo latin1.

estoy ejecutando php 5.3 en debian wheezy con mysql 5.1.

¿Alguna sugerencia?


actualizado con información de:

i olvidó mencionar la Directiva skip-character-set-client-handshake y por qué yo era reacio a utilizarlo.

a primera vista pensé ignorando el apretón de manos podría dar lugar a la situación de que el cliente habla latin1 mientras que las conversaciones servidor UTF-8.¿Cómo convierte el servidor la cadena del juego de caracteres character_set_client al character_set_server sin conocer el juego de caracteres actualmente en uso?

corrígeme si me equivoco, por favor. Voy a experimentar con esta configuración más tarde para ver si funciona.

actualiza con workaroud:

asegurarse de que todo funciona bajo UTF-8 (o cualquier juego de caracteres preferible). luego agregue la línea skip-character-set-client-handshake al my.cnf.

esto funciona para mí hasta ahora. Experimenté con algunos caracteres de doble ancho utf-8. ambos insert y select tuvieron éxito y se muestran correctamente en el navegador.

qué significa omitir el saludo de manos aún no está claro. y el servidor mysql ahora se vuelve incapaz de usar cualquier conjunto de caracteres excepto utf-8, lo que hace que esta solución no sea práctica ya que simplemente no puedo aplicar esta configuración a todos los servidores en los que se ejecuta mi sitio web.

así que no estoy adoptando esta solución. otros comentarios y respuestas son muy apreciados.

+0

¿Ha intentado cambiar la configuración regional del sistema con 'setlocale()'? – Narf

+0

@Narf las configuraciones regionales que están disponibles para php (salida de 'locale -a') en mi sistema son C, POSIX y en_US.utf8. además, 'setlocale()' no puede ser una solución permanente ya que _ "la información de la configuración regional se mantiene por proceso" _, según el manual php. –

+0

en_US.utf8 sería el correcto si esto debería funcionar. Es lógico que el conjunto de caracteres predeterminado para cada programa se establezca como la configuración regional actual del sistema, a menos que se configure de otra manera. Si ejecuta PHP como un módulo de Apache, podría establecerse la configuración regional como una directiva apache o incluso podría establecer que la configuración regional predeterminada del sistema sea en_US.utf8. De todos modos ... es solo un pensamiento en caso de que nada más funcione. – Narf

Respuesta

18

Ha diagnosticado correctamente el problema básico: Si bien puede cambiar el juego de caracteres predeterminado del cliente MySQL en my.cnf o .my.cnf de la máquina cliente, PHP no utiliza estos archivos.

Si se piensa en cómo funcionan las extensiones MySQLi/MySQL de PHP, esto tendrá sentido - no tienen nada que ver con el programa mysql cliente y no se van a rastrear su sistema de archivos para los archivos de configuración, ya que utilizan directamente libmysql .

Para cambiar el juego de caracteres predeterminado de libmysql, solo tendrá que volver a generar libmysql. Puede que esa no sea la respuesta que prefieras (ya que estás utilizando binarios MySQL precompilados), pero es la respuesta real. Los valores predeterminados se establecen en tiempo de compilación, y luego pueden anularse en tiempo de ejecución.

Si no quieres hacer esto y llamar a set_charset() te molesta, mi sugerencia sería simplemente extender la clase MySQLi y usar esa clase en lugar de mysqli. es decir:

class MyDB extends mysqli { 
    // (You could set defaults for the params here if you want 
    // i.e. $host = 'myserver', $dbname = 'myappsdb' etc.) 
    public function __construct($host = NULL, $username = NULL, $dbname = NULL, $port = NULL, $socket = NULL) { 
    parent::__construct($host, $username, $dbname, $port, $socket); 
    $this->set_charset("utf8"); 
    } 
} 

típicamente en una aplicación que va a tener algún tipo de capa de abstracción de base de datos de todos modos, por lo que puede tener este uso MyDB capa en lugar de mysqli, o puede hacer que esta capa sea MyDB y añadir o anula los métodos que desee (lo he hecho con aplicaciones simples sin ORM).

Es una buena práctica tener siempre algún tipo de capa de abstracción de base de datos, incluso si comienza solo como class MyDB extends mysqli {} porque entonces nunca tendrá que buscar/reemplazar toda su base de código para hacer pequeños cambios.

RE: su solución, como se explica, este hardcodes esencialmente toda su servidor db a UTF-8 independientemente de lo que solicitan los clientes. En lugar de tener múltiples bases de datos, cada una con su propio juego de caracteres, el servidor solo funciona con UTF-8 y puede destruir datos en silencio si los clientes se conectan con otro juego de caracteres. Esto es fundamentalmente incorrecto porque efectivamente ha trasladado un aspecto de la configuración de la aplicación (juego de caracteres de la base de datos) desde la aplicación/máquina cliente al servidor de la base de datos donde realmente no pertenece.

Si se piensa en las capas de la pila de aplicaciones,

[server] <=> [network] <=> [client libmysql] <=> [PHP binary] <=> [app] 

entonces entenderá que la "correcta" lugar para una configuración de la aplicación específica de este tipo es en la propia aplicación, no en la pila a otra parte . Puede que no te guste tener que especificar el juego de caracteres de tu base de datos en PHP, pero si lo piensas, ahí es donde pertenece, porque es también donde estás especificando la base de datos a la que te quieres conectar, es un parámetro de conexión, no es un problema de configuración del servidor. La codificación del juego de caracteres en cualquier otro lugar hace que su aplicación no sea portátil.

+0

+1 para la capa de abstracción. No usé la solución alternativa de todos modos. –

2

de acuerdo a los siguientes puestos de MySQL

http://dev.mysql.com/doc/refman/5.0/en/charset-connection.html http://dev.mysql.com/doc/refman/5.0/en/charset-applications.html

sus ajustes no tienen toda la razón es decir

uso

[mysqld] 
character-set-server=utf8 
collation-server=utf8_general_ci 

en lugar de

[mysqld] 
default-character-set=utf8 

para el cliente que sólo se encuentra

[mysql] 
default-character-set=utf8 

no

[client] 
default-character-set=utf8 

oportunidad y dame un poco de retroalimentación.

Recuerdo que una vez leí sobre una configuración var para desactivar la capacidad de un cliente para cambiar la configuración del carácter. Pero no puedo encontrar el ref en la documentación de mysql ahora. Si lo encuentro, te lo hago saber.

Espero que ayude.

Saludos

ACTUALIZACIÓN

@Unisland Por cierto he encontrado este hilo http://www.webmasterworld.com/php/3553642.htm donde un problema similar se discute

intente cualquiera

Por lo que puede tratar de añadir un:
[mysqld]
init-connect = 'nombres de los conjuntos utf8'

o

[cliente] set-default-character
= UTF-8

[mysqld]
conjunto de caracteres-servidor = utf8
default-character-set = UTF-8
default-colación = utf8_unicode_ci
del juego de caracteres UTF-8-cliente =

para establecer esto como un defecto para todas las conexiones, o empezar con estas consultas después de su secuencia de comandos específicos se conecta a la base de datos antes de enviar otra consulta: ajustar nombres UTF-8; SET CHARACTER_SET utf8;

+0

tengo la línea 'juego de caracteres-server' realidad, el 'show salida de la consulta variables' adjunta demuestra que está funcionando. –

+0

creo que las instrucciones '[mysql]' solo afectan a la herramienta cmd 'mysql'. Corrígeme si estoy equivocado. Sé que puedo ignorar la información del charset del cliente con 'skip-character-set-client-handshake', pero soy un poco reacio a hacer eso. ¿No significa que ignorando el efecto negativo la situación podría llegar a ser que el cliente hable _latin1_ mientras el servidor lee _utf8_? –

+0

@Unilsland pruébalo. ¿Qué tienes que perder? El problema es que si mysql detecta una línea incorrecta en my.cnf, realmente no sabes cómo trata el resto de la configuración. Me sucedió una vez que tenía una configuración incorrecta en una línea y resultó en un comportamiento extraño –

Cuestiones relacionadas