Las aburridas formas de subir archivos son cosa del pasado. HTML5 ofrece la posibilidad de añadir la función de “arrastrar y soltar”, y AJAX permite subir archivos sin actualizar la página.

Principalmente, los usuarios ven o descargan información de los sitios web, pero a veces necesitan subir algo ellos mismos. Puede ser una foto de perfil, un archivo comprimido con documentos, una canción, un vídeo de una boda o un artículo en formato .docx.

El programador debe asegurarse de que el visitante pueda hacerlo de la manera más cómoda posible. Se puede subir un archivo a un sitio web usando un formulario normal y un gestor en PHP, pero con la llegada de HTML5 han aparecido otras posibilidades interesantes; en este artículo hablaremos tanto de las funciones básicas como de las novedades.

Subir archivos con PHP

Empecemos creando un formulario:

<form method='post' action="/file.php" enctype="multipart/form-data">
<input type="hidden" name="MAX_FILE_SIZE" value="5000000">
<input type='file' name='file[]' class='file-drop' id='file-drop' multiple required><br>
<input type='submit' value='Subir' >
</form>
<div class='message-div message-div_hidden' id='message-div'></div>

Para la etiqueta <form>, especificamos los siguientes atributos:

  • method: método de envío de datos (en nuestro caso, post);
  • action: ruta al gestor;
  • enctype: tipo de formulario; el valor multipart/form-data le indica al navegador que se enviarán varios archivos a la vez.

A continuación, en el formulario se crea un campo oculto MAX_FILE_SIZE, donde se indica el tamaño máximo de los archivos a subir en bytes. Este campo debe preceder al campo de selección de archivos. Esto es necesario para que el usuario sepa que ha superado el límite de tamaño del archivo antes de que termine de cargar un vídeo de 200 MB. Pero la comprobación principal debe hacerse igualmente con el gestor, ya que el valor de este campo se puede modificar en el navegador.

En la segunda etiqueta <input>, se añade el atributo multiple y el nombre file[]; esto permitirá subir varios archivos a la vez con un solo campo. También hay un <div> en el código, donde se mostrará más tarde un mensaje.

A continuación, se indican los estilos CSS:

.file-drop {
background:#fff;
margin:auto;
padding:200px 200px;
border:2px solid #333;
}
.file-drop_dragover {
border:2px dashed #333;
}
.file-drop__input {
border:0;
}
.message-div {
background:#fefefe;
border:2px solid #333;
color:#333;
width:350px;
height:150px;
position:fixed;
bottom:25px;
right:25px;
font-size:15px;
padding:5px;
z-index:99999;
box-shadow: 0 0 10px rgba(0,0,0,0.5);
}
.message-div_hidden {
right:-9999999999999999999px;
}

Y así es como se ve:

Una captura de pantalla muestra una interfaz de usuario simple para subir archivos. Incluye un botón "Elegir archivos"
Diseño limpio y sencillo para la subida de archivos en un sitio web.

El formulario ya funciona: se pueden seleccionar o arrastrar archivos, y después de hacer clic en el botón “Subir”, los datos se envían al gestor. Allí llegan a un súper array multidimensional $_FILES. Su estructura es la siguiente:

  • nombre del campo a través del cual se ha subido el archivo;
  • name: nombre del archivo a subir;
  • type: tipo en formato MIME;
  • size: tamaño en bytes;
  • tmp_name: dirección temporal;
  • error: número de error, si se ha producido alguno.

Si se suben varios archivos a la vez a través de un solo campo, el acceso a uno en concreto se realiza de la siguiente manera: $_FILES['file']['name'][0] – el índice del archivo está al final.

Primero hay que hacer varias comprobaciones, y solo después mover los archivos del almacenamiento temporal directamente al sitio web. De lo contrario, podría ocurrir que los intrusos suban archivos PHP y puedan ejecutarlos para obtener acceso a la base de datos o al sistema de archivos del servidor.

Así es como se ve el gestor:

<?php
if(isset($_FILES)) {
$allowedTypes = array('image/jpeg','image/png','image/gif');
$uploadDir = "files/"; //Directorio de subida. Si no existe, el gestor no podrá subir archivos y mostrará un error
for($i = 0; $i < count($_FILES['file']['name']); $i++) { //Recorremos los archivos subidos
$uploadFile[$i] = $uploadDir . basename($_FILES['file']['name'][$i]);
$fileChecked[$i] = false;
echo $_FILES['file']['name'][$i]." | ".$_FILES['file']['type'][$i]." — ";
for($j = 0; $j < count($allowedTypes); $j++) { //Comprobamos si corresponde a los formatos permitidos
if($_FILES['file']['type'][$i] == $allowedTypes[$j]) {
$fileChecked[$i] = true;
break;
}
}
if($fileChecked[$i]) { //Si el formato es correcto, movemos el archivo a la dirección especificada
if(move_uploaded_file($_FILES['file']['tmp_name'][$i], $uploadFile[$i])) {
echo "Subido correctamente <br>";
} else {
echo "Error ".$_FILES['file']['error'][$i]."<br>";
}
} else {
echo "Formato no permitido <br>";
}
}
} else {
echo "No has enviado ningún archivo!";
}
?>

