Forzar la descarga de archivos con PHP

 
 

En ocasiones necesitamos que el enlace a un archivo, que insertamos en una página web, sea para descargar y no para ser visualizado en el navegador. Esto se puede hacer utilizando una tecnología del lado del servidor, como puede ser PHP.

DOS formas de hacerlo

1. Método Básico
Creamos un archivo llamado, por ejemplo, descargar.php, en el que insertaremos el siguiente código:

<?php
$file = $_GET['file'];
header("Content-disposition: attachment; filename=$file");
header("Content-type: application/octet-stream");
readfile($file);
?>

Con “Content-disposition: attachment; filename=$file” indicamos que el archivo se debe mostrar como adjunto (attachment).

Para crear el enlace insertaremos, por ejemplo, el siguiente código:

<a href="descargar.php?file=archivo.txt">Descargar</a>

2. Método + Seguro
El script anterior, no sólo descarga el archivo indicado en el enlace, si no que además permite descargar cualquier archivo del servidor. Por ejemplo, cualquiera podría descargar nuestro archivo index.php con solo cambiar la ruta de descarga por descargas.php?file=../index.php.

Con el siguiente código, evitaremos lo anterior y además, comprobaremos que el archivo existe, para evitar errores en caso de que el archivo no exista.
Modificaremos el archivo descargas.php y sustituiremos todo su código por el siguiente:

<?php
 
if (!isset($_GET['file']) || empty($_GET['file'])) {
  exit();
}
$root = "archivos/";
$file = basename($_GET['file']);
$path = $root.$file;
$type = '';
 
if (is_file($path)) {
  $size = filesize($path);
 
  if (function_exists('mime_content_type')) {
    $type = mime_content_type($path);
  }
  else if (function_exists('finfo_file')) {
    $info = finfo_open(FILEINFO_MIME);
    $type = finfo_file($info, $path);
    finfo_close($info);
  }
 
  if ($type == '') {
    $type = "application/force-download";
  }
 
  // Definir headers
  header("Content-Type: $type");
  header("Content-Disposition: attachment; filename=$file");
  header("Content-Transfer-Encoding: binary");
  header("Content-Length: " . $size);
 
  // Descargar archivo
  readfile($path);
}
else {
  die("El archivo no existe.");
}
 
?>

La función basename() devuelve únicamente el nombre del archivo, eliminando cualquier ruta, para que no se puedan descargar archivos de otras carpetas del servidor.

Con la variable $root se define la carpeta donde se encuentran los archivos para descargar.
 
Referencias

Espero que este artículo os haya sido de utilidad. Si pensáis que podéis colaborar para mejorar este artículo, que hay algo erróneo en él o simplemente deseáis comentarlo, por favor, dejad vuestra opinión más abajo.
  Configuración de privacidad y de cookies.
Seguir J. Carlos:

Técnico Informático - Desarrollo Web - Administración de Redes

Técnico Informático. Desarrollo Web. Administración de redes.

Últimas publicaciones de

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.