5.19 Almacenamiento de Archivos en Laravel (Storage)
5.19.1 Introducción
-
En Laravel, los ficheros se pueden almacenar en diferentes ubicaciones, pero las más comunes son
publicystorage. -
public: Los ficheros almacenados en esta carpeta son accesibles directamente desde el navegador. Esto es útil cuando necesitamos que los archivos sean accesibles públicamente (por ejemplo, imágenes, documentos, etc.). -
storage: Los ficheros almacenados aquí no son accesibles directamente desde el navegador, lo que brinda una mayor seguridad para archivos privados o protegidos. Sin embargo, es necesario utilizar un enlace simbólico para poder acceder a ellos desde el navegador. -
En este tema, vamos a explorar cómo almacenar archivos de forma segura y cómo configurar Laravel para manejar estos ficheros.
5.19.2 Configuración de Laravel para Storage
Laravel proporciona una configuración simple para manejar los archivos. Por defecto, Laravel utiliza el disco local para almacenar los archivos en el directorio storage/app. Sin embargo, Laravel permite configurar otros discos para almacenar los archivos en ubicaciones remotas, como Amazon S3, FTP, Google Cloud Storage, entre otros.
Configuración del disco en config/filesystems.php
Por defecto, Laravel está configurado para usar el disco local para almacenar archivos, pero podemos modificarlo o agregar otros discos. En config/filesystems.php, encontramos algo como esto:
config/filesystems.php
local: Define el almacenamiento local enstorage/app.public: Define el almacenamiento enstorage/app/public. Laravel lo hace accesible desde el navegador usando un enlace simbólico a través dephp artisan storage:link.
5.19.3 Crear la Aplicación para Subir Archivos
Paso 1: Crear la Migración para la Tabla files
Comenzamos creando una migración para la tabla files, donde almacenaremos el nombre, la descripción y la URL del archivo cargado.
Ejecutamos el siguiente comando para crear la migración:
Editamos la migración en database/migrations/YYYY_MM_DD_create_files_table.php:
create_files_table.php
Luego, ejecutamos la migración para crear la tabla:
Paso 2: Crear el Modelo File
Creamos el modelo File para trabajar con esta tabla:
El modelo File.php quedará así:
File.php
Paso 3: Crear el Controlador para Gestionar Archivos
Ahora, creamos el controlador que gestionará los archivos. Ejecutamos:
En el controlador FileController.php, implementamos los métodos para mostrar el formulario de carga, almacenar el archivo y mostrar los archivos almacenados. En esta primera versión vamos a guardar los archivos en una carpeta pública de manera que sean accesibles desde el navegador.
FileController.php
Creamos un Request para validar los datos de entrada. Ejecutamos:
Enapp/Http/Requests/FileRequest.php, definimos las reglas de validación:
FileRequest.php
En este caso, estamos validando que el archivo sea de tipo jpg, png, jpeg o pdf y que no supere los 2MB. También validamos que la descripción sea un texto con un máximo de 255 caracteres.
Paso 4: Crear las Rutas para las Operaciones
En routes/web.php, agregamos las rutas necesarias para index, create y store:
Paso 5: Crear las Vistas para Subir y Ver Archivos
Layout layouts/app.blade.php
Comencemos creando un layout básico para nuestras vistas. En resources/views/layouts/app.blade.php, añadimos:
app.blade.php
Vista files/create.blade.php
En resources/views/files/create.blade.php, creamos el formulario para cargar archivos:
create.blade.php
Vista files/index.blade.php
En resources/views/files/index.blade.php, mostramos los archivos cargados:
index.blade.php
Paso 6: Probar la Carga de Archivos
- Accede a
http://localhost/myfiles/createy sube un archivo. - Accede a
http://localhost/filespara ver los archivos cargados.
5.19.4 Cambiar de public a storage
Por defecto, los archivos cargados se almacenan en la carpeta public. Para evitar que los archivos sean accesibles directamente desde el navegador, podemos moverlos a la carpeta storage.
Paso 1: Crear un enlace simbólico
Para crear un enlace simbólico entre la carpeta storage y public (para poder acceder a los archivos de forma controlada), ejecuta:
Paso 2: Cambiar la ruta en la migración y el código
A diferencia de la práctica anterior ahora vamos a almacenar los archivos en storage/app/private. Para ello, tenemos que modificar el controlador, ya que ahora no moveremos los archivos a public, sino que los almacenaremos directamente en storage.
Modifica el método store en el controlador para almacenar los archivos en storage en lugar de public:
Esto guardará los archivos en storage/app/private/files en lugar de en public/files. Por lo tanto ya no tenemos acceso a él desde la vista y si la cargamos veremos que este último fichero no se carga.
5.19.5 Permitir acceso a archivos almacenados en storage
La primera manera de poder acceder a los archivos es almacenarlos en la carpeta storage\app\public. Para ello, modificamos el método store en el controlador para almacenar los archivos en storage en lugar de public:
Si volvemos a subir el fichero ahora veremos que se encuentra en la carpeta storage/app/public/files. Pero, es cierto, que seguimos sin ver el fichero en la web. Esto es por dos motivos:
- El primero es que no hemos creado el enlace simbólico entre
storageypublic. - El segundo es que no hemos modificado la vista para que cargue el fichero desde
storage.
Vamos a ver cómo solucionarlo.
Paso 1: Crear el enlace simbólico
Ejecuta el siguiente comando para crear un enlace simbólico que permita acceder a los archivos almacenados en storage desde public:
public que apunta a la carpeta storage/app/public.
Modificamos el archivo .env para cambiar el disco de almacenamiento por defecto a public:
storage/app/public. Además a esta carpeta le hemos dado un enlace simbólico en public/storage. Para que sean accesibles desde el navegador.
Paso 2: Modificar la vista para cargar el fichero
Ahora, en la vista files/index.blade.php, modificamos la forma de cargar el fichero:
Ahora los ficheros que subamos se almacenarán en storage/app/public/files y serán accesibles desde el navegador a través de public/storage/files. De esta forma estarán almacenados de forma segura y no serán accesibles directamente desde el navegador.
5.19.6 Almacenarminto de archivos en storage
Comenzamos por hacer un reset a la base de datos y crear la tabla files de nuevo:
Y vaciamos las carpetas storage/app/public y storage/app, para asegurarnos de que no hay archivos duplicados y poder verexactamente lo que subimos.
Comenzamos por subir un par de imagenes y veremos que gracias al enlace simbólico que hemos creado, los archivos que subamos a storage/app/public serán accesibles desde el navegador a través de public/storage.
Ahora por ejemplo si queremos guardar un archivo en un disco diferente al public, podemos hacerlo de la siguiente manera:
Esto guardará el archivo en storage/app/files. Si queremos acceder a este archivo desde el navegador, no podremos hacerlo directamente, ya que no hemos creado un enlace simbólico para esta carpeta.
Para poder ofrecer la descarga en el controlador podemos hacer lo siguiente:
Esto nos dará la ruta completa del archivo en el sistema de archivos.
Con todo esto, vamos a eliminar la etiqueta img que hemos añadido antes y vamos a añadir un enlace para descargar el archivo. Para ello, en la vista files/index.blade.php, añadimos lo siguiente:
Necesitamos la ruta para descargar el archivo. Para ello, añadimos la siguiente función en el controlador:
Y por último, añadimos la función download en el controlador:
download
5.19.7 Opción para eliminar el Archivo
Para eliminar el archivo, podemos añadir un botón de eliminar en la vista files/index.blade.php:
Eliminar archivo
Esto generará un formulario que enviará una solicitud DELETE al controlador para eliminar el archivo. En el controlador, añadimos la siguiente ruta:
Y en el controlador, añadimos la siguiente función:
destroy
Prueba la funcionalidad de eliminar archivos y asegúrate de que se eliminan correctamente tanto de la base de datos como del sistema de archivos.
5.19.7 Ejercicio Propuesto: Clientes
Objetivo: Crear una tabla clientes y permitir que el usuario suba un PDF (DNI) y una imagen (perfil) al crear el cliente.
Pasos:
- Crear la migración para la tabla clientes.
- Crear un formulario que permita subir tanto un PDF como una imagen.
- Modificar la vista para mostrar las imágenes y enlaces de descarga del PDF.
- Implementar la funcionalidad de edición y actualización de estos archivos.
Paso 1: Crear la migración para la tabla clientes
Primero, creamos la migración para la tabla clientes, que almacenará el DNI (PDF) y la imagen de perfil.
Ejecutamos el siguiente comando para crear la migración:
En la migración generada, editamos database/migrations/YYYY_MM_DD_create_clients_table.php para definir los campos de la tabla:
create_clients_table.php
Después, ejecutamos la migración para crear la tabla en la base de datos:
Paso 2: Crear el Modelo Client
Ahora, vamos a crear el modelo para interactuar con la tabla clients.
Ejecutamos:
En el archivo generado app/Models/Client.php, agregamos lo siguiente:
Client.php
```php {linenums="1"} class Client extends Model { use HasFactory;
// Definir los campos asignables en masa
protected $fillable = ['name', 'email', 'dni', 'profile_image'];
}
```
Paso 3: Crear el Controlador para gestionar los clientes
Creamos el controlador que manejará las operaciones de creación y almacenamiento de los archivos. Ejecutamos:
En app/Http/Controllers/ClientController.php, agregamos lo siguiente:
ClientController.php
Paso 4: Crear las rutas para la creación y listado de clientes
En routes/web.php, agregamos las rutas para crear y listar los clientes:
Paso 5: Crear las vistas para crear y listar clientes
Vista clients/create.blade.php (Formulario para crear un cliente y subir archivos)
En resources/views/clients/create.blade.php:
create.blade.php
Vista clients/index.blade.php (Mostrar clientes y sus archivos)
En resources/views/clients/index.blade.php:
index.blade.php
Paso 6: Probar la funcionalidad
- Visita
http://localhost/clients/createy crea un nuevo cliente, subiendo el archivo DNI (PDF) y la imagen de perfil. - Después de crear el cliente, será redirigido a
http://localhost/clientsdonde podrá ver el cliente creado junto con los enlaces para ver su DNI (PDF) y su imagen de perfil.
5.19.7 Cambiar de public a storage
Por defecto, los archivos se guardan en storage/app/public, lo que los hace accesibles desde el navegador. Sin embargo, para mejorar la seguridad, podemos moverlos a storage y crear un enlace simbólico.
Paso 1: Crear el enlace simbólico
Ejecuta el siguiente comando para crear un enlace simbólico que permita acceder a los archivos almacenados en storage desde public:
Paso 2: Cambiar las rutas de acceso a los archivos
En el controlador, cambia la ruta de los archivos de esta manera:
$profileImagePath = $request->file('profile_image')->store('profile_images', 'public');
$client->profile_image = $profileImagePath;
Y en la vista clients/index.blade.php, usa el método Storage::url() para generar la URL correcta de los archivos:
<a href="{{ Storage::url($client->dni) }}" target="_blank">Ver DNI (PDF)</a>
<img src="{{ Storage::url($client->profile_image) }}" alt="Profile Image" width="100">
Paso 3: Descargar el archivo
Para permitir que el usuario descargue los archivos, podemos agregar un enlace de descarga en la vista:
5.19.8 Resumen
- Hemos creado una tabla de clientes con campos para DNI (PDF) y imagen de perfil.
- Hemos implementado un formulario que permite subir ambos tipos de archivo y guardarlos en el almacenamiento de Laravel.
- Se ha utilizado
Storage::url()para generar las URLs de acceso a los archivos, tanto para visualizarlos como para permitir su descarga. - Se ha cambiado el almacenamiento de los archivos de
publicastoragepara mejorar la seguridad.