• Publicidad

Barra de progreso

¿Apenas comienzas con Perl? En este foro podrás encontrar y hacer preguntas básicas de Perl con respuestas aptas a tu nivel.

Barra de progreso

Notapor tinchosan » 2011-09-01 11:42 @529

Hola gente, ¿qué tal? Bueno, como es mi primer post, me presento ante ustedes, Me llamo Martín y soy de Argentina. Hace unos días, mis jefes me pidieron que realice un upload de archivos (en Perl) con barra de progreso, el problema es que no logro comprender muy bien la sintaxis de Perl y no me da el tiempo como para leer un buen tutorial o el libro de Perl. Ahora bien, recurro a ustedes por la barra de progreso, el upload lo modifiqué de uno que está posteado en esta misma página (gracias). Aquí les dejo el código modificado, espero puedan ayudarme, se los agradecería muchísimo.

Por cierto, ¡qué buen lenguaje parece ser Perl!

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. sub recepcion_de_archivo {
  2.         my $nombre_en_servidor = $Input{'archivo'};
  3.         #para mantener el nombre del archivo original
  4.         $nombre_en_servidor =~ s/ /_/gi;
  5.         $nombre_en_servidor =~ s!^.*(\\|\/)!!;
  6.  
  7.         my $extension_correcta = 0;
  8.  
  9.         foreach (@extensiones)
  10.         {
  11.                 if($nombre_en_servidor =~ /\.$_$/i)
  12.                 {
  13.                         $extension_correcta = 1;
  14.                         last;
  15.                 }
  16.         }
  17.  
  18.  
  19.         if($extension_correcta) {
  20.                 #Abrimos el nuevo archivo
  21.                 my $fechahora = time(); # tomamos la fecha en el momento que se carga el archivo
  22.                 my $extensiondelarchivo = substr $nombre_en_servidor, -3; # tomamos la extension del archivo (ver)
  23.                 my $nuevonombrearchivo = $fechahora.".".$extensiondelarchivo; #rearmamos el nombre del archivo
  24.                 #print "\n".$nuevonombrearchivo;
  25.                 open (OUTFILE, ">$dir/$nuevonombrearchivo") || die "No se puedo crear el archivo";
  26.                 binmode(OUTFILE); #Para no tener problemas en Windows
  27.                 open (MIARCH,$Input{'archivo'});
  28.  
  29.                 my $peso_del_archivo = -s $nombre_en_servidor;
  30.                 #print "\n tamaño: ".$peso_del_archivo;
  31.                 #Transferimos byte por byte el archivo
  32.                 my $sumaBytes = 0;
  33.                 while (my $bytesread = read($Input{'archivo'}, my $buffer, 1024)) {
  34.                         print OUTFILE $buffer;
  35.                         $sumaBytes = $sumaBytes + $bytesread;
  36.                         my $porcentaje = int (($sumaBytes*100)/$peso_del_archivo);
  37.                         print "Content-type: text/html \n\n";
  38.                         print "<div name='porcentaje'>$porcentaje</div>";
  39.                         #################### aquí debería de mostrar la barra
  40.                 }
  41.                 #Cerramos el archivo creado
  42.                 close (OUTFILE);
  43.         }
  44.         else
  45.         {
  46.                 print "Content-type: text/html \n\n";
  47.                 print "<h1>Extension incorrecta</h1>";
  48.                 print join(",", @extensiones);
  49.                 exit(0);
  50.         }
  51.  
Coloreado en 0.003 segundos, usando GeSHi 1.0.8.4


¡Desde ya, muchas gracias!
Martín
tinchosan
Perlero nuevo
Perlero nuevo
 
Mensajes: 6
Registrado: 2011-09-01 11:28 @519

Publicidad

Re: Barra de progreso

Notapor explorer » 2011-09-01 13:43 @613

Bienvenido a los foros de Perl en español, tinchosan.

La solución no es obvia porque el problema, aunque lo parezca, tampoco lo es.

Primero, unos conceptos básicos.

Un CGI es un programa que el servidor web ejecuta, y del que espera unos contenidos, que serán transmitidos al navegador del usuario. Esos contenidos pueden ser una página HTML completa, o solo una parte (un módulo) dentro de una página HTML. Casi siempre son contenidos dinámicos, es decir, que depende de ciertas condiciones o parámetros, dará resultados distintos.

El proceso es: el usuario pulsa "algo" en la página que está viendo (una imagen, un enlace, un botón...). Eso se convierte en una petición al servidor web. Éste, mirando los mapas de traslación, se da cuenta de que corresponde a la ejecución de un proceso externo (el programa cgi). Arranca el proceso, pasándole por la entrada estándar los argumentos que el usuario ha enviado junto con la petición (el nombre del botón que ha pulsado, las coordenadas dentro de la imagen, o algún parámetro pasado por la URL en el caso del enlace).

El programa cgi se ejecuta, leyendo los argumentos, sacará el resultado por la salida estándar, con una cabecera HTTP. El servidor web encamina todo eso hacia el navegador del usuario, quien, por medio de la cabecera, sabrá cómo representar el resto del contenido. El programa cgi termina, y el servidor web cierra la conexión con el navegador del usuario. Y... ya empiezas a ver los primeros problemas: el protocolo CGI depende del protocolo HTTP, que no está orientado a conexión, sino solo a petición y respuesta. Una vez servido el contenido, se corta la conexión (bueno, no es del todo así, pero sí lo es de forma estricta).

Cuando un usuario hace una subido de un fichero, ese fichero se convierte en un flujo, que el servidor web reenvía hacia el proceso cgi, también a través de la entrada estándar.

El problema es que hasta que no se cierra el proceso cgi, la página sigue apareciendo como que sigue cargando, desde el lado del usuario. Y hay algunos navegadores que no presentan la página hasta que ésta ha llegado completamente. Y eso solo sucede si el proceso cgi ha terminado.

Dicho de otra manera: si el proceso cgi termina, no podemos ir mostrando la barra de progreso. Y si el proceso cgi no termina, el navegador del usuario no termina de pintar la página.

En tu programa, estás metiéndote en un bucle, enviando capas (<div>), con la esperanza de que el navegador web los represente, pero, para el navegador web se trata de capas individuales, con lo que saldrán todas las capas, una detrás de otra. Y lo dicho: no hay garantía de que salgan hasta que termine el cgi.

La solución clásica es usar el protocolo NPH (Non-Parsed-Header), y así el navegador va pintando la página a medida de que recibe contenidos, pero el resultado es el mismo que el de tu programa: los contenidos se van colocando unos detrás de otros.

Una solución intermedia es la siguiente: el proceso cgi envía una redirección (Location: ) a una página, cuyo único propósito es:
* recargarse cada x segundos (gracias a los <meta> de su cabecera)
* en cada recarga, ejecuta otro cgi, cuya única misión es de consultar el estado de descarga del fichero que se sigue bajando el primer cgi. En el caso de que ya esté del todo bajado, entonces, devuelve otra redirección (otro Location) pero esta vez para otra página que indique que el fichero ha subido completamente.

La solución moderna es usando Ajax: la página lanza el formulario con el fichero que sube el usuario, y queda a la espera de las respuestas que reciba desde el servidor. Desde el lado del servidor, el cgi sigue a lo suyo, recibiendo el fichero. El Ajax va ejecutando peticiones a otro cgi, que mira el progreso de la subida, y eso lo traduce el JavaScript en la animación de la barra de progreso.

No es una solución sencilla, claro. Por fortuna, algunos entornos de trabajo en JavaScript pueden ayudar a simplificar el trabajo de codificación.

En Perl, existe el módulo CGI::ProgressBar, que usa una mezcla de Perl y JavaScript, para presentar una barra de progreso, para procesos largos. Usa el truco de enviar un trozo de código HTML que llama a un código JavaScript que se envió en primer lugar.
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14480
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Re: Barra de progreso

Notapor tinchosan » 2011-09-01 14:32 @647

Hola Explorer, un millón de gracias por tu explicación, miraré un poco esta librería que comentaste en el post, y luego te aviso qué logré con ella. En caso que no logre un resultado positivo, ¿continuarías ayudándome?
tinchosan
Perlero nuevo
Perlero nuevo
 
Mensajes: 6
Registrado: 2011-09-01 11:28 @519

Re: Barra de progreso

Notapor explorer » 2011-09-01 14:37 @650

En la medida de nuestras posibilidades...
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14480
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Re: Barra de progreso

Notapor HernandoP » 2011-09-01 16:18 @721

Hola, mira aquí hay un código que a mi me sirvió mucho: http://www.perlmonks.org/?node_id=588964 , es usando CGI::Ajax.

Siempre puedes usar el código que tienes y meter en el HTML un meta refresh para que recargue la web cada X segs. Sería una solución muy rápida, pero lo de arriba es algo más elegante.

Saludos
HernandoP
Perlero nuevo
Perlero nuevo
 
Mensajes: 4
Registrado: 2011-05-24 04:26 @226

Re: Barra de progreso

Notapor tinchosan » 2011-09-02 07:29 @354

Hola HernandoP, muchas gracias por tu ayuda, voy a probar el ejemplo que me pasaste también. Saludos y gracias nuevamente.
tinchosan
Perlero nuevo
Perlero nuevo
 
Mensajes: 6
Registrado: 2011-09-01 11:28 @519

Re: Barra de progreso

Notapor tinchosan » 2011-09-02 12:57 @581

Hola gente, estuve probando la librería progressbar pero, no me funciona ni siquiera el ejemplo más básico :(

Les adjunto una imagen de cómo se visualiza el ejemplo. Quisiera saber por qué no me funciona, de paso, les dejo el ejemplo que utilicé.

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. #!C:\wamp\bin\perl\bin\perl.exe
  2. use strict;
  3. use warnings;
  4. use CGI::ProgressBar qw/:standard/;
  5. $| = 1;                                # Do not buffer output
  6. print
  7.     header,
  8.     start_html(
  9.         -title => 'A Simple Example',
  10.         -style => {
  11.             -src  => '',                   # You can override the bar style here
  12.             -code => '',                   # or inline, here.
  13.         },
  14.     ),
  15.     h1('A Simple Example'),
  16.     p('This example will update a JS/CSS progress bar.'),
  17.     progress_bar( -from => 1, -to => 100 )
  18.     ;
  19.  
  20. # We're set to go.
  21. for ( 1 .. 10 ) {
  22.     print update_progress_bar;
  23.  
  24.     # Simulate being busy:
  25.     sleep 1;
  26. }
  27.  
  28. # Now we're done, get rid of the bar:
  29. print hide_progress_bar;
  30. print p('All done.');
  31. print end_html;
  32. exit;
  33.  
  34.  
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4


Obviamente, investigué la forma de hacerlo funcionar, pero no la encontré, incluso, modificando el css de la librería.
Adjuntos
error progressbar.jpg
error progressbar.jpg (23.22 KiB) Visto 1443 veces
tinchosan
Perlero nuevo
Perlero nuevo
 
Mensajes: 6
Registrado: 2011-09-01 11:28 @519

Re: Barra de progreso

Notapor explorer » 2011-09-02 14:12 @633

Pues... tienes razón... El problema está en el propio módulo, que tiene errores.

Si aplicas el siguiente parche, al fichero ProgressBar.pm, ya funciona.
Sintáxis: [ Descargar ] [ Ocultar ]
Using text Syntax Highlighting
252c252
<   pblib_progress_update()\n//-->\n</script>\n";
---
>   pblib_progress_update();\n//-->\n</script>\n";
267c267
<   $self->{progress_bar}->{layer_id}->{container}.style.display='none';\n//-->\n</script>\n"
---
>   document.getElementById('$self->{progress_bar}->{layer_id}->{container}').style.display = 'none';\n//-->\n</script>\n"
350c350,351
<           }\n";
---
>           }
>       }\n";
352c353
<   $html .= "}\n//-->\n</script>\n";
---
>   $html .= "  }\n//-->\n</script>\n";
366a368
>       height: ".($self->{progress_bar}->{height})."px;
375,377c377,379
<     : "float:left;
<        width: ".($self->{progress_bar}->{block_wi})."px;"
<   )."
---
>       : "     float:left;
>       width: ".($self->{progress_bar}->{block_wi})."px;"
>         )."
380,381c382,383
<   .pblib_block_on  { border:1px solid blue;  background: navy; }

