File Storage: Gestionar Archivos en Laravel (Públicos y Privados)

La gestión de archivos en proyectos backend es una necesidad súper común.

¿Alguna vez has tenido dificultad para almacenar y/o compartir archivos en tus proyectos Laravel?

Ahora verás que en realidad es muy sencillo.

¿En qué casos trabajamos con archivos?

  • Cuando nuestros usuarios suben imágenes o fotos de perfil
  • Para asociar a imágenes a productos de una tienda
  • Generando y compartiendo facturas
  • Exportando datos en archivos Excel, reportes de ventas, etcétera

File Storage

Laravel abstrae todo lo concerniente a almacenamiento de archivos en su integración llamada File Storage.

E incluye drivers para trabajar con archivos de manera local, pero también en la nube, por ejemplo con Amazon S3.

Mejor aún, es muy sencillo cambiar entre estas opciones.

De tal manera que nuestro servidor de producción y de desarrollo podrán usar diferentes configuraciones, pero el código será el mismo para ambos.

Cómo se configura

Para esto sólo necesitamos ir al archivo de configuración ubicado en config/filesystems.php.

Dentro de este archivo podemos configurar los llamados "disks".

Cada "disk" declarado se asocia con un driver y determina dónde se van a almacenar nuestros archivos.

  • El driver local interactúa con los archivos almacenados en nuestro propio proyecto Laravel.
  • Y el driver s3 usa el servicio S3 de Amazon.

Dónde almacenar nuestros archivos

Si tu proyecto a penas está empezando y no vas a usar un servicio como S3, lo más recomendable es usar la carpeta storage.

Es decir, es posible almacenar tus archivos directamente sobre la carpeta public, pero no es lo ideal.

Al guardar tus archivos dentro de storage, puedes decidir si quieres que sean públicos o privados.

Cómo usar la clase Storage

Esta clase fachada permite guardar archivos fácilmente:

Storage::put('pdf/nombre_archivo.pdf', $contenido);
  • El primer argumento indica dónde se va a guardar, y el segundo, qué se va a guardar.
  • Cuando no se indica el disco, se usará el que está declarado como default en el archivo de configuración.

Para leer archivos, puedes usar:

Storage::get('pdf/nombre_archivo.pdf');

Ejemplo: PDFs con acceso privado

Vamos a crear un disco para guardar archivos de forma privada.

Y en este ejemplo, vamos a guardar archivos PDF, que sólo los usuarios con los permisos adecuados podrán ver.

Para esto, en el arreglo disks (que está en config\filesystems.php), vamos a agregar el siguiente disco:

'disks' => [
    'private_files' => [
        'driver' => 'local',
        'root' => storage_path('app/private'),
    ],
    // ...
],
// ...

A nuestro disk le hemos puesto el nombre private_files.

Dentro del mismo archivo de configuración, en la parte superior encontramos el disco por defecto:

'default' => env('FILESYSTEM_DRIVER', 'private_files'),

Como puedes ver, el valor se lee desde la variable FILESYSTEM_DRIVER.

Sólo debemos ir a nuestro archivo .env y declarar dicha variable (o actualizar su valor si ya la tenemos).

FILESYSTEM_DRIVER="private_files"

De tal manera que en nuestro controlador, cuando un usuario suba un archivo, tendremos lo siguiente:

if ($request->file('pdf')) {
    $uploadedFile = $request->file('pdf');
            
    $shortName = Str::random(6) . '.pdf';
    $filePath = '/pdf/' . $shortName;
            
    Storage::put($filePath, file_get_contents($uploadedFile));
}
  • Nuestra variable $filePath determina dónde se va a guardar nuestro archivo y con qué nombre.
  • El método file_get_contents obtiene el contenido del archivo subido.

Si quieres que Laravel genere el nombre del archivo por ti, también es posible.

En ese caso usarías: $assignedPath = Storage::put($folderPath, $uploadedFile);

Puedes guardar en tu base de datos el path hacia el archivo, o si la carpeta destino es estándar, sólo el nombre del archivo.

Luego, puedes definir una ruta para que tus usuarios accedan a sus archivos.

Y tu controlador se vería más o menos de esta forma:

class FileController extends Controller
{
    public function __construct()
    {
        $this->middleware('auth');
    }
        
    public function show($shortName)
    {
        $pdf = DocumentFile::where('short_name', $shortName)->firstOrFail();
                
        $hasAccess = UserPermission::where('user_id', auth()->id())->where('folder_id', $pdf->folder_id)->exists();
        
        if ($hasAccess) {
            return Storage::download('pdf/' . $shortName);
        }

        return back();
    }

    // ...
}

Sobre este ejemplo:

  • El middleware auth asegura que sólo usuarios que han iniciado sesión puedan acceder a los PDF.
  • El modelo DocumentFile representa cada PDF subido al sistema.
  • El modelo UserPermission determina el permiso que tienen los usuarios respecto a las carpetas.
  • Esto lo puedes reemplazar con la lógica de tu aplicación.

Lo importante es que, si el usuario tiene los permisos suficientes, puedes generar la descarga del archivo usando:

return Storage::download($filePath);

Es decir, debes indicar la carpeta y el nombre del archivo, de la misma manera que usamos put para determinar dónde subir.

# laravel # php # eloquent

Logo de Programación y más

Comparte este post si te fue de ayuda 🙂.

Regístrate

Accede a todos los cursos, y resuelve todas tus dudas.

Cursos Recomendados

Imagen para el curso Aprende Laravel

Aprende Laravel

Aprende Laravel desde cero y desarrolla aplicaciones web reales, en tiempo récord, de la mano de Laravel.

Iniciar curso
Imagen para el curso Laravel Upgrade

Laravel Upgrade

Actualiza tus proyectos desde cualquier versión hasta la última versión estable de Laravel.

Iniciar curso
Imagen para el curso Laravel y Vue

Laravel y Vue

Desarrollemos un Messenger! Aprende sobre Channels, Queues, Vuex, JWT, Sesiones, BootstrapVue y mucho más.

Iniciar curso

Espera un momento ...

¿Te gustaría llevar mi curso de Laravel, gratis?

Sólo debes ingresar tus datos: