En algunas ocasiones necesitamos que un archivo 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.
Veremos dos formas de hacerlo, una básica y otra más avanzada pero también más segura.
Forzar descarga (Básico)
Primero creamos un archivo llamado, por ejemplo, “download.php“, en el que tendríamos que colocar 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 (para descargar).
Y para crear el enlace pondríamos:
<a href="download.php?file=imagen.jpg">Descargar</a>
Forzar descarga (Seguro)
Ahora veamos cómo hacer el script más seguro.
Por un lado, el script anterior permite descargar cualquier archivo del servidor. Por ejemplo, cualquiera podría descargar nuestro archivo ‘index.php‘ con solo cambiar la ruta de descarga por “download.php?file=../index.php“.
Además, vamos a comprobar previamente que el archivo existe, para evitar errores en caso de que el archivo no se encuentre en el servidor.
<?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.");
}
?>Mediante la función basename() hacemos que se devuelva únicamente el nombre del archivo, eliminando cualquier ruta, para que no se puedan descargar archivos de otras carpetas del servidor.
Con la variable $root hemos definido la carpeta donde se encuentran los archivos para descargar.