Weblog

Barra de progreso en ... PHP

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.

Comentarios sobre esta entrada

  1. 2004-11-02 20:21:40

    • Julio Juarez
    • [e]
    esta muy cool la barra se sacaron un diezzzzzz
  2. 2004-11-03 10:42:24

    Hi Sergi, Thanks for posting this code it's fantastic just what I have been looking for. I had got as far as the flush and ob_flush code to return the html to the browser but hadn't managed to work out the way to add the bar. It's great! Thank You and it seems so obvious now. I think I will make it work with percentages and post the code back to you if you are interested. Thanks again, Darren
  3. 2004-11-03 10:51:39

    hey Darren, so glad you like it ;) I already have that % code done, it's just 2 or 3 lines of code. i added that comment to try to start some small "homeworks feedback" on code-related posts, but thanx, its always great to hear from users

  4. 2004-11-11 06:52:46

    Hey Sergi, I've used a method like this in the past for a project that had some long processing tasks. I echoed out something like this:

    
    <script>
    ProgressBar.Update($percent,'$projectname','$filename');
    </script>
    

    Then the ProgressBar object handles the nice displaying of the bar.

    (For what it's worth, the project I worked on rendered 100s of pages from a server based e-learning development system as HTML and output them in a directory structure with image and script resources, it then zipped them all up and sent them down to the user.)

  5. 2004-11-11 06:54:40

    PS It might be nice to automatically add <br />'s to the messages :)

    Also my last post's <script> tags were stripped out. Maybe a BB-Code type thing would be better.

  6. 2004-11-11 08:35:52

    hey Dan, thanx for the comments! It's awesome, i think it'd work much better than my approach casue javascript would handle all calculations, php would only have to flush the script tags.

    ah, yeah, i have to fix the form to accept bbcode or smth like that, i only accept p, em, strong and links so far but code would be perfect. I'll have a look ;)

  7. 2005-02-12 12:52:08

    This works amazingly well! Thanks!
  8. 2005-03-14 12:21:43

    • hector Barrera
    • [e]
    Este pedazo de codigo es excelente, me haz sacado del mayor apuro que he tenido, muchas gracias. un detalle podriamos colocarle algo de diseno a esa barra?? soy un conchudo. gracias
  9. 2005-05-11 09:20:28

    scsd
  10. 2005-05-13 12:27:46

    Very, very nice script, i searched long time for it. I modificated it a little bit so that only one bar line appear for regardless how many peace of data: for example you recive from SELECT n rows: $n = mysql_num_rows($rs); than: $bc = round($cnt/135); //135 was my experiment for DIV width=450px $bcnt = 1; than in loop: if ($bc==0) { echo " "; } else { if (($bcnt%$bc)==0) { echo " "; } } flush(); ob_flush(); $bcnt++; // if ($bc==0) it's for small data, where $bc will be 0 ... now i have only and each time one bar line independent of data lines count. Gruess Sergio
  11. 2005-09-15 13:26:33

    Muchas gracias por compartir este codigo, aclara muchas cosas...

Cerrado

Debido a la mierda de spam este weblog queda cerrado a comentarios, era imposible mantener el script de la lista negra al día. Si quieres busca mi email y enviame un mensaje. Lo siento.

Cambia las preferencias

Cambia las preferencias

Licencia

Creative Commons 2001-2004. Sergi Meseguer

Sindicación RSS

rss (1, 2 ), xhtml, css, taw