<   ";
---
>   .pblib_block_on  { border:1px solid blue;  background: navy; }";
>
Coloreado en 0.000 segundos, usando GeSHi 1.0.8.4


Ejemplo: http://joaquinferrero.com/~explorer/cgi ... ressbar.pl
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14480
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Re: Barra de progreso

Notapor tinchosan » 2011-09-02 14:31 @646

Disculpa mi ignorancia, pero no comprendí el parche que me has pasado (la sintaxis no la comprendo). ¿Podrías explicármelo un poco?
tinchosan
Perlero nuevo
Perlero nuevo
 
Mensajes: 6
Registrado: 2011-09-01 11:28 @519

Re: Barra de progreso

Notapor explorer » 2011-09-02 14:40 @653

Debes abrir el fichero ProgressBar.pm. Luego, debes hacer los cambios que te propone el parche.

* los números indican el número de la(s) línea(s) del cambio que debes hacer. Entre los números hay unas letras, que quieren decir: 'a' -> añadido, 'c' -> cambiado, 'd' -> borrado.

* el carácter '<' indica cómo es la línea actual

* el carácter '>' indica cómo ha de ser la nueva línea.

Otra opción es usar la utilidad patch, que hace todos estos cambios de forma automática.

Más información (Wikipedia)
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14480
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Siguiente

Volver a Básico

¿Quién está conectado?

Usuarios navegando por este Foro: No hay usuarios registrados visitando el Foro y 27 invitados