Generar descarga de archivos con PHP

En este artículo vamos a ver una forma de generar la descarga de archivos con PHP. No estamos hablando de archivos que pueden ser descargados mediante un simple enlace <a>. Sinó de archivos generados de forma dinámica mediante una consulta a Mysql y exportarlos a excel, html, txt, etc.

Para conseguirlo utilizaremos un archivo PHP que podemos llamar descargas.php y que recibirá como parámetro el recurso a descargar.

https://mi_dominio.com/descargas.php?r=recurso_a_descargar

El archivo descargas.php es el encargado de generar y crear la descarga del recurso pasado como parámetro. La diferencia con un enlace tipo <a> es que dentro podemos programar todo tipo de código PHP, pero su salida consistirá únicamente en generar la descarga del recurso solicitado.

Observa que estamos hablando de recuros, como puede ser un resultado Mysql en forma de tabla HTML. Esto nos obliga a comprobar si se trata de un usuario registrado, si tiene acceso a este recurso, generar el contenido de forma dinámica y proceder a su descarga.

Generar descarga con PHP

<?php
session_start();
if (!isset($_SESSION['ok'])) exit('Acceso no autorizado ...');
if (!isset($_GET['r'])) exit('Recurso no solicitado ...');
switch ($_GET['r']) {
  case  '1' : $file = crear_archivo();
              $fileName = 'archivo.txt';
              break;
  case  '2' : $file = exportar_datos(); 
              $fileName = 'exportar.xls';
              break;
  case  '3' : $file = descargar_archivo();
              $fileName = 'descarga.html';
              break;
  default   : exit('Recurso no encontrado ...');
}
$file = utf8_decode($file);
$fp = fopen($fileName, "w");
fwrite($fp, $file);
fclose($fp);
header("Content-Transfer-Encoding: binary");
header("Content-Type: application/octet-stream");
header("Content-Disposition: attachment; filename= $fileName");
readfile($fileName);
unlink($fileName);
?> 

Este código básico genera un archivo descargable según el recurso solicitado con el parámetro $_GET[‘r’]. Es importante observar los filtros que podemos añadir para dotar de seguridad a nuestra web:

  • session_start() Podemos o debemos crear sesiones para saber si los usuarios se encuentran identificados en nuestra web y tienen permitido el acceso a los recursos preguntando por las variables de $_SESSION
  • $_GET[‘r’] Debemos asegurarnos de que el recurso se solicita de forma correcta comprobando que existe el parámetro
  • switch($_GET[‘r’]) Aquí filtramos el valor del parámetro y asignamos a la variable $file el recurso solicitado. He añadido diversos tipos de funciones posibles pero todas ellas deben devolver los datos del recurso solicitado. En función de los datos asignaremos un nombre y tipo de archivo en $fileName, según nos convenga. Sería un error que $_GET[‘r’] enlazara directamente a archivos físicos del servidor. Un usuario malintencionado podría modificar la URL para acceder a cualquier archivo de nuestra web

Estos filtros son MUY IMPORTANTES para evitar que cualquiera pueda descargar recursos de nuestro servidor y evitar que incluso usuarios autorizados puedan manipular la URL de descargas.

Ahora vamos a trabajar con los datos obtenidos del recurso solicitado, supongamos que nuestras variables $file y $fileName contienen los siguientes datos de mi web Gestor Ligas.

$fileName = 'listado.xls';
$file = '
<table class="table">
<tr>	
<th>#</th>	
		<th>Promotor</th>												
		<th>Ligas</th>					
		<th>Torneos</th>	
		<th>Equipos</th>	
		<th>Jugadores</th>													
	</tr>		
	<tr>
		<td>1</td>
		<td><a class="link" title="Gestor Ligas Demo" href="https://gestorligas.com/promotor-1/">Gestor Ligas Demo</a></td>
		<td>8</td>	
		<td>1</td>	
		<td>48</td>	
		<td>0</td>																				
	</tr>
	<tr>
		<td>8</td>
		<td><a class="link" title="Educación Física" href="https://gestorligas.com/promotor-25414/">Educación Física</a></td>
		<td>4</td>	
		<td>2</td>	
		<td>5</td>	
		<td>20</td>																				
	</tr>		
	<tr>
		<td>13</td>
		<td><a class="link" title="Johnnie Portilla Zuñiga" href="https://gestorligas.com/promotor-13153/">Johnnie Portilla Zuñiga</a></td>
		<td>2</td>	
		<td>1</td>	
		<td>18</td>	
		<td>88</td>																				
	</tr>
