Link de descarga de archivos privados o temporales

Buenas drupaleros y bienvenidos a otro tutorial. En esta ocasión os explicaremos como poder crear un "sistema" para poder descargar archivos dentro de la carpeta privada o temporal.

El problema

Seguro que algunos de vosotros habéis usado alguna vez la carpeta privada o la careta temporal para alojar vuestros archivos. Sí, no solo de la carpeta publica vive el hombre! en ocasiones, generalmente por motivos de seguridad, necesitamos ocultar ciertos assets del usuario anónimo o general.

El problema viene cuando intentáis crear una enlace de descarga de alguno de esos archivos y siempre que tengáis bien configurado vuestro drupal, os debería de salir un mensaje de error de permisos o simplemente os da error al descargar el archivo.

Esto se debe a que drupal por defecto bloquea todo aquello que este dentro de la carpeta privada o temporal. A efectos prácticos estas dos carpetas tienen el mismo comportamiento con la única diferencia de que la carpeta temporal borra todo su contenido al ejecutarse el cron. Esto hace que a nivel conceptual se usen para diferentes comportamientos.

El hook responsable

En drupal, tanto en la versión 7 como la versión 8, existe un hook llamado "hook_file_download" el cual nos permite configurar este comportamiento y en este tutorial os voy a explicar como poder configurarlo, dado que la documentación oficial es un poco pobre al respecto.

Para ello, vamos a crear un nuevo permiso para poder controlar que usuarios pueden descargar estos archivos, En caso que queráis que cualquier persona se pueda descargar estos archivos, deberíais de plantearos si la carpeta privada es el lugar correcto.

Creando permisos

/* D7 ejemplo */
/**
 * Implements hook_permission();
 */
function nombre_del_modulo_permission() {
  return array(
    '[nombre de nuestro permiso]' => array(
      'title' => t('[EL titlo que aparecera en el apartado de permisos en la pagina de roles]'),
    ),
  );
}

No voy a entrar al detalle de como crear un nuevo permiso ya que no es el objetivo de este tutorial, simplemente recordad cambiar el texto "[..]" por el que se ajuste y sea claro en vuestro proyecto. 

Recordad que en Drupal 8 los permisos se configuran desde el *.permissions.yml de vuestro modulo.

Configurando el hook_file_download

/* D7 ejemplo */
/**
 * Implements hook_file_download().
 */
function nombre_del_modulo_file_download($uri) {
  $scheme = file_uri_scheme($uri); // Esta funcion esta deprecated para drupal 9 asi que ojo al usarla, para D8 recomiendo \Drupal\Core\File\FileSystem::uriScheme().
  $target = file_uri_target($uri);
  if ($scheme == 'temporary' && strpos($target, $folder_name ) && user_access('[nombre de nuestro permiso]') !== false ) {
    $info = file_get_mimetype($uri); return array('Content-Type' => $info['mime_type']); 
  } 
}
Como vemos el en código anterior lo que hacemos es básicamente comprobar varios puntos:

1. Comprobamos que el archivo este dentro de la carpeta que realmente queremos usar, podríamos usar "temporary" o "private" para la carpeta temporal y privada respectivamente.

2. Como norma general no deberíamos guardar todos los archivos dentro de la raíz de la carpeta temporal o privada yo os recomiendo crear una subcarpeta para cada tipo de archivo para poder estar organizado. De esta forma podremos filtrar también la carpeta donde se encuentra el archivo.

3. Comprobamos que el usuario que esta intentado acceder tiene permisos suficientes para poder descargar el archivo.

Para que os hagáis una idea si hiciéramos un dump de $uri nos devolvería algo como "temporary://nombre_carpeta/nombre_archivo.extension"

Nota: En caso de que el archivo sea una imagen podemos usar  "$info = image_get_info($uri);"

Creando el enlace de descarga

Este un ejemplo de muchos que podréis encontrar por internet, a mi personalmente me funciona muy bien y me gusta dejar a drupal que haga todo el trabajo.

$url = file_create_url($uri);
$options_download['attributes']['title'] = $nombre_del_archivo;
$options_download['attributes']['download'] = '';
$output = '<div><span class="file-download">' . l($nombre_del_archivo, $url, $options_download) . '</span></div>';

Este output nos generara un enlace listo para descargar nuestro archivo deseado.

Conclusión

Como veis, aunque no es algo sencillo, tampoco es un drama una vez entiendes la idea. He de decir que existen módulos contribuidos que hacen algo parecido a esto, incluso he encontrado alguno que otro que incluso permite gestionar permisos. 

Eso esta bien dado que usar módulos contribuidos es lo que "vende" drupal, pero de tanto en tanto es bueno bajar al código y poder hacer nuestro propio código y entender que es lo que pasa por debajo de drupal.

Espero que os haya gustado y ya sabéis compartir y comentar!

Total de votos: 22

Entradas relacionadas

Comentarios (0)

Deja un comentario