Subir archivos con JavaScript, fetch y FormData a PHP

Cargar archivo a PHP desde JavaScript con FormData

Introducción

Enviar datos con AJAX es algo relativamente fácil; pues al final de todo son simples datos. Ya sean cadenas o números, todo es texto. Pero algo distinto pasa cuando queremos cargar un archivo o fichero con JavaScript hacia PHP.

Esto es más complicado cuando queremos hacerlo con AJAX, pues no hay una forma estandarizada de enviar un archivo; y nos topamos con que el usuario podría seleccionar archivos pesados.

Lo que nos quedaría sería poner un formulario y agregar un <input type="file"> pero nuestra página perdería dinamismo.

Afortunadamente desde hace algunos años existe la API de FormData, la cual ofrece una manera de enviar todo tipo de datos como se enviarían en un formulario; con la ventaja de poder hacerlo sin interrumpir al usuario o recargar la página.

Subir archivo a PHP con JavaScript + FormData

Esto será muy, muy simple y fácil de hacer. Lo que haremos será subir un archivo de cualquier tipo con JavaScript y guardarlo con PHP. No nos fijaremos en la seguridad o esas cosas.

Todo eso será usando FormData y fetch, el remplazo nativo de XMLHttpRequest. Por cierto, para esto debes tener configurado e instalado un servidor con PHP.

Ya habíamos hecho algo similar pero usando jQuery y CodeIgniter; ahora usaremos JavaScript y PHP sin frameworks.

El lado del cliente

Sólo necesitamos poner el input de tipo file para tomar el archivo y para darle al usuario una interfaz para que pueda seleccionarlo. Quedaría así:

También agregamos un botón que será el encargado de enviar el archivo. Estos dos elementos los tomamos en el script:

Necesitamos a ambos. btnEnviar para escuchar su click y realizar la lógica necesaria; inputFile para obtener los archivos que el usuario ha elegido.

Entonces, en el click del botón agregamos esto:

Lee sobre las funciones flecha aquí si no entiendes eso de () =>.

Primeramente comprobamos si hay archivos cargados. Los mismos son representados como un arreglo, así que usamos la propiedad length. Si no hay archivos, le avisamos al usuario con un alert.

Lo que estamos haciendo es crear un objeto de tipo FormData.

Le agregamos un elemento (podrían ser miles más, y no todos tienen que ser archivos, podrían ser cadenas o números) con la clave “archivo” justo en donde hacemos formData.append("archivo", inputFile.files[0]).

Es importante entender que esta clave servirá más tarde para leer el archivo del lado del servidor. Le estamos agregando lo que haya en el arreglo de archivos en la posición 0; es decir, el primer elemento.

Más tarde hacemos una petición con fetch, la cual es de tipo POST.

Como cuerpo enviamos el objeto formData. Cuando la promesa se resuelva decodificamos la respuesta como texto y cuando esta segunda promesa se resuelva imprimimos el contenido; en resumen simplemente estamos imprimiendo lo que el servidor dijo.

Aquí termina el lado del cliente.

Lado del servidor con PHP

No sé si es coincidencia, pero siempre el código del lado del servidor es más corto. Supongo que ha de ser porque no validamos ni hacemos tantas cosas como en el lado del cliente.

Pues bien, nuestro archivo estará en el arreglo superglobal de PHP $_FILES; en la posición clave, indicada por el nombre que le pusimos en el append de JavaScript.

Como le pusimos “archivo”, aquí también accederemos a “archivo” así:

Pero sólo estamos obteniendo su información; porque cuando lo subimos se mueve a una carpeta temporal.

Para guardarlo en el disco duro, o mejor dicho, en donde está el script, usamos la función move_uploaded_file que quiere decir algo como mover_archivo_subido.

Este toma dos argumentos. El primero indica en dónde está el archivo original, y esa ruta no la sabemos pero PHP sí, y la puso en $archivo["tmp_name"].

El segundo argumento indica en dónde pondremos el archivo. Aquí, por simplicidad, lo estoy guardando con su nombre original aunque no recomiendo hacerlo si no confías en el usuario final.

Si queremos, podemos cambiar el segundo argumento por un nombre generado por nosotros. Se me ocurre usar uniqid y concatenarlo con la extensión del archivo, la cual podemos obtener con pathinfo.

La función que mueve el archivo devuelve un booleano. Dependiendo de lo que devuelva imprimimos un mensaje, y eso será lo que reciba el cliente como respuesta.

Probando código

Aquí dejo un GIF:

Subir archivos con JavaScript, fetch y FormData a PHP
Subir archivos con JavaScript, fetch y FormData a PHP

En él se puede observar que arrastramos un archivo (también podríamos simplemente pulsar el botón de Seleccionar archivo).

La carga es demasiado rápida, y el archivo aparece copiado a la carpeta en donde está el script.

Código final

Lo dejo en GitHub.

Encantado de ayudarte


Estoy disponible para trabajar en tu proyecto, modificar el programa del post o realizar tu tarea pendiente, no dudes en ponerte en contacto conmigo.

No te pierdas ninguno de mis posts

Suscríbete a mi canal de Telegram para recibir una notificación cuando escriba un nuevo tutorial de programación.

6 comentarios en “Cargar archivo a PHP desde JavaScript con FormData”

  1. ¿Y si tengo dos input distintos, uno para subir una imagen y otro para subir pdf? No doy con la forma de capturar ambos archivos…lo he intentado añadiendo ambos archivos a un mismo formdata pero no consigo nada útil. La cosa es que quiero presionar un boton y todos esos archivos se suban a su lugar correspondiente.

    1. Puedes hacer uso de un bucle para subir ambos archivos junto a la propiedad “multiple” del input file.

  2. Pingback: Grabar audio de micrófono con JavaScript y PHP - Parzibyte's blog

Dejar un comentario