2012-02-02 19 views
8

Tengo un gran objeto php que quiero serializar y almacenar en una base de datos MySql. La codificación de la tabla es UTF-8 y la columna para contener la codificación del objeto serializado también es UTF-8.Almacenar un objeto serializado en la base de datos MySql

El problema es que el objeto contiene una cadena de texto que contiene caracteres franceses.

Por ejemplo:

Merci d'avoir passé commande avec Lovre. Voici le récapitulatif de votre commande 

Cuando serializar el objeto a continuación unserialize de nuevo directamente la cadena se mantiene y está en formato correcto.

Sin embargo, cuando guardo el objeto serializado en una base de datos MySQL y luego recuperarlo de nuevo a continuación unserialize que la cadena se convierte de esta manera:

Merci d'avoir passé commande avec Lovre. Voici le récapitulatif de votre commande 

Algo va mal cuando se almaceno el objeto en la base de datos.

Notas:

  • El objeto se almacena utilizando propulsar ORM.
  • El tipo de columna es text.
  • La cadena se almacena y se lee desde un archivo html.
+0

¿Cuál es la codificación de su archivo? – alexn

+0

Puedes intentar codificarlo en base_64, pero no deberías tener que hacer eso. ¿Qué tipo es la columna de la base de datos? ¿Ha comprobado la configuración de conexión de la base de datos en php? –

+0

@TheSilencer el tipo de columna de base de datos es texto. La conexión a la base de datos se realiza utilizando PROPEL. – Songo

Respuesta

10

Las cadenas creadas por serialize son cadenas binarias, no tienen una codificación de juego de caracteres específica, sino que son simplemente una "matriz" de bytes (donde -como un byte es de 8 bits, un octeto).

Si ahora toma una cadena y le dice a su base de datos que está codificada en LATIN-1 y su base de datos la almacena en un campo de texto con codificación UTF-8, la base de datos cambiará la codificación de LATIN-1 a UTF-8. UTF-8 es una codificación de conjunto de caracteres que utiliza más de un byte por carácter para algunos caracteres, por ejemplo, los que usted da en su pregunta como é.

El carácter é se almacena entonces como é dentro de la base de datos, que es la secuencia de bytes UTF-8 para é.

Si ahora busca los datos de la base de datos sin especificar en qué codificación los necesita, la base de datos lo devolverá como UTF-8.

Ahora unserialize tiene un problema porque la cadena binaria ha sido modificada de forma que no es válida.

En su lugar, debe decirle a su base de datos que no debe modificar la codificación cuando almacena la cadena serializada, p. al elegir el tipo de columna y la codificación correctas (campo binario, BLOB - Binary Large Object­MySQL Docs, consulte también Binary Types­Propel Docs) -o- cuando recupera los datos de la base de datos, revierte la codificación de juego de caracteres al formato original. El primer enfoque (campo binario) es mejor porque es exactamente lo que estás buscando.

Para los datos que ya han sido almacenados en la base de datos en un formato incorrecto, debe corregir los datos. Para hacerlo, primero debe averiguar qué codificación se ha aplicado, p. Ej. de qué conjunto de caracteres a qué juego de caracteres. Supongo que es LATIN-1 pero no hay garantía. Debe averiguar la codificación de los datos y procesos de su aplicación actual para averiguarlo.

Después de que se haya enterado, codifique los valores de nuevo desde UTF-8 a la codificación original.

+0

Intenté lo que dijiste y convertí el tipo de columna a BLOB, pero el problema persistía.Sin embargo, decidí 'utf_decode' el mensaje en sí después de recuperar el objeto de la base de datos y eso resolvió el problema. – Songo

+0

