- Introducción
- Configuración
- Obteniendo instancias del disco
- Retornando archivos
- Almacenando archivos
- Eliminando archivos
- Directorios
- Sistemas de archivos personalizados
Introducción
Laravel proporciona una poderosa abstracción del sistema de archivos gracias al genial paquete de PHP Flysystem de Frank de Jonge. La integración de Flysystem de Laravel proporciona drivers simples de usar para trabajar con sistemas de archivos locales y Amazon S3. Aún mejor, es maravillosamente simple cambiar entre estas opciones de almacenamiento de modo que la API permanezca sin cambios para cada sistema.
Configuración
La configuración del sistema de archivos está ubicada en config/filesystems.php
. Dentro de este archivo puedes configurar todos tus «discos». Cada disco representa un driver de almacenamiento y una ubicación de almacenamiento en particular. Configuraciones de ejemplo para cada driver soportado están incluidas en el archivo de configuración. Así que, modifica la configuración para reflejar tus preferencias de almacenamiento y credenciales.
Puedes configurar tantos discos como quieras e incluso tener múltiples discos que usen el mismo driver.
El disco público
El disco public
está pensado para archivos que serán públicamente accesibles. Por defecto, el disco public
usa el driver local
y almacena estos archivos en storage/app/public
. Para hacerlos accesibles desde la web, debes crear un enlace simbólico desde public/storage
a storage/app/public
. Esta convención mantendrá tus archivos públicamente accesibles en un directorio que puede ser fácilmente compartido a través de despliegues al usar sistemas de despligue sin tiempo de inactividad como Envoyer.
Para crear un enlace simbólico, puedes usar el comando de Artisan storage:link
:
php artisan storage:link
Una vez que un archivo ha sido guardado y el enlace simbólico ha sido creado, puedes crear una URL a los archivos usando el helper asset
:
echo asset('storage/file.txt');
Driver local
Al usar el driver local
, todas las operaciones sobre archivos son relativas al directorio root
definido en tu archivo de configuración filesystems
. Por defecto, este valor es establecido al directorio storage/app
. Por lo tanto, el siguiente método almacenará un archivo en storage/app/file.txt
:
Storage::disk('local')->put('file.txt', 'Contents');
Permisos
La visibilidad public
se traduce a 0755
para directorios y 0644
para archivos. Puedes modificar el mapeo de permisos por defecto en tu archivo de configuración filesystems
:
'local' => [ 'driver' => 'local', 'root' => storage_path('app'), 'permissions' => [ 'file' => [ 'public' => 0664, 'private' => 0600, ], 'dir' => [ 'public' => 0775, 'private' => 0700, ], ], ],
Prerrequisitos del driver
Paquetes de Composer
Antes de usar los drivers de SFTP o S3, necesitarás instalar el paquete apropiado mediante Composer:
- SFTP:
league/flysystem-sftp ~1.0
- Amazon S3:
league/flysystem-aws-s3-v3 ~1.0
Algo sumamente recomendable para mejorar el rendimiento es usar un adaptador de caché. Necesitarás un paquete adicional para esto:
- CachedAdapter:
league/flysystem-cached-adapter ~1.0
Configuración del driver S3
La información de configuración del driver de S3 está ubicada en tu archivo de configuración config/filesystems.php
. Este archivo contiene un arreglo de configuración de ejemplo para un driver de S3. Eres libre de modificar este arreglo con tu propia configuración y credenciales de S3. Por conveniencia, estas variables de entorno coinciden con la convención de nombres usada por AWS CLI.
Configuración del driver FTP
Las integraciones de Flysystem de Laravel funcionan bien con FTP; sin embargo, una configuración de ejemplo no está incluida con el archivo de configuración por defecto del framework filesystems.php
. Si necesitas configurar un sistema de archivos FTP, puedes usar la siguiente configuración de ejemplo:
'ftp' => [ 'driver' => 'ftp', 'host' => 'ftp.example.com', 'username' => 'your-username', 'password' => 'your-password', // Optional FTP Settings... // 'port' => 21, // 'root' => '', // 'passive' => true, // 'ssl' => true, // 'timeout' => 30, ],
Configuración del driver SFTP
Las integraciones de Flysystem de Laravel funcionan bien con SFTP; sin embargo, una configuración de ejemplo no está incluida con el archivo de configuración por defecto del framework filesystems.php
. Si necesitas configurar un sistema de archivos SFTP, puedes usar la siguiente configuración de ejemplo:
'sftp' => [ 'driver' => 'sftp', 'host' => 'example.com', 'username' => 'your-username', 'password' => 'your-password', // Settings for SSH key based authentication... // 'privateKey' => '/path/to/privateKey', // 'password' => 'encryption-password', // Optional SFTP Settings... // 'port' => 22, // 'root' => '', // 'timeout' => 30, ],
Caché
Para habilitar la caché para un disco dado, puedes agregar una directiva cache
a las opciones de configuración del disco. La opción cache
debe ser un arreglo de opciones de caché que contiene un nombre de disco disk
, el tiempo de expiración en segundos expire
, y el prefijo prefix
de la caché:
's3' => [ 'driver' => 's3', // Other Disk Options... 'cache' => [ 'store' => 'memcached', 'expire' => 600, 'prefix' => 'cache-prefix', ], ],
Obteniendo instancias del disco
El facade Storage
puede ser usado para interactuar con cualquiera de tus discos configurados. Por ejemplo, puedes usar el método put
en el facade para almacenar un avatar en el disco por defecto. Si llamas a métodos en el facade Storage
sin primero llamar al método disk
, la llamada al método será automáticamente pasada al disco por defecto:
use Illuminate\Support\Facades\Storage; Storage::put('avatars/1', $fileContents);
Si tus aplicaciones interactúan con múltiples discos, puedes usar el método disk
en el facade Storage
para trabajar con archivos en un disco en particular:
Storage::disk('s3')->put('avatars/1', $fileContents);
Retornando archivos
El método get
puede ser usado para retornar el contenido de un archivo. La cadena sin procesar (raw string) del archivo será retornadas por el método. Recuerda, todas las rutas del archivo deben ser especificadas relativas a la ubicación «raíz» configurada por el disco:
$contents = Storage::get('file.jpg');
El método exists
puede ser usado para determinar si un archivo existe en el disco:
$exists = Storage::disk('s3')->exists('file.jpg');
El método missing
puede ser usado para determinar si falta un archivo en el disco:
$missing = Storage::disk('s3')->missing('file.jpg');
Descargando archivos
El método download
puede ser usado para generar una respuesta que obliga al navegador del usuario a descargar el archivo al directorio dado. El método download
acepta un nombre de archivo como segundo argumento del método, que determinará el nombre del archivo que será visto por el usuario que está descargando el archivo. Finalmente, puedes pasar un arreglo de encabezados HTTP como tercer argumento al método:
return Storage::download('file.jpg'); return Storage::download('file.jpg', $name, $headers);
URLs de archivos
Puedes usar el método url
para obtener la URL del archivo dado. Si estás usando el driver local
, esto típicamente agregará /storage
a la ruta dada y retornará una URL relativa al archivo. Si estás usando el driver s3
, será retornada la URL remota completamente calificada:
use Illuminate\Support\Facades\Storage; $url = Storage::url('file.jpg');
Recuerda, si estás usando el driver local
, todos los archivos que deberían ser públicamente accesibles deben ser colocados en el directorio storage/app/public
. Además, debes crear un enlace simbólico a public/storage
que apunte al directorio storage/app/public
.
URLs temporales
Para archivos almacenados usando el driver s3
, puedes crear una URL temporal a un archivo dado usando el método temporaryUrl
. Este método acepta una ruta y una instancia DateTime
que especifica cuándo la URL debería expirar:
$url = Storage::temporaryUrl( 'file.jpg', now()->addMinutes(5) );
Si necesitas especificar parámetros de petición de S3 adicionales, puedes pasar el arreglo de parámetros de petición como tercer argumento del método temporaryUrl
:
$url = Storage::temporaryUrl( 'file.jpg', now()->addMinutes(5), ['ResponseContentType' => 'application/octet-stream'] );
Personalización del host de URL local
Si te gustaría predefinir el host para archivos almacenados en un disco usando el driver local
, puedes agregar una opción url
al arreglo de configuración del disco:
'public' => [ 'driver' => 'local', 'root' => storage_path('app/public'), 'url' => env('APP_URL').'/storage', 'visibility' => 'public', ],
Metadatos de archivos
Además de leer y agregar archivos, Laravel también puede proporcionar información sobre los archivos. Por ejemplo, el método size
puede ser usado para obtener el tamaño del archivo en bytes:
use Illuminate\Support\Facades\Storage; $size = Storage::size('file.jpg');
El método lastModified
retorna la marca de tiempo de UNIX de la última vez en que el archivo fue modificado:
$time = Storage::lastModified('file.jpg');
Almacenando archivos
El método put
puede ser usado para almacenar el contenido sin procesar (raw) de archivo en un disco. Puedes también pasar un resource
de PHP al método put
, que usará el soporte subyacente de stream de Flysystem. Recuerda, todas las rutas de archivos deben ser especificadas de forma relativa a la ubicación «raíz» configurada en el disco:
use Illuminate\Support\Facades\Storage; Storage::put('file.jpg', $contents); Storage::put('file.jpg', $resource);
Streaming automático
Si te gustaría que Laravel automáticamente haga streaming de un archivo dado a tu ubicación de almacenamiento, puedes usar los métodos putFile
o putFileAs
. Este método acepta una instancia de Illuminate\Http\File
o Illuminate\Http\UploadedFile
y automáticamente hará stream del archivo a la ubicación deseada:
use Illuminate\Http\File; use Illuminate\Support\Facades\Storage; // Automatically generate a unique ID for file name... Storage::putFile('photos', new File('/path/to/photo')); // Manually specify a file name... Storage::putFileAs('photos', new File('/path/to/photo'), 'photo.jpg');
Hay algunas cosas importantes a tener en cuenta sobre el método putFile
. Observa que sólo especificamos un nombre de directorio, no un nombre de archivo. Por defecto, el método putFile
generará un ID único que servirá como nombre del archivo. La extensión del archivo será determinada examinando el tipo MIME del archivo. La ruta al archivo será retornada por el método putFile
para que puedes almacenar la ruta, incluyendo el nombre de archivo generado, en tu base de datos.
Los métodos putFile
y putFileAs
también aceptan un argumento para especificar la «visibilidad» del archivo almacenado. Esto es particularmente útil si estás almacenando el archivo en disco en la nube como S3 y te gustaría que el archivo sea públicamente accesible:
Storage::putFile('photos', new File('/path/to/photo'), 'public');
Añadir al inicio o al final de un archivo
Los métodos prepend
y append
te permiten escribir al inicio o final de un archivo:
Storage::prepend('file.log', 'Prepended Text'); Storage::append('file.log', 'Appended Text');
Copiando y moviendo archivos
El método copy
puede ser usado para copiar un archivo existente a una nueva ubicación en el disco, mientras que el método move
puede ser usado para renombrar o mover un archivo existente a una nueva ubicación:
Storage::copy('old/file.jpg', 'new/file.jpg'); Storage::move('old/file.jpg', 'new/file.jpg');
Carga de archivos
En las aplicaciones web, una de los casos de uso más comunes para almacenar archivos es almacenar archivos cargados por los usuarios como imágenes de perfil, fotos y documentos. Laravel hace que sea muy fácil almacenar archivos cargados usando el método store
en la instancia de un archivo cargado. Llama al método store
con la ruta en la quieres almacenar el archivo:
<?php namespace App\Http\Controllers; use App\Http\Controllers\Controller; use Illuminate\Http\Request; class UserAvatarController extends Controller { /** * Update the avatar for the user. * * @param Request $request * @return Response */ public function update(Request $request) { $path = $request->file('avatar')->store('avatars'); return $path; } }
Hay algunas cosas importantes a tener en cuenta sobre este ejemplo. Observa que sólo especificamos un nombre de directorio, no un nombre de archivo. Por defecto, el método store
generará un ID único que servirá como nombre de archivo. La extensión del archivo será determinada examinando el tipo MIME del archivo. La ruta al archivo será retornada por el método store
para que puedas guardar la ruta, incluyendo el nombre generado, en tu base de datos.
También puedes llamar al método putFile
en el facade Storage
para realizar la misma manipulación de archivo del ejemplo anterior:
$path = Storage::putFile('avatars', $request->file('avatar'));
Especificando un nombre de archivo
Si no te gustaría que un nombre de archivo sea automáticamente asignado a tu archivo almacenado, puedes usar el método storeAs
, que recibe una ruta, el nombre del archivo y el disco (opcional) como sus argumentos:
$path = $request->file('avatar')->storeAs( 'avatars', $request->user()->id );
Puedes usar el método putFileAs
en el facade Storage
, que realizará las mismas manipulaciones de archivos del ejemplo anterior:
$path = Storage::putFileAs( 'avatars', $request->file('avatar'), $request->user()->id );
Caracteres unicode no válidos y que no pueden ser mostrados serán automáticamente eliminados de rutas de archivos. Por lo tanto, podrías querer sanitizar las rutas de tus archivos antes de pasarlas a los métodos de almacenamiento de archivos de Laravel. Las rutas de archivos son normalizadas usando el método League\Flysystem\Util::normalizePath
.
Especificando un disco
Por defecto, este método usará tu disco predeterminado. Si te gustaría especificar otro disco, pasa el nombre del disco como segundo argumento al método store
:
$path = $request->file('avatar')->store( 'avatars/'.$request->user()->id, 's3' );
Otra información de archivos
Si te gustaría obtener el nombre original del archivo cargado, puedes hacer esto usando el método getClientOriginalName
:
$name = $request->file('avatar')->getClientOriginalName();
El método extension
puede ser usado para obtener la extensión del archivo cargado:
$extension = $request->file('avatar')->extension();
Visibilidad de archivos
En la integración de Flysystem de Laravel, «visibilidad» es una abstracción de permisos de archivos a través de múltiples plataformas. Los archivos pueden ser declarados public
o private
. Cuando un archivo es declarado public
, estás indicando que el archivo debería ser generalmente accesible por otros. Por ejemplo, al usar el driver de S3, puedes retornar URLs para archivos public
.
Puedes establecer la visibilidad al configurar el archivo mediante el método put
:
use Illuminate\Support\Facades\Storage; Storage::put('file.jpg', $contents, 'public');
Si el archivo ya ha sido almacenado, su visibilidad puede ser retornada y establecida mediante los métodos getVisibility
y setVisibility
:
$visibility = Storage::getVisibility('file.jpg'); Storage::setVisibility('file.jpg', 'public');
Eliminando archivos
El método delete
acepta un solo nombre de archivo o un arreglo de archivos a eliminar del disco:
use Illuminate\Support\Facades\Storage; Storage::delete('file.jpg'); Storage::delete(['file.jpg', 'file2.jpg']);
Si es necesario, puedes especificar el disco en el que se debe eliminar el archivo:
use Illuminate\Support\Facades\Storage; Storage::disk('s3')->delete('folder_path/file_name.jpg');
Directorios
Obtener todos los archivos dentro de un directorio
El método files
retorna un arreglo de todos los archivos en un directorio dado. Si te gustaría retornar una lista de todos los archivos dentro de un directorio dado incluyendo subdirectorios, puedes usar el método allFiles
:
use Illuminate\Support\Facades\Storage; $files = Storage::files($directory); $files = Storage::allFiles($directory);
Obtener todos los directorios dentro de un directorio
El método directories
retorna un arreglo de todos los directorios dentro de un directorio dado. Adicionalmente, puedes usar el método allDirectories
para obtener una lista de todos los directorios dentro de un directorio dado y todos sus subdirectorios:
$directories = Storage::directories($directory); // Recursive... $directories = Storage::allDirectories($directory);
Crear un directorio
El método makeDirectory
creará el directorio dado, incluyendo cualquier subdirectorio necesario:
Storage::makeDirectory($directory);
Eliminar un directorio
Finalmente, el método deleteDirectory
puede ser usado para eliminar un directorio y todos sus archivos:
Storage::deleteDirectory($directory);
Sistemas de archivos personalizados
La integración de Flysystem de Laravel proporciona drivers para múltiples «drivers» de forma predeterminada; sin embargo, Flysystem no está limitado a estos y tiene adaptadores para muchos otros sistemas de almacenamiento. Puedes crear un driver personalizado si quieres usar alguno de los adaptadores adicionales en tu aplicación de Laravel.
Para configurar el sistema de archivos personalizado necesitarás un adaptador de Flysystem. Vamos a agregar un adaptador de Dropbox mantenido por la comunidad a nuestro proyecto:
composer require spatie/flysystem-dropbox
Luego, debes crear un proveedor de servicios como DropboxServiceProvider
. En el método boot
del proveedor, puedes usar el método extend
del facade Storage
para definir el driver personalizado:
<?php namespace App\Providers; use Illuminate\Support\ServiceProvider; use League\Flysystem\Filesystem; use Spatie\Dropbox\Client as DropboxClient; use Spatie\FlysystemDropbox\DropboxAdapter; use Storage; class DropboxServiceProvider extends ServiceProvider { /** * Register any application services. * * @return void */ public function register() { // } /** * Bootstrap any application services. * * @return void */ public function boot() { Storage::extend('dropbox', function ($app, $config) { $client = new DropboxClient( $config['authorization_token'] ); return new Filesystem(new DropboxAdapter($client)); }); } }
El primer argumento del método extend
es el nombre del driver y el segundo es una Closure que recibe las variables $app
y $config
. La Closure de resolver debe retornar una instancia de League\Flysystem\Filesystem
. La variable $config
contiene los valores definidos en config/filesystems.php
para el disco especificado.
Luego, registra el proveedor de servicios en tu archivo de configuración config/app.php
:
'providers' => [ // ... App\Providers\DropboxServiceProvider::class, ];
Una vez que hayas creado y registrado el proveedor de servicios de la extensión, puedes usar el driver dropbox
en tu archivo de configuración config/filesystems.php
.
Regístrate hoy en Styde y obtén acceso a todo nuestro contenido.
Lección anterior Eventos - Documentación de Laravel 6 Lección siguiente Helpers - Documentación de Laravel 6