Subir archivos a un servidor desde nuestra web

Permitir que los usuarios de nuestra web puedan enviar archivos directamente al servidor es una utilidad muy versátil que puede ser clave en multitud de procesos.

Algunas de las funcionalidades que podemos implementar gracias a la subida de ficheros por parte de los usuarios son:

1
Incluir imágenes en artículos o comentarios generados por los usuarios.
2
Subida de archivos CSV para suministrar y procesar gran cantidad de datos.
3
Alojar en el servidor archivos del usuario como currículums y documentación de todo tipo.
4
Personalización de páginas de perfil mediante imágenes.
5
Gestores de información en los que sea necesario indicar una imagen.

EJEMPLO: Gestor de productos de una tienda online.

Envío de imágenes al servidor

Un usuario quiere cambiar la foto de perfil en una red social.

Para ello deberá enviar un archivo .jpg al servidor que la almacenará para poder mostrarla en la web.

Del mismo modo que los parámetros GET y POST son un fundamento básico de la web 2.0, ya que permiten al usuario la creación de contenido, la subida de archivos, al ser un suministro de información por parte de los usuarios a la web, también lo es.

Redes sociales como Facebook, Instagram o YouTube, entre muchas otras, no podrían existir sin la posibilidad de que el usuario subiese archivos.

La subida de archivos, no es una característica exclusiva de PHP, todos los lenguajes de programación web dispondrán de métodos para tratar las subidas de archivos.

La forma de envío de archivos desde el lado del cliente, será idéntica indiferentemente del lenguaje que usemos en el servidor. Si aprendemos un lenguaje de programación web distinto a PHP, simplemente deberemos aprender cómo recuperar los archivos enviados.

Formulario de envío de archivos

Como sucede con en envío de parámetros, para que un usuario pueda subir archivos al servidor, necesitamos crear un formulario HTML en nuestra página web.

Este formulario tiene que contar con tres requisitos para que se pueda realizar el envío de archivos:

input
En HTML, disponemos de un tipo de campo especialmente diseñado para el envío de archivos. Su sintaxis es la siguiente:



Su apariencia por pantalla es similar a la siguiente:



Este tipo de campo, permitirá al usuario seleccionar un archivo de su ordenador o dispositivo.

Para el envío de archivos, evidentemente debemos tener al menos un campo de este tipo.
method
El método de envío del formulario cuando queremos subir archivos debe ser obligatoriamente POST:

enctype
Para habilitar el envío de archivos, debemos establecer un atributo adicional en la etiqueta form:



Al indicar este atributo, establecemos que el campo de tipo file, debe enviar el archivo al servidor. Si no lo establecemos, enviará únicamente el nombre del archivo y no podremos recuperar su contenido.

Vamos a ver un ejemplo completo de formulario de envío de archivos:

El siguiente fragmento de código HTML
Se visualiza en el navegador de la siguiente forma:
 

Recuperación y tratamiento del archivo enviado

Una vez que el usuario ha enviado el archivo al servidor, utilizaremos un array especial de PHP para recuperar el archivo y su información. Su sintaxis es la siguiente:

Este array es multidimensional y tiene varias componentes con información del archivo:

Nombre del archivo enviado.
Ruta temporal donde se ha almacenado el archivo.
Tipo MIMESon convenciones dirigidas al intercambio a través de Internet de todo tipo de archivos. Mediante una serie de cadenas de texto estandarizadas, especifican de qué tipo es un archivo determinado. del archivo. Lo utilizaremos para identificar el tipo del archivo.
Tamaño en bytes del archivo.

print_r de $_FILES

Si hacemos un print_r de $_FILES tras el envío de un archivo, nos encontraremos una estructura como la siguiente:

Por defecto, el archivo se sube a un directorio temporal, pero es muy frecuente que queramos guardar este archivo de forma permanente. Para ello utilizaremos la siguiente sintaxis:

será la ruta donde se guardará el archivo. Podemos utilizar tanto rutas relativas (partiendo del directorio en el que se encuentra el script de PHP) como absolutas. 

Limitaciones en la subida de archivos

Ya que el usuario podría subir archivos de gran tamaño, haciendo que nuestro servidor se colapsase si no dispone de los recursos adecuados, existen varios parámetros de configuración de PHP que limitan el tamaño y el tiempo de subida.

Podemos modificar los valores de estos parámetros desde nuestro php.ini.

max_file_uploads 20 Número máximo de ficheros que se pueden subir de forma simultánea.
upload_max_filesize 2M Tamaño máximo de cada fichero subido.
post_max_size 8M Tamaño máximo del conjunto de datos enviados mediante POST.
max_input_time 60 Tiempo máximo en segundos de envío de datos al servidor.

Aspectos de seguridad

Debemos tener especial cuidado a la hora de gestionar los archivos que un usuario sube a nuestro servidor. Si permitimos que los usuarios suban cualquier tipo de archivo al servidor, podrían hacernos llegar archivos ejecutables con virus o códigos malintencionados.

Si necesitásemos guardar archivos de este tipo, siempre debemos hacerlo en una carpeta que no sea pública, ya que de lo contrario, el usuario podría lanzar la ejecución de cualquier programa.

Ataque clásico mediante envío de archivos

  • Tenemos un formulario en nuestra web http://www.example.com/ con una subida de archivos.
  • Un usuario nos envía un archivo llamado hack.php y nosotros lo guardamos en la carpeta pública "archivos".
  • El usuario llama a la siguiente dirección http://www.example.com/archivos/hack.php y ejecuta todas las instrucciones de PHP contenidas en él.
  • El archivo PHP lee el contenido de todos nuestros archivos PHP y muestra el código por pantalla exponiendo la contraseña de nuestra base de datos.
  • El usuario puede acceder ahora a nuestra base de datos y recuperar o modificar toda la información que desee.

Al ejecutar un código PHP, el usuario puede realizar cualquier acción, pudiendo incluso borrar o modificar nuestro código fuente.

Por lo tanto, las precauciones que siempre deberemos tomar a la hora de hacer una subida de archivos son:

1
Validar todas las extensiones de los archivos subidos y permitir únicamente las que vayamos a tratar.

EJEMPLO: Si el usuario va a subir una imagen, solo permitiremos archivos con extensión .jpg, .jpeg, .gif o .png
2
Si vamos a alojar ficheros con todo tipo de extensiones, guardar los archivos en un directorio que no esté en la carpeta pública.

EJEMPLO: Creamos una carpeta al lado de la carpeta pública (carpeta htdocs en XAMPP) llamado archivos y referenciamos las rutas de move_uploaded_file a dicha carpeta.