Serialize vs json_encode o el array maldito

Mediante json_encode podemos grabar arrays en la base de datos sin problemas al combinarse con real_escape_string

lempika

archivado en: PHP/AJAX / 8 marzo, 2013

Me he topé anoche con un problema cuya solución creo que es interesante compartirla.

La situación es esta. En una aplicación web el usuario necesita guardar pequeñas opciones de configuración, como el color de fondo de la web o cualquier otra puñeta similar. Aunque no sea del todo correcto formalmente, una posibilidad para no crear tropecientas mil tablas, es guardar las opciones en una sola general mediante arrays.

id_opcion nombre_opcion valor_opcion
 1  estilos  array("fondo"=>"#900", "fuente" =>"1em")

Es lo que hacen la mayor parte de los gestores de contenidos, como WordPress. Así, por ejemplo, en el caso anterior podríamos guardar esto:

  • nombre_opcion = estilos;
  • valor_opcion = array("fondo"=>"#900", "fuente" =>"1em")

El problema es que no se puede guardar un array sin más en MySql. Es decir, si intentamos hacer esto:

  • $nombre_opcion = estilos;
  • $valor_opcion = array("fondo"=>"#900", "fuente" =>"1em")
  • $miConexion = new Conexion();
  • $link_id = $miConexion->conexion();
  • $resultado = $link_id->query("UPDATE opciones_generales SET valor_opcion = '$valor_opcion'
  • WHERE nombre_opcion = '$nombre_opcion' ");

Revienta por todos los lados, pues para insertar un array antes hay que serializarlo.

Serialize

Serialize() es una función que «genera una representación almacenable de un valor. Esto es útil para el almacenamiento de valores en PHP sin perder su tipo y estructura». Así, en el caso anterior, bastaría con hacer esto al enviar:

  • ...
  • $valor_opcion = array("fondo"=>"#900", "fuente" =>"1em")
  • $valor_opcion = serialize ($valor_opcion);
  • ...

Y esto al recibir

  • $valor_opcion = unserialize ($valor_opcion);

El problema viene cuando algún valor del array tiene comillas y hay que escaparlas pues vienen de un formulario, como era mi caso con un este dato:

'iframe'=><iframe width="560" height="315" src="http://www.youtube.com/embed/BQaKHGvjCYI?rel=0" frameborder="0" allowfullscreen></iframe>

El cual recibía este tratamiento más que necesario para cualquier dato que venga de fuera:

  • if ( isset($_REQUEST['canal_iframe']) ) {
    • $iframe = strip_tags($_REQUEST['canal_iframe'],'<iframe><embed>');
    • $iframe = $link_id->real_escape_string($iframe); 
  • } else {
    • header('Location: error-envio.php');
  • exit;
  • }

The problem

Un dato serializado tiene dos valores, en uno se almacena el tipo qué es (string, int...) y en otro su longitud. Por ejemplo, esto:

  • s:6:"activo"

Significa un string de 6 caracteres, que es lo que espera encontrar la función unserialize() al decodificar el dato.

Y el problema es que al codificar una cadena pasada por real_escape, PHP ¡cuenta las barras de escape!, las cuales no son retornadas cuando se recupera el dato. Así, por ejemplo, en la base de datos, el dato iframe que usaba para las pruebas estaba así:

s:135:"<iframe width="420" height="315" src="http://www.youtube.com/embed/DwYPG6vreJg?rel=0" frameborder="0" allowfullscreen></iframe>

peeeero, al contar los caracteres salían 127.

Después de darle varias vueltas al asunto, incluido el tratar de usar base64_encode y base64_decode, que no funciona, encontré una solución en abandonar el serialize y pasarme a json_encode.

json_encode

Esta función convierte un valor en una representación JSON que luego podemos decodificar mediante json_decode, pero la clave para que funcione en este caso, donde se necesita un array asociativa de vuelta, es indicar el parámetro assoc como true.

  • $arrayDatosPantalla = $mi_selector->getterConsultaSimple();
  • $arrayDatosPantalla = json_decode($arrayDatosPantalla['datosDirecto'], true);

(Tengo puesto $arrayDatosPantalla['datosDirecto'], es decir, un array, por como funciona mi clase, pero ahí iría normalmente el resultado de la consulta).

El único problema ahora eran los acentos y las eñes, que no van bien con JSON, así que nada más fácil que convertirlos a la entrada...

  • if ( isset($_REQUEST['canal_titulo']) ) {
    • $canal_titulo = strip_tags($_REQUEST['canal_titulo']);
    • $canal_titulo = $link_id->real_escape_string($canal_titulo);
    • $canal_titulo = htmlentities($canal_titulo);
  • } else {
    • header('Location: error-envio.php');
  • exit;
  • }

y desconvertirlos a la salida, que así te quitas de líos para ver qué versión de PHP hay instalada y esas cosas.

  • echo html_entity_decode($arrayDatosPantalla['titulo']);

En síntesis: si tienes que grabar arrays en la base de datos, es mejor emplear json_encode con el assoc definido como true.

|| Tags: , ,

valoración de los lectores sobre Serialize vs json_encode o el array maldito

  • estrellica valoración positiva
  • estrellica valoración positiva
  • estrellica valoración positiva
  • estrellica valoración positiva
  • estrellica valoración negativa
  • 3.7 sobre 5 (11 votos)

¿Te ha parecido útil o interesante esta entrada?
dormido, valoración 1 nadapensativo, valoración 2 un poco sonrisa, valoración 3 a medias guiño, valoración 4 bastante aplauso, valoración 5 mucho

Tú opinión es muy importante, gracias por compartirla!

Los comentarios están cerrados.