Recientemente me han pedido que añada en una de las webs que administro un enlace (de manera artesanal) para poder descargar un documento concreto.
Bien… la mayoría pensaréis que es algo trivial, porque seguramente uso alguno de los múltiples cms que existen en el mercado (y no os equivocáis), que seguro implementa de core o mediante algún sencillo plugin… Y es totalmente cierto. Pero, como os planteaba en la primera línea, me lo han pedido de forma “artesanal”.
En fin, no le demos mas vueltas, porque no tiene mucho sentido.
Sin más preámbulos, os dejo un código escrito en php que hará las delicias de los mas necesitados.
<?php // accepted file extensions $extensions = array("pdf","mp3","zip","rar"); // file name to download $file = $_GET["file"]; // file size $size = filesize($file); // Prevent go throught directories if(strpos($file,"/")!==false){ die("Permission denied to change directory, please, especify only a file name"); } // test the file estension $ftmp = explode(".",$file); $fExt = strtolower($ftmp[count($ftmp)-1]); if(!in_array($fExt,$extensions)){ die("ERROR: File extension not recognized: $fExt"); } // if it was ok, let's download it header("Content-Transfer-Encoding: binary"); header("Content-type: application/octet-stream"); header("Content-Disposition: attachment; filename=$file"); header("Content-Length: $size"); $fp=fopen("$file", "r"); fpassthru($fp); ?>
Expliquemos un poco las líneas mas importantes
- 3 : definimos un array de extensiones de fichero aceptadas (en este caso, pdf, mp3, zip, rar…)
- 6 : obtenemos de la request (query string) el nombre del fichero a descargar, mediante el parámetro file
- 9 : validamos el parámetro, y no permitimos que se especifiquen nombres de fichero que contengan cambios de directorio, para prevenir descargas no deseadas (si encontramos una / terminamos con un error)
- 14 : extraemos la extensión del fichero solicitado
- 15 : eliminamos el . de la extensión y lo convertimos a minúsculas, para asemejarlo al array de aceptados
- 16 : comprobamos que la extensión existe en el array de extensiones aceptadas, y en caso contrario, finalizamos con un mensaje de error adecuado
- 21 : modificamos la cabecera de respuesta html para indicar que contiene un binario
- 22 : añadimos a la cabecera html el nombre del fichero a descargar
- 23 : abrimos el fichero como lectura (aquí es donde podemos comprobar que el fichero debe estar en la ruta actual en la que se encuentra esta misma página php, aunque si deseais cambiar el directorio de almacenamiento de los ficheros, es tan fácil como añadir la ruta delante del $file
- 24 : se escribe el fichero en la response de la página
Como véis, el procedimiento es muy sencillo:
- Subid vuestro fichero al directorio desde dónde descargaréis los ficheros
- Subid vuestro código al directorio desde dónde descargaréis los ficheros (este es el caso sencillo, pero como os he explicado sobre la línea 23, la ruta podría variarse sin problemas)
- Añadid un link a vuestra imagen o texto de descarga, (supongamos que yo tengo el tinglado montado en /files) del tipo: /files/download.php?file=nombre_fichero
Y ya lo tenéis.
Fácil, ¿verdad?
Espero haberos sido de ayuda!
Jordi
Buenos dias estoy intentando hacer esto para descargar la sesión de 150mb de la página de un cliente pero solo me descarga la mitad del archivo.
¿Que solución hay? Si lo pongo como RAR lo descarga completo, pero el cliente quiere que se descargue en mp3 directamente.
Un saludo
Buenos días, Alejandro.
Quizá el problema sea por varios motivos. Añade las siguientes líneas a la cabecera:
$size = filesize($file);
header("Content-Transfer-Encoding: binary");
header("Content-Length: $size");
Con esto lo que haremos será decirle que debe descargar un fichero binario, y por otro lado, añades el tamaño esperado. Quizá esté cortando el flujo porque no sabe cuánto pesa en realidad y evita saturarse (temas de navegador).
Espero te sirva. Dime qué tal.
Jordi
Me sirvió muchas gracias.
Me alegro mucho, gracias por comentar 🙂
Un saludo.
Hola Jordi
Me sirivio mucho, excelente aporte solo una consulta mas:
Despues de haber hecho la descarga, hay alguna forma de avisarle al usuario con un mensaje por Ej. Ud hizo la descarga del archivo … en el directorio ….
gracias
Luis
Hola Luís, gracis por tu comentario. Me alegro de que te haya sido útil.
Respondiendo a tu pregunta, no es posible controlarlo desde la página o código PHP, ya que el proceso de descarga es tarea del navegador, y nosotros ya no tenemos el control una vez comienza la descarga. Al menos no se me ocurre cómo hacerlo ahora mismo. Lo siento!
Jordi
Hola,
Quisiera saber como puedo descargar una tabla de mysql comprimida, muchas gracias
Hola Fercho, gracias por tu comentario.
No entiendo qué es lo que necesitas exactamente. Los datos comprimidos?
Neceistas quizá algo así? >>> https://voragine.net/weblogs/como-hacer-copias-de-seguridad-de-bases-de-datos-con-php-y-mysqldump