Muchos programadores, entre los cuales me incluyo tenemos siempre la tendencia a reinventar el agua azucarada cuando decidimos crear un carrito de compras, un blog o un foro a partir de la nada. Eso no significa que estemos en contra de las herramientas gratuitas que abundan en Internet que sirven para esos mismos propósitos y que con toda seguridad funcionan mucho mejor. Lo que sucede, es que como desarrolladores, queremos aprender el funcionamiento y cada uno de los secretos de tales elementos, para tener la satisfacción de poder decir “yo puedo hacerlo”.
Pues bien, resulta que un problema común que a mi me ocurrió en mis comienzos y que sigue atrapando a más de algún desprevenido, es la duplicación de datos cuando luego de haberlos almacenado en la base de datos, presionamos la tecla F5 o el botón que actualiza o “refresca” la página. Un problema frustrante si trata de atacarse por el lado aparentemente más fácil, pero a su vez incorrecto. Veamos un caso típico.
Juan Pérez, está tratando de hacer su propio foro (que bien puede ser un sistema de comentarios o algo similar), y según su buen criterio, la página debe constar de un área para los comentarios publicados y un formulario (ubicado en “foro.php”) para que los usuarios que deseen opinar, escriban el suyo. Hasta el momento todo bien, pero entonces la lógica le indica que el formulario debería enviar la información al mismo documento foro.php para que luego de guardar el comentario, muestre todos los que hay almacenados. Por lo tanto escribe:
<form action="foro.php" method="POST">
Al momento de hacer algunas pruebas, comprueba con agrado que en realidad la idea funciona, pero al hacerle la demostración a un amigo, presiona la tecla F5 para volver a cargar su documento y descubre con desagrado que el último comentario aparece dos veces. Entonces decide hacer otra prueba, y hace clic sobre el botón “actualizar” del navegador y entonces el infame comentario se repite por tercera vez. Al revisar su tabla en MySQL, Juan Pérez confirma que en efecto el dato se almacenó tres veces. Obviamente cada vez que actualiza, se reenvían los datos. ¿Cómo evitarlo?
Sabemos que los datos se envían por el método POST del formulario, y por lo tanto deben recibirse por medio de la variable $_POST de PHP. Vaciar su contenido por medio de unset($_POST); no sirve de nada pues acá solo recibe la información que manda el navegador, y es este último quien tiene guardada la información y no hay forma de limpiarla. Lo correcto entonces es recurrir a una práctica que nos evitará éste y muchos otros problemas, que es la de usar un script auxiliar (save.php) para que sea éste el encargado de hacer la inserción de datos. Una vez que ha terminado, redirige a la página que el usuario puede ver (foro.php) y al mismo tiempo “limpia” la información del navegador, porque hace un llamado a la página del foro sin haberle enviado los datos. El encabezado del formulario quedará de la siguiente manera:
<form action="save.php" method="POST">
Mientras que el docuemnto save.php, al terminar su trabajo incluirá la instrucción:
header('Location: foro.php'); // que hace la redirección.
Explico esto un poco más despacio:
Procedimiento incorrecto:
- El navegador (con la memoria limpia) llama al documento foro.php
- foro.php no recibe información, y muestra solo los comentarios viejos
- El usuario escribe su comentario en foro.php y pulsa el botón “Enviar”
- El navegador almacena en memoria el POST (datos del formulario) y lo envía a foro.php
- foro.php recibe el POST, lo almacena y muestra los comentarios anteriores, pero también el que el usuario acaba de escribir
- El usuario presiona la tecla F5 o el botón “actualizar” del navegador
- El navegador que aún tiene en memoria el POST, lo reenvía a foro.php
- foro.php recibe el comentario (que ya almacenó) y lo vuelve a guardar, provocando la repetición de datos
Procedimiento correcto:
- El navegador (con la memoria limpia) llama al documento foro.php
- foro.php no recibe información, y muestra solo los comentarios viejos
- El usuario escribe su comentario en foro.php y pulsa el botón “Enviar”
- El navegador almacena en memoria el POST y lo envía a save.php (he aquí la diferencia)
- save.php recibe el POST y lo almacena en la base de datos
- save.php hace un llamado a foro.php sin enviar nada por POST (importantísimo)
- El navegador no recibe nada por POST así que vuelve a tener limpia la memoria y muestra foro.php
- foro.php muestra todos los comentarios, incluyendo el que se acaba de agregar
- El usuario presiona la tecla F5 o el botón “actualizar” del navegador
- foro.php no recibe datos y solo vuelve a mostrar la lista de comentarios sin duplicar nada
Con esto resolvimos un problema pequeño, pero que puede traer enormes consecuencias si no es corregido a tiempo. Para los que necesitan ver un poco de código, les dejo un ejemplo descargable que les despejará un poco mejor las dudas. Hago la aclaración que dicho ejemplo es bastante minimalista y ni siquiera trabaja con clases, pues no quiero aturdir al principiante con elementos que aún no conoce.


#1 by Katiuska Flores on 2/Mar/2010
Excelente post! gracias por compartir y explicar muy bien este tema.
saludos
#2 by Gabo on 2/Mar/2010
Buenísimo, algo bastante simple que fijo le puede pasar hasta al más experimentando de los desarrolladores.
Haber cuando le paso mi otro artículo para que lo publique ñ_ñ
#3 by chepe263 on 9/Mar/2010
Es buena idea, no le habia entendido pero ya le capte la onda. “Juan Perez” es un nombre mero generico, me dio un poquito de risa
Buen tuto!
#4 by Natalia Cruz on 30/May/2010
Hey ke chilero tu Blog
….x cierto no entendi nada del post! neehh ya se ke te esta saltando la ceja!! jaja… Sos una maquina ps
…mis respetos.
#5 by Attakinsky on 31/May/2010
jajajaja noooo, no me salta la ceja, al contrario… estoy muy agradecido por tu visita
#6 by LOVELY on 2/Jun/2010
Hola buenas tardes, tengo una pregunta, si yo no kiero que al actualizar se revien mis datos otra vez, pero cuando doy guardar y me envia a otro formulario yo le estoy psando datos a ese formulario, es decir en mis cajitas de texto me aparecera el nombre, apellido paterno que guarde en el form anterior y al dar actualizar en ese form es cuando se me duplican los datos, como puedo darle actualizar sin k se reenvien los datos, pero sin k se booren los datos que ya le pase.
#7 by Attakinsky on 2/Jun/2010
Yo te recomendaria que segmentaras tu FORM en varias partes usando http://jqueryui.com/demos/tabs/ y http://css-tricks.com/jquery-ui-tabs-with-nextprevious/
De esa forma, solo harian un envio para todo el formulario.
#8 by Luis on 17/Ago/2010
OMFG como son cositas pequeñas las que hacen la diferencia xD
#9 by Guille on 24/Ago/2010
sips… o a veces… tambien pasa que se un simple “data entry” guarde “nulls” … y todo lo que se guarde sea… nada. XD