8 sept 2012

Tratamiento de select multiple y paso de arrays por $_POST

Mediante un formulario podemos enviar información a un script para que la procese. Habitualmente esta información es la que proviene directamente de los mismos campos del formulario.
Cuando el usuario introduce la información cada elemento del formulario se procesa, creando una variable con el atributo 'name' con el valor indicado en el atributo 'value'.
El problema surge cuando nos vemos con la necesidad de enviar datos algo más complejos que un simple valor, como por ejemplo un conjunto de valores en una variable, como un array o información más estructurada.
Tomemos un ejemplo sencillo. Un usuario puede acceder desde una web múltiples productos de una oferta. Esta selección se procesará. Si cumple una serie de condiciones se pasará otro formulario de confirmación para posteriormente aplicar descuentos, y si no de vuelta al principio.
Este sería el punto de entrada:
<form name="pedido" method="post" action="procesar.php">
<label for="tfno"> Tfno </label>
<input name="tfno" type="text"></input>
<label for="ofertas[]">Ofertas</label>
<select name="ofertas[]" multiple>
    <option value="100">Pizza</value>
    <option value="101">Bocata</value>
    <option value="102">Ensalada</value>
    <option value="103">Kebab</value>
    <option value="110">Refresco</value>
   //... más opciones
</select>
<input type="submit" value="Procesar"></input>
</form>
Se puede comprobar que  el name del select se ha definido como ofertas[], con corchetes. Si la variable la pasamos por GET en la URL veríamos una sucesión de parámetros con el mismo nombre, uno por cada selección y podríamos procesar esta cadena. Pero al ser por POST sólo obtendremos el último valor de todos los seleccionados.
De esta forma lo que obtenemos será un array que procesará en este caso el script 'procesar.php'
$ofertas=$_POST['ofertas'];
//...
 foreach ($ofertas as $oferta) {
       $importe_total += precio($oferta);
//...tratamiento de cada código de producto
}
Este script hará una serie de cálculos sobre el array recibido, por ejemplo una validación. Una vez hecha, supongamos que se requiere de otro formulario más para que el usuario haga una serie de confirmaciones o aporte más datos.
Por ejemplo, se ha verificado que el pedido es correcto, que la selección se ajusta a las condiciones de la oferta y ahora se quiere aplicar un descuento sobre el mismo, visualizándose en un ticket como documento final. Tendremos que pasar el array $ofertas de alguna manera como parámetro al siguiente formulario. Lo haremos de la siguiente manera:
'<input type="hidden" name="ofertas" value="'
       .base64_encode(serialize($ofertas))
       .'" />';           
Es decir, podemos pasar un array serializándolo. Se puede observar que el paso de parámetros se hace en un input oculto, una forma muy habitual de pasar información entre formularios.
Si no usamos la codificación base64 podemos encontrarnos con un error similar al siguiente.
       Error at offset 9 of 13 bytes
La codificación base64 nos garantiza que la información no se verá afectada por los protocolos de transporte.
De forma análoga, estos datos enviados serializados y codificados al recibirse podrán ser usados tras descodificarse y deserializarse. Por ejemplo, en facturar.php recibiriamos los datos de procesar.php para determinar según los productos que descuento aplicar, cual sale gratis, que regalo dar, o lo que fuere oportuno.
$ofertas=unserialize(base64_decode($_POST['ofertas']));
foreach ($ofertas as $oferta) {
     //... tratamiento de cada producto
}

De esta forma, a modo de resumen:
  • para recoger variables multivaluadas en un select usar [] en la variable
  • para enviar como parámetro POST un array, serializar y codificar en base64
    (base64_encode(serialize($array))