</table>';

Uno de los problemas más habituales a la hora de importar/exportar datos es mostrar correctamente los caracteres como acentos y eñes. Usando utf8_decode() y utf8_encode() podemos filtrar los datos según nos convenga.

$file = utf8_decode($file);

Una vez tratados los datos de nuestra variable $file procedemos a escribirlos en un archivo físico del servidor de manera temporal. Se podría hacer la descarga directamente, pero algunos servidores no lo permiten por temas de seguridad.

El nombre y extensión del archivo que vamos a guardar y descargar puede ser de cualquier tipo (txt, xls, html, etc), esto lo establecemos en la variable $fileName, para guardar el archivo simplemente ejecutamos estas instrucciones.

$fp = fopen($fileName, "w");
fwrite($fp, $file);
fclose($fp);

Ahora que tenemos el archivo guardado en el disco duro del servidor sólo nos falta proceder a su descarga. Como hemos dicho, podemos generar la descarga de archivos con PHP del tipo que sea (txt, xls, html, etc).

Para conseguirlo debemos modificar las cabeceras HTTP para indicar al navegador que se va a proceder a la descarga de un archivo de tipo indefinido y que sea la extensión del archivo quien determine las aplicaciones compatibles con él.

header("Content-Transfer-Encoding: binary");
header("Content-Type: application/octet-stream");
header("Content-Disposition: attachment; filename= $fileName");
readfile($fileName);
unlink($fileName);

Estas instrucciones indican al navegador que la transferencia será binaria y el tipo de archivo octet-stream (indefinido).

Para finalizar indicamos que se debe adjuntar (attachment) el archivo (filename) para su descarga. Procedemos a su lectura para iniciar la transferencia y justo después lo borramos del servidor.

En este caso hemos descargado una tabla HTML como un archivo EXCEL simplemente indicando el nombre y extensión listado.xls El resultado una vez abierto el archivo listado.xls en el EXCEL es el siguiente:

Descarga de archivo php a excel
Exportación de html a excel

Podemos ver que los acentos se han codificado correctamente, la distribución de la tabla HTML en la tabla EXCEL es idéntica, e incluso los enlaces <a> también se han generado en la tabla EXCEL. Sólo hay un problema que podemos encontranos alguna vez: EXCEL no permite la exportación de imágenes.

Motivos para descargar archivos con PHP

Hay muchas razones por las que añadir un generador de descargas con PHP, algunas ya se han comentado pero vamos a resumirlas.

  • Podemos convertir descargas.php en un generador de contenidos descargables útil y versátil
  • Generar contenido dinámico y descargable a través de un parámetro en la URL
  • Exportar consultas Mysql, tablas HTML, textos, etc como archivos descargables de nuestra web
  • Tener el contenido descargable siempre actualizado al generarse dinámicamente
  • Evitar tener multitud de archivos estáticos preparados para la descarga al crearse dinámicamente
  • Verificar los usuarios autorizados para la descarga de ciertos contenidos o recursos
  • Evitar la descarga de recursos o archivos no autorizados
  • Crear un historial de usuarios y recursos descargados. En este caso creando un registro en la DB con el usuario, recurso y fecha de descarga
  • Controlar la cantidad de bytes descargados por usuario, fecha o ip
  • Ocultar la ubicación de los recursos y archivos descargables de nuestro servidor
  • Un largo etcétera.

El archivo descargas.php tiene muchas posibilidades de programación y control de los recursos que queremos sean accesibles de forma dinámica en nuestra web.

Con un poco de imaginación, ensayo y error, podemos programar un potente gestor de recursos para generar la descarga de archivos con PHP.

Deja un comentario

A %d blogueros les gusta esto: