Upload de archivos y progressbar con PHP,Perl y AJAX

Aún cuando no he conseguido desentramar el misterio de la antena reaparecida, otra misteriosa casualidad ha roto mi paz interior, esta vez relacionada con el trabajo.

Hoy al llegar a la oficina me he encontrado con una recomendación por mail en qué se citaba un artículo en inglés que habla acerca de un sistema de carga de ficheros con barra de progreso usando técnicas AJAX y PHP+Perl como lenguages de servidor.

Da la casualidad que llevo semanas intentando montar un sistema así para el upload de videos y audio en OboLog , y de hecho hace algunos días que he conseguido una primera versión funcional, y me ha sorprendido que el artículo de Thomas Epineer, "Asynchronous file upload with AJAX progress bar in PHP", se ha basado exactamente en los mismos proyectos que el "mix" en qué he estado trabajando, como apunté días atrás en la lista de correo de JQuery.

Realmente hasta ahora no habia nada sobre el tema, y los únicos acercamientos al upload de archivos que hacían uso de AJAX, como el de Martin Konicek , dejaban de lado la posibilidad de saber en cada momento qué porcentaje del archivo llevamos cargado, debido en parte a la limitación de PHP al respecto ( PHP no permite acceder 'en bruto' a los datos POST durante el envío ).

El ejemplo de Martin va orientado principalmente al upload de imágenes para una galería y esto significa que los archivos no serán, en principio, demasiado grandes. En este caso una barra de upload no es imprescindible, puesto que los tiempos de carga serán generalmente bastante bajos, y además los ficheros se van cargando en paralelo,en segundo plano, cada vez que el usuario selecciona uno.

En otras situaciones, sin embargo, como sería el caso de vídeos, archivos de audio, o documentos de cierto tamaño ( > 1 MB ), es mucho más probable que la demora en la carga pueda provocar desconcierto en el usuario y una ocasional cancelación por su parte, reenviando el formulario o volviendo atrás para probar de nuevo. La barra de progreso permite que mantengamos informado en todo momento al usuario del estado del upload que está realizando, y nos evita problemas, consecuencia de las largas esperas y la falta de información acerca del estado de su solicitud.

La limitación de PHP la podemos solventar simplemente usando otro lenguaje a la hora de gestionar la carga de los archivos al servidor: un CGI en Perl. Buscando un poco (tampoco había mucha literatura sobre el tema, como os comentaba), en raditha.com encontré un script que hacía precisamente esto: combinar PHP y CGIs para conseguir un upload con barra de progreso: Mega Upload. . Básicamente lo que hace es generar varios archivos en una carpeta temporal con datos acerca de la carga que se está realizando: Tamaño total del envío, nombre de los archivos que se envían, y datos en bruto del envío post combinando todos los archivos contenidos. Sólo queda acceder a esos datos de manera repetitiva mientras se lleve a cabo el upload para ir dibujando la correspondiente barra de progreso.

En la implementación de AJAX, sin embargo, hemos usado herramientas diferentes. Thomas ha usado Prototype, una librería Javascript muy potente (¿os suena script.aculo.us?) que permite simplificar algunos procesos para el acceso y la modificación de los elementos DOM y el uso de peticiones asíncronas via XMLHttpRequest ( AJAX, vamos ). Sin embargo, uno de los problemas de Prototype es, a mi parecer, el excesivo peso de la librería por si sola ( sin tener en cuenta ya el peso total de las librerías JS necesarias si pensamos usar todo el potencial de script.aculo.us ). La versión de Prototype incluída en el ejempo de Thomas pesa más de 40Kb.

Para llevar a cabo el experimento que he mencionado arriba he usado una librería que descubrí hace poco: JQuery. Permitidme tirarme a la piscina, y asegurar sin demasiado miedo a equivocarme, que creo que JQuery es una auténtica revolución. En menos de 15Kb de peso tenemos una librería que permite simplificar en extremo la sintaxis de Javascript, acceder y modificar el árbol DOM usando sintaxis de CSS1,2 y 3, XPath y algunos métodos propios, aplicar efectos visuales sencillos y ejecutar peticiones AJAX, así como parsear las respuestas resultantes en XML o usarlas para escribir directamente dentro de contenedores de la propia página. Podría extenderme largamente, y posiblemente lo haga en el futuro con un post dedicado a JQuery en exclusiva, pero ahora mismo lo más sencillo es que entréis a su web y echéis un vistazo a la documentación y los ejemplos de uso. Sencillamente es-pec-ta-cu-lar. De hecho la estoy usando para simplificar librerías que uso para otros menesteres, adaptándolas al "JQuery way of coding". Os aseguro que la mejora en cuanto a ahorro de espacio y simplificación es del orden del 70%. También debo decir, por otra parte, que tiene algunos puntos débiles: las funciones AJAX devuelven errores o no funcionan correctamente en algunos navegadores. JQuery se encuentra en contínua evolución, así que estoy seguro de que pronto las solucionarán estos problemas.

El toque final, la idea de seleccionar varios archivos usando un _aparentemente_ único campo "file" la tomé prestada de un artículo que leí hace un tiempo en StickBlog, "Upload multiple files with a single file element". El tema es ir creando dinámicamente nuevos campos file a medida que el usuario va seleccionando ficheros, e ir ocultando los campos file ya usados. Adicionalemente, para llevar un control de todos los ficheros seleccionados, se va creando una lista con los nombres de los archivos. Hacer todo esto con Jquery no són más de 5 líneas de código ( lo podéis comprobar revisando el código fuente del experimento).

Bueno, y eso es todo. Espero que alguien pueda sacar provecho de todo esto, después de la parrafada! Al final la sorpresa me ha inducido a reflexionar en voz alta y dejar por escrito algo en lo que llevaba "trabajando en silencio" desde hace un tiempo. Los usuarios de OboLog lo veréis en funcionamiento dentro de poco. Tened paciencia. Guiño

Albert García Gibert

Cofounder and former CTO of Uvinum. Founder of Obolog and Splitweet. Father of Júlia & Abril. I'd like to travel more and improve my guitar skills.

El Prat de Llobregat, Barcelona https://twitter.com/obokaman