Si la subida se ha realizado correctamente, se crea un array de tipos permitidos, según el cual se comprueba si los formatos son correctos. Luego, si la validación se ha superado, con la función move_uploaded_file el archivo se mueve del almacenamiento temporal al directorio especificado.

Este código, aunque funciona, es bastante primitivo y debe ampliarse:

  • eliminar los caracteres especiales y los espacios del nombre, y lo ideal es asignar el nombre uno mismo;
  • registrar la información en la base de datos;
  • comprobar el tamaño del archivo;
  • si es una imagen, se puede comprimir, etc.

En general, conviene realizar algunas comprobaciones adicionales para que los archivos no representen una amenaza para el sitio web y no queden sin usar.

Subir archivos a un sitio web con AJAX

Si añadimos las posibilidades de JavaScript, el formulario puede ser más útil y atractivo. Por ejemplo, se pueden subir archivos a través de AJAX, y también se puede añadir una animación al arrastrar:

var fileDrop = document.getElementById('file-drop'); //Obtenemos los objetos
var loadButton = document.getElementById('load-button');
var messageDiv = document.getElementById("message-div");
function dragOver() {//Cambiamos el marco cuando el usuario arrastra un archivo al campo
fileDrop.setAttribute('class','file-drop file-drop_dragover');
}
function dragOut() {//Restauramos el marco normal
fileDrop.setAttribute('class','file-drop');
}
function closeMessage() {//Cerramos el mensaje
messageDiv.setAttribute('class','message-div message-div_hidden');
messageDiv.innerHTML = '';
}
function showMessage(data = 0) {//Mostramos un mensaje de que la subida ha comenzado o ha terminado
if(data == 0) {
data = "Subiendo...";
} else {
setTimeout(closeMessage,4000);
}
messageDiv.innerHTML = data;
messageDiv.setAttribute('class','message-div');
}
function uploadFile() { //Subimos el archivo
dragOut();
var files = this.files;
var data = new FormData();
for(var i = 0; i < files.length; i++) { //Añadimos al array de datos los archivos
data.append(i, files[i]);
}
showMessage(); //Mostramos un mensaje de que la subida ha comenzado
$.ajax({
url: "/file.php", //Enlace al gestor
type: 'POST', //Método de transmisión
data: data, //Array con los archivos
cache: false, //Hay que especificar false
processData: false, //Hay que especificar false
contentType: false, //Hay que especificar false
success: function (data) {//En caso de éxito, mostramos un mensaje con el resultado del trabajo y limpiamos el campo
showMessage(data);
fileDrop.value = null;
}
});
}
//Especificamos los eventos para llamar a las funciones
fileDrop.addEventListener('dragover',dragOver);
fileDrop.addEventListener('dragleave',dragOut);
fileDrop.addEventListener('change',uploadFile); //Enviamos los archivos inmediatamente después de que se hayan seleccionado

Primero, el campo se pasa al objeto fileDrop, y luego se crean las funciones dragOver, dragOut, showMessage y closeMessage: las dos primeras cambian el marco para la etiqueta <input>, y las segundas muestran y ocultan el mensaje. Luego se crea la función uploadFile, que envía el archivo a través de AJAX.

La función obtiene los archivos con el objeto FormData, luego muestra un mensaje de que la subida ha comenzado y comienza a enviar el archivo.

Debido al método de transmisión modificado, la estructura del súper array $_FILES cambia ligeramente: ahora primero se especifica el índice del archivo y luego la celda necesaria.

<?php
if(isset($_FILES)) {
$uploadDir = "files/";
$allowedTypes = array('image/jpeg','image/png','image/gif');
for($i = 0; $i < count($_FILES); $i++) {
$uploadFile[$i] = $uploadDir . basename($_FILES[$i]['name']);
$fileChecked[$i] = false;
echo $_FILES[$i]['name']." | ".$_FILES[$i]['type']." — ";
for($j = 0; $j < count($allowedTypes); $j++) {
if($_FILES[$i]['type'] == $allowedTypes[$j]) {
$fileChecked[$i] = true;
break;
}
}
if($fileChecked[$i]) {
if(move_uploaded_file($_FILES[$i]['tmp_name'], $uploadFile[$i])) {
echo "Subido correctamente <br>";
} else {
echo "Error ".$_FILES[$i]['error']."<br>";
}
} else {
echo "Formato no permitido <br>";
}
}
} else {
echo "No has enviado ningún archivo!";
}
?>

Así es como funciona la subida de archivos con AJAX:

Captura de pantalla que muestra una interfaz de usuario simple para subir archivos con AJAX. Se muestra un botón "Elegir archivos"
Ejemplo de cómo mostrar la selección de archivos múltiples antes de la subida con AJAX.

Conclusión

A partir de aquí, puedes hacer lo que quieras con los archivos:

  • usar imágenes en artículos y como fotos de perfil;
  • añadir un reproductor que reproduzca vídeos y audio;
  • crear un editor de texto, gráfico o de audio/vídeo;
  • permitir la descarga de archivos mediante un enlace, etc.

Un claro ejemplo es nuestra web amiga: subirfoto.es

Categorizado en:

Programación,