Barra de progreso en ... PHP
2004-10-21 09:03:56
Situación
Tengo que hacer una importación masiva de datos de Excel a MySQL. Todo muy bien, excepto por dos detalles: debo usar un set_time_limit(600); para sobrepasar el tiempo máximo de ejecución del servidor (ningún problema) y durante todo el proceso los echo que están dentro del bucle interminable no salen por pantalla. Eso ya me preocupa más porque el usuario que haga la importación puede pensar que el proceso se ha quedado congelado en algún punto. Así que me pongo a buscar...
Avances
Parece ser que php trae unas funciones que liberan el contenido de los buffers por pantalla. Se trata de flush() y ob_flush(). Sinceramente no entiendo muy bien la diferencia entre ambos, pero por lo visto en los comentarios del manual es mejor usarlos conjuntamente para asegurarse que el contenido actual de la página de muestra en el navegador. Probamos en cada etapa del bucle y bingo! La cosa funciona! Así que me pongo a pensar si será posible hacer una barra de progreso en PHP... Y lo es! No me lo puedo creer. Claro que bajo ciertas condiciones, pero el efecto es una gozada. Veamos...
Requisitos
Ante todo, decir que esta barra de progreso solamente tiene sentido si no sacamos datos por pantalla durante todo el proceso de importación de datos (o consulta, etc). Es decir, si queremos sacar datos por pantalla tansolo necesitamos añadir flush();ob_flush(); al final de cada paso del bucle para hacer efectiva la salida por pantalla. Pero en lugar de ir sacando datos del tipo un registro en cada linea a medida que pasa el bucle, creo que es más elegante mostrar una barra de progreso. Es decir, no sacaremos datos del bucle por pantalla pero sí que iremos informando de cómo va el proceso.
Solución
Añadiremos antes del bucle lo siguiente:
echo "<div id='progress' style='position:relative;padding:0px;
width:650px;height:960px;left:25px;'>";
Eso empieza un bloque (una capa) donde iremos mostrando unos botones a modo de barra de progreso, añadiendo el siguiente código dentro de cada paso del bucle:
echo "<div style='float:left;margin:5px 0px 0px 1px;width:2px;
height:12px;background:red;color:red;'> </div>";
flush();
ob_flush();
Y terminaremos cerrando la capa una vez fuera del bucle y escondiendo la barra de progreso con un pequeño script:
echo "</div>";
echo "<script>";
echo "document.getElementById('progress').style.display = 'none';";
echo "</script>";
Podeis ver un ejemplo donde simulamos hacer un gran trabajo de consulta en la base de datos (en realidad usamos una pausa en el bucle usando sleep(1); para que la cosa tarde un segundo en hacer cada paso). Y aquí teneis el código de la barra de progreso en PHP. Disfrutadla ;)
Ojo, esta técnica no muestra porcentajes, aunque podría con un poco más de cálculos, obteniendo el número máximo de registros devueltos y añadiendo un contador proporcional, etc. Os lo dejo de deberes.