¿Persiste para datos existentes y/o para datos nuevos? Además, no soy especialista en propulsión, pero estoy bastante seguro de que debe haber una solución directa con la capa de la base de datos, por lo que no es necesario preocuparse por la codificación dentro del código de la lógica de la aplicación. Si no puede resolverlo en la capa de la base de datos, también existe la interfaz ['Serializable'] (http://php.net/Serializable) en PHP que puede ser útil para mantener su código limpio. – hakre

+0

No tengo datos existentes ya que todavía estoy en la fase de desarrollo. Comprobé la configuración de PROPEL y usa UTF-8 en su conexión. Tal vez hay algo que me perdí, pero veré la interfaz Serializable que mencionaste. Gracias por tu ayuda. – Songo

4

asegúrese de usar utf-8 en todas partes - suena como que se ha perdido algo.

En su caso, creo que olvidó establecer el juego de caracteres correcto para su conexión a la base de datos (usando una declaración SET NAMES o) - pero eso es difícil de decir sin ver su código (y no sé propulsar)

la siguiente es una cita de chazomaticus, que ha dado una respuesta perfecta en UTF-8 all the way through, listando todos los puntos que hay que tener cuidado de:

almacenamiento:

  • Especificar utf8_unicode_ci (o equivalente) colación en todas las tablas y columnas de texto en su base de datos. Esto hace que MySQL físicamente almacene y recuperen valores de forma nativa en UTF-8.

Recuperación:

  • En PHP, en cualquier envoltorio DB que uso, tendrá que configurar el juego de caracteres UTF-8 para la conexión . De esta manera, MySQL hace sin conversión desde su UTF-8 nativo cuando entrega los datos a PHP. * Tenga en cuenta que si usted no utiliza una base de datos envoltura, que probablemente tendrá que ejecutar una consulta a decir a MySQL para darle resultados en UTF-8: SET NAMES 'utf8' (tan pronto como se conecta).

entrega:

  • Tienes que decirle a PHP para entregar las cabeceras adecuadas para el cliente, por lo texto se interpreta como UTF-8. En PHP, puede utilizar la opción php.ini default_charset , o manualmente emitir la cabecera Content-Type a sí mismo, que es sólo más trabajo, pero tiene el mismo efecto .

de presentación:

  • ¿Quieres tener todos los datos enviados por los navegadores estar en UTF-8. Desafortunadamente, la única manera de hacer esto es agregar el atributo accept-charset a todas sus etiquetas <form>: <form ... accept-charset="UTF-8">.
  • Nota que la especificación W3C HTML dice que clientes "debería" por defecto para enviar formas de vuelta al servidor en cualquier charset el servidor servido, pero esto es al parecer sólo una recomendación, ahí la necesidad de ser explícito en cada una de las etiquetas <form>.
  • Aunque, en ese frente, todavía va a desea verificar cada cadena enviada como UTF-8 válida antes de intentar almacenarla o utilizarla en cualquier lugar. El de PHP mb_check_encoding() hace el truco, pero tienes que usarlo religiosamente.

de procesamiento:

  • Esto es, por desgracia, la parte difícil. Debe asegurarse de que cada vez que procese una cadena UTF-8, lo haga de manera segura. La forma más fácil de hacer es haciendo un uso extensivo de la extensión de PHP mbstring.
  • PHP operaciones de cadena NO son por defecto seguro UTF-8. Hay algunas cosas que pueden hacer con seguridad con las operaciones normales de cadena PHP (como la concatenación), pero para la mayoría de las cosas debe usar la función equivalente mbstring.
  • Para saben lo que está haciendo (es decir: no se metan arriba), que realmente necesita saber UTF-8 y cómo funciona en la nivel más bajo posible. Revise cualquiera de los enlaces de utf8.com para algunos buenos recursos para aprender todo lo que necesita para saber.
  • Además, me siento así debe decirse en algún lugar, a pesar de que pueda parecer obvio: cada PHP o HTML archivo se le sirve deben codificados en UTF-8 válidos.

nota de que no es necesario utilizar UTF-8 - la parte importante es usar el mismo juego de caracteres todas partes, independiente de lo que podría ser charset. pero si necesita cambiar las cosas de todos modos, use utf-8.

1

Siempre estoy almacenando datos esrializados usando base64_encode(). Los datos serializados a veces causan problemas, pero después de usar el valor base64 de este, solo quedan caracteres simples.

1

Le recomiendo que use json_encode en lugar de serializar. Algún día se encontrará tratando de usar esa información desde otro lugar que no sea PHP y tenerla almacenada en JSON la hace legible en todas partes; prácticamente todos los idiomas admiten la decodificación de JSON y es un estándar bien establecido.

¡La respuesta sobre el uso de utf8 en todas partes es válida! :-D

+0

No es una buena idea: 1. convierte matrices en objetos, 2. tipo de clase y métodos se pierden –

+0

Los métodos se pierden de todos modos ... no los guardas con la llamada 'serialize' Créeme, es una idea mucho peor para almacenar cosas serializadas .. eventualmente necesitarás leer esas cosas de otro lado. si necesita deserializar de nuevo a una clase simplemente almacene el tipo como cadena y luego cambie para crear la clase correcta con los datos json como campos versus devolver el json simple, como cualquier ORM básicamente para registros DB. –

Cuestiones relacionadas