> Manuales > Manual de Ajax práctico - Taller Ajax

Se ha escrito y discuto mucho sobre si es o no es factible utilizar AJAX para subir un archivo al servidor.

Por una necesidad personal yo también me vi involucrado en esta serie de discusiones. La finalidad de este artículo es que le sea útil a alguien; principalmente a mi.

Entonces ...
Al finalizar este pequeño tutorial deberías entender a la perfección este ejemplo.

Primer Error: Titulo Mal Empleado

Me voy a disfrazar de traductor en Inglés. Sería algo como Archivo Subido con AJAX. Esto, hoy por hoy, no se puede hacer. Es así y no hay vuelta que darle.
Entonces usted dirá ...
- heeee, si yo en gmail puedo subir archivos y lo hago con AJAX !!!.
Yo le respondo ...
- No sea bobo, yo también creía lo mismo.

Hay sobradas muestras que el objeto XMLHttpRequest no puede enviar archivos al servidor.
Entonces deberíamos cambiar el titulo del post. Sería así:

Ajax File Upload SIN Ajax

Frente a esta inmutable condición los desarrolladores han buscado una buena forma de simular scripts para subir archivos al servidor como si fuese con AJAX, y por lo menos conmigo lo lograron. Primer Ejemplo - Subir un Archivo el Server

Utilizaremos tan solo dos scripts muy sencillos. Luego iremos mejorando y complementando el desarrollo hasta llegar a nuestro objetivo.

HTML:

<form method="post" enctype="multipart/form-data"
action="controlUpload.php"
target="iframeUpload">
<input type="hidden" name="phpMyAdmin" />
Archivo: <input name="fileUpload" type="file" />
<input type="submit" value="enviar">
<iframe name="iframeUpload"></iframe>
</form>


Es es un simple formulario HTML con un campo FILE y un marco flotante iframe denominado iframeUpload. Cuando enviamos el archivo al servidor ejecutaremos el script controlUpload.php y la respuesta del server se hará en nuestro iframe ya que apuntamos al mismo dentro de la etiqueta target en la declaración form.

PHP:

// Script Que copia el archivo temporal subido al servidor en un directorio.
echo '<p>Nombre Temporal: '.$_FILES['fileUpload']['tmp_name'].'</p>';
echo '<p>Nombre en el Server: '.$_FILES['fileUpload']['name'].'</p>';
echo '<p>Tipo de Archivo: '.$_FILES['fileUpload']['type'];
$tipo = substr($_FILES['fileUpload']['type'], 0, 5);
// Definimos Directorio donde se guarda el archivo
$dir = 'archs/';
// Intentamos Subir Archivo
// (1) Comprovamos que existe el nombre temporal del archivo
if (isset($_FILES['fileUpload']['tmp_name'])) {
// (2) - Comprovamos que se trata de un archivo de imágen
if ($tipo == 'image') {
// (3) Por ultimo se intenta copiar el archivo al servidor.
if (!copy($_FILES['fileUpload']['tmp_name'], $dir.$_FILES['fileUpload']['name']))
echo '<script> alert("Error al Subir el Archivo");</script>';
}
else echo 'El Archivo que se intenta subir NO ES del tipo Imagen.';
}
else echo 'El Archivo no ha llegado al Servidor.';


Cuando se ejecuta el script, este intenta rescatar los datos del archivo a subir. Para eso se vale del array global de PHP $_FILES. Si no estas muy familiarizado recomiendo que leas esta sección del manual oficial para entender su funcionamiento y sus particularidades.

En las primeras líneas presentamos el nombre del archivo temporal generado por nuestro motor PHP, el segundo es el nombre real del archivo y el tercero es el tipo de archivo.
Si estos valores están definidos evidentemente el archivo llego al server. Estas líneas mas adelante no las utilizaremos; ahora sólo las usamos para realizar el seguimiento del script.
Asignamos a $tipo el tipo de archivo para poder controlar que sea una imágen. Se cortan los primeros 5 caracteres y si todo es correcto $tipo tendrá el valor image. Si no es una imagen tendrá un valor distinto. Este control se puede hacer de diversas formas; nosotros utilizamos esta.

Luego, intentamos copiar el archivo temporal en forma definitiva en algún sector físico en nuestro servidor. Se verifica en forma anidada definición de nombre temporal de archivo, tipo de archivo y si el motor concretó la copia.
En este ejemplo lo hacemos en la carpeta archs/.
Si está todo bien podemos pasar al segundo paso.
En este link podemos probar el script. Podemos ver los archivos subidos al server en este link.

Aclaraciones.
Hay que definir permisos de escritura de PHP en el directorio a copiar el archivo. En nuestro caso es la carpeta archs.

Armando el Circo

Empecemos a modificar un poco los archivos anteriores.
En primer lugar vamos a eliminar el botón submit Enviar y vamos a disparar el formulario con una orden en JS.

JavaScript:

onchange="javascript: submit()"

Vamos a ocultar el iframe.

JavaScript:

style="display:none"

Al final del archivo agregamos una línea que nos dirige a un simple script que nos muestra los archivos subidos al server; más que nada para que puedas corroborar la funcionalidad.

HTML:

<a href="verArchivos.php">Ver Archivos</a>

Esta línea no se presenta en el script.

HTML:

   <form method="post" enctype="multipart/form-data"
action="controlUpload2.php" target="iframeUpload">
Archivo: <input name="fileUpload" type="file" onchange="javascript: submit()" />
<br /><iframe name="iframeUpload" style="display:none"></iframe>
</form>
Y al script controlUpload.php le vamos a agregar alertas de control (también con JS por ahora). Además vamos a eliminar sentencias que se han vuelto innecesarias al ocular el iframe.

PHP:

// Script Que copia el archivo temporal subido al servidor en un directorio.
$tipo = substr($_FILES['fileUpload']['type'], 0, 5);
// Definimos Directorio donde se guarda el archivo
$dir = 'archs/';
// Intentamos Subir Archivo
// (1) Comprovamos que existe el nombre temporal del archivo
if (isset($_FILES['fileUpload']['tmp_name'])) {
// (2) - Comprovamos que se trata de un archivo de imágen
if ($tipo == 'image') {
// (3) Por ultimo se intenta copiar el archivo al servidor.
if (!copy($_FILES['fileUpload']['tmp_name'], $dir.$_FILES['fileUpload']['name']))
echo '<script> alert("Error al Subir el Archivo");</script>';
else
echo '<script> alert("El archivo '.$_FILES['fileUpload']['name'].' se ha copiado con Exito");</script>';
}
else echo '<script> alert("El Archivo que se intenta subir NO ES del tipo Imagen.");</script>';
}
else echo '<script> alert("El Archivo no ha llegado al Servidor.");</script>';


controlUpload2.php | Ver

Ya se empieza a parecer a un verdadero AJAX FILE UPLOAD. Que siga el circo !. Show must go on.

Finalmente un sencillo Script

Con estas últimas modificaciones tendremos la base final para poder implementar nuestro FILE UPLOAD con un comportamiento muy similar a gmail.
Al formulario lo vamos a contener en un div con id formUpload.

HTML:

<div id="formUpload">
Al archivo upload3.php, aparte del formulario de envío le vamos a agregar una sencilla función resultadoUpload (estado, file) realizada en JS que, dependiendo del código que nos 'envíe' controlUpload.php en las variales estado y file (ahora vemos como ...) imprimirá en dicho div un mensaje de respuesta al intento de subida.

JavaScript:

function resultadoUpload(estado, file) {
var link = '<br /><br /><a href="upload3.php">Subir Archivo</a> - <a href="verArchivos.php">Ver Imagenes</a>';
if (estado == 0)
var mensaje = 'El Archivo <a href="archs/' + file + '" target="_blank">' + file + '</a> se ha subido al servidor correctamente' + link;
if (estado == 1)
var mensaje = 'Error ! - El Archivo no llego al servdor' + link;
if (estado == 2)
var mensaje = 'Error ! - Solo se permiten Archivos tipo Imagen' + link;
if (estado == 3)
var mensaje = 'Error ! - No se pudo copiar Archivo. Posible problema de permisos en server' + link;
document.getElementById('formUpload').innerHTML=mensaje;
}


La impresión de nuestro mensaje en el div lo hace en la última linea de la función.

JavaScript:

document.getElementById('formUpload').innerHTML=mensaje;

Este sitio tiene una buena descripción del conjunto de funciones getElementBy*. De todas formas, con un poco de tu gran astucia podrás encontrar muchos ejemplos de su funcionamiento.

Ahora solo resta modificar controlUpload.php para que en vez de ejecutar una ventana alert () (como en el ejemplo anterior) simplemente ejecute el código JavaScript para llamar a la función resultadoFile () enviándole los datos correspondientes al intento de subida del archivo.
El punto llamativo es como accedemos desde el iframe oculto a la función que se encuentra en la página que lo contiene. Utilizamos la palabra reservada de JS parent.

JavaScript:

<script>parent.resultadoUpload(estado, file);</script>

Las otras modificaciones son para mejorar estéticamente las páginas. También se utilizan dos scrips en php. verArchivos.php para ver los archivos subidos y eliminar.php que no requiere demasiada explicación. Finalizando

Este humilde tutorial se hizo más largo de lo que hubiese querido. Voy a seguir trabajando para mejorar el funcionamiento y evolucionarlo. Queda pendiente una barra de progreso (ahí creo que no podemos escapar de AJAX) y otras formas de aplicación.
Tomen al mismo y a todo el código como una guia par desarrollar esta pequeña aplicación. Faltan muchos controles de errores, de seguridad, etc. El código fuente presentado no es idéntico a los archivos que se pueden descargar; esto es simplemente por una cuestión de prolijidad.
Disculpen mi desorden semántico y gramatical; como la mayoría, soy atrevido al jugar el papel de tutor. Nada más lejos de mis fines. Simplemente lo mío es ayudar como así también me han ayudado.

Damián Suárez

Impulsor de XiFOX.net

Manual