Laravel storage overview
In a nutshell
Laravel provides a powerful filesystem abstraction based on the Flysystem PHP package. The Laravel Flysystem integration provides drivers for working with:
- Local filesystems
- Amazon S3
- SFTP
Laravel’s filesystem configuration is stored at config/filesystems.php
. Here you can configure all your filesystem’s “disks”.
Each disk represents a particular storage driver and storage location. Here’s the default config file at the time of writing (August, 2024):
<?php
return [
/*
|--------------------------------------------------------------------------
| Default Filesystem Disk
|--------------------------------------------------------------------------
|
| Here you may specify the default filesystem disk that should be used
| by the framework. The "local" disk, as well as a variety of cloud
| based disks are available to your application for file storage.
|
*/
'default' => env('FILESYSTEM_DISK', 'local'),
/*
|--------------------------------------------------------------------------
| Filesystem Disks
|--------------------------------------------------------------------------
|
| Below you may configure as many filesystem disks as necessary, and you
| may even configure multiple disks for the same driver. Examples for
| most supported storage drivers are configured here for reference.
|
| Supported drivers: "local", "ftp", "sftp", "s3"
|
*/
'disks' => [
'local' => [
'driver' => 'local',
'root' => storage_path('app'),
'throw' => false,
],
'public' => [
'driver' => 'local',
'root' => storage_path('app/public'),
'url' => env('APP_URL').'/storage',
'visibility' => 'public',
'throw' => false,
],
's3' => [
'driver' => 's3',
'key' => env('AWS_ACCESS_KEY_ID'),
'secret' => env('AWS_SECRET_ACCESS_KEY'),
'region' => env('AWS_DEFAULT_REGION'),
'bucket' => env('AWS_BUCKET'),
'url' => env('AWS_URL'),
'endpoint' => env('AWS_ENDPOINT'),
'use_path_style_endpoint' => env('AWS_USE_PATH_STYLE_ENDPOINT', false),
'throw' => false,
],
],
/*
|--------------------------------------------------------------------------
| Symbolic Links
|--------------------------------------------------------------------------
|
| Here you may configure the symbolic links that will be created when the
| `storage:link` Artisan command is executed. The array keys should be
| the locations of the links and the values should be their targets.
|
*/
'links' => [
public_path('storage') => storage_path('app/public'),
],
];
Local vs S3 driver
Local driver
When using the local
driver, all file operations are relative to the root
directory defined in your filesystems
configuration file. By default, this value is set to the storage/app
directory. Therefore, the following method would write to storage/app/example.txt
:
use Illuminate\Support\Facades\Storage;
Storage::disk('local')->put('example.txt', 'Contents');
S3 driver
Before using the S3 driver, you’ll need to install the Flysystem S3 package:
composer require league/flysystem-aws-s3-v3 "^3.0" --with-all-dependencies
An S3 disk configuration array is located in your config/filesystems.php
configuration file. Typically, you should configure your S3 information and credentials using the following environment variables which are referenced by the config/filesystems.php
configuration file:
AWS_ACCESS_KEY_ID=<your-key-id>
AWS_SECRET_ACCESS_KEY=<your-secret-access-key>
AWS_DEFAULT_REGION=us-east-1
AWS_BUCKET=<your-bucket-name>
AWS_USE_PATH_STYLE_ENDPOINT=false
The public
disk
The public
disk included in your application’s filesystems
configuration file is intended for files that are going to be publicly accessible. By default, the public
disk uses the local
driver and stores its files in storage/app/public
.
To make these files accessible from the web, you should create a symbolic link from public/storage
to storage/app/public
.
To create this symbolic link, you may use the storage:link
Artisan command:
php artisan storage:link
Once a file has been stored and the symbolic link has been created, you can create a URL to the files using the asset
helper:
echo asset('storage/file.txt');
You may configure additional symbolic links in your filesystems
configuration file. Each of the configured links will be created when you run the storage:link
command:
'links' => [
public_path('storage') => storage_path('app/public'),
public_path('images') => storage_path('app/images'),
],
The storage:unlink
command may be used to destroy your configured symbolic links:
php artisan storage:unlink
Scoped & read-only filesystems
Scoped filesystems
Scoped disks allow you to define a filesystem where all paths are automatically prefixed with a given path prefix. Before creating a scoped filesystem disk, you will need to install an additional Flysystem package via the Composer package manager:
composer require league/flysystem-path-prefixing "^3.0"
You may create a path scoped instance of any existing filesystem disk by defining a disk that utilizes the scoped
driver. For example, you may create a disk which scopes your existing s3
disk to a specific path prefix, and then every file operation using your scoped disk will utilize the specified prefix:
's3-videos' => [
'driver' => 'scoped',
'disk' => 's3',
'prefix' => 'path/to/videos',
],
Read-only file systems
“Read-only” disks allow you to create filesystem disks that do not allow write operations. Before using the read-only
configuration option, you will need to install an additional Flysystem package via the Composer package manager:
composer require league/flysystem-read-only "^3.0"
Next, you may include the read-only
configuration option in one or more of your disk’s configuration arrays:
's3-videos' => [
'driver' => 's3',
// ...
'read-only' => true,
],
Obtaining a disk instance
You can use the Storage
facade to interact with any of your configured disks. For example, you can use its put
method to store a file on the default disk:
use Illuminate\Support\Facades\Storage;
Storage::put('avatars/1', $content);
If your app has multiple disks, you can use the disk
method to work files on a particular disk:
Storage::disk('s3')->put('avatars/1', $content);
Use on-demand disks
Sometimes you may wish to create a disk at runtime using a given configuration without that configuration actually being present in your application’s filesystems
configuration file. To accomplish this, you may pass a configuration array to the Storage
facade’s build
method:
use Illuminate\Support\Facades\Storage;
$disk = Storage::build([
'driver' => 'local',
'root' => '/path/to/root',
]);
$disk->put('image.jpg', $content);
Working with files
Read / download files
Retrieve file contents
The get
method may be used to retrieve the contents of a file. The raw string contents of the file will be returned by the method. Remember, all file paths should be specified relative to the disk’s “root” location:
$contents = Storage::get('file.jpg');
Retrieve JSON file
If the file you are retrieving contains JSON, you may use the json
method to retrieve the file and decode its contents:
$orders = Storage::json('orders.json');
Download a file from disk
return Storage::download('file.jpg');
return Storage::download('file.jpg', $filenameForDownload, $httpHeaders);
Check things about files
Check if file exists on disk
if (Storage::disk('s3')->exists('file.jpg')) {
// ...
}
Check if file is missing on disk
if (Storage::disk('s3')->missing('file.jpg')) {
// ...
}
Get file metadata
use Illuminate\Support\Facades\Storage;
$size = Storage::size('file.jpg');
$time = Storage::lastModified('file.jpg');
$mime = Storage::mimeType('file.jpg');
$path = Storage::path('file.jpg');
File URLs
Get a file URL from a local
driver
If you are using the local
driver, this will typically just prepend /storage
to the given path and return a relative URL to the file.
use Illuminate\Support\Facades\Storage;
$url = Storage::url('file.jpg');
Storage::url()
will typically just prepend /storage
to the given path and return a relative URL to the file.
When using the local
driver, all files that should be publicly accessible should be placed in the storage/app/public
directory. Furthermore, you should create a symbolic link at public/storage
which points to the storage/app/public
directory.
When using the local
driver, the return value of url
is not URL encoded. It’s therefore recommended to always store your files using names that will create valid URLs.
Get a file URL from a s3
driver
use Illuminate\Support\Facades\Storage;
$url = Storage::url('file.jpg');
Storage::url()
will return a fully qualified remote URL.
Generate temporary s3
URL
Using the temporaryUrl
method, you may create temporary URLs to files stored using the s3
driver. This method accepts a path and a DateTime
instance specifying when the URL should expire:
use Illuminate\Support\Facades\Storage;
$url = Storage::temporaryUrl(
'file.jpg', now()->addMinutes(5)
);
If you need to specify additional S3 request parameters, you may pass the array of request parameters as the third argument to the temporaryUrl
method:
$url = Storage::temporaryUrl(
'file.jpg',
now()->addMinutes(5),
[
'ResponseContentType' => 'application/octet-stream',
'ResponseContentDisposition' => 'attachment; filename=file2.jpg',
]
);
Store a file
The put
method may be used to store file contents on a disk. You may also pass a PHP resource
to the put
method, which will use Flysystem’s underlying stream support. Remember, all file paths should be specified relative to the “root” location configured for the disk:
use Illuminate\Support\Facades\Storage;
Storage::put('file.jpg', $contents);
Storage::put('file.jpg', $resource);
If the put
method (or other “write” operations) is unable to write the file to disk, false
will be returned:
if (! Storage::put('file.jpg', $contents)) {
// The file could not be written to disk...
}
Upload file to default disk
You can use the store()
method to upload to your default disk:
<?php
namespace App\Http\Controllers;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
class UserAvatarController extends Controller
{
/**
* Update the avatar for the user.
*/
public function update(Request $request): string
{
$path = $request->file('avatar')->store('avatars');
return $path;
}
}
By default, the store
method will generate a unique ID to serve as the filename. The file’s extension will be determined by examining the file’s MIME type. The path to the file will be returned by the store
method so you can store the path, including the generated filename, in your database.
Upload file to specific disk
$path = $request->file('avatar')->store(
'avatars/'.$request->user()->id, 's3'
);
Stream files to storage
Streaming files to storage offers significantly reduced memory usage. If you would like Laravel to automatically manage streaming a given file to your storage location, you may use the putFile
or putFileAs
method. This method accepts either an Illuminate\Http\File
or Illuminate\Http\UploadedFile
instance and will automatically stream the file to your desired location:
use Illuminate\Http\File;
use Illuminate\Support\Facades\Storage;
// Automatically generate a unique ID for filename so you can store in DB if needed...
$path = Storage::putFile('photos', new File('/path/to/photo'));
// Manually specify a filename...
$path = Storage::putFileAs('photos', new File('/path/to/photo'), 'photo.jpg');
The putFile
and putFileAs
methods also accept an argument to specify the “visibility” of the stored file. This is particularly useful if you are storing the file on a cloud disk such as Amazon S3 and would like the file to be publicly accessible via generated URLs:
Storage::putFile('photos', new File('/path/to/photo'), 'public');
Prepend / append to files
Storage::prepend('file.log', 'Prepended Text');
Storage::append('file.log', 'Appended Text');
Delete a file
From default disk:
use Illuminate\Support\Facades\Storage;
Storage::delete('file.jpg');
Storage::delete(['file.jpg', 'file2.jpg']);
From specific disk:
use Illuminate\Support\Facades\Storage;
Storage::disk('s3')->delete('path/file.jpg');
Explore the filesystem
Get files in a directory
use Illuminate\Support\Facades\Storage;
# Get files in a directory
$files = Storage::files($directory);
# Get files in a directory and all subdirectories
$files = Storage::allFiles($directory);
Get directories within a directory
# Get files within one directory
$directories = Storage::directories($directory);
# Get files within a directory and all its subdirectories
$directories = Storage::allDirectories($directory);
Create directory
Storage::makeDirectory($directory);
Delete directory
Storage::deleteDirectory($directory);
Copy / move files
Storage::copy('old/file.jpg', 'new/file.jpg');
Storage::move('old/file.jpg', 'new/file.jpg');
File visibility
In Laravel’s Flysystem integration, “visibility” is an abstraction of file permissions across multiple platforms. Files may either be declared public
or private
. When a file is declared public
, you are indicating that the file should generally be accessible to others. For example, when using the S3 driver, you may retrieve URLs for public
files.
You can set the visibility when writing the file via the put
method:
use Illuminate\Support\Facades\Storage;
Storage::put('file.jpg', $contents, 'public');
If the file has already been stored, its visibility can be retrieved and set via the getVisibility
and setVisibility
methods:
$visibility = Storage::getVisibility('file.jpg');
Storage::setVisibility('file.jpg', 'public');
When interacting with uploaded files, you may use the storePublicly
and storePubliclyAs
methods to store the uploaded file with public
visibility:
$path = $request->file('avatar')->storePublicly('avatars', 's3');
$path = $request->file('avatar')->storePubliclyAs(
'avatars',
$request->user()->id,
's3'
);
Local Files and Visibility
When using the local
driver, public
visibility translates to 0755
permissions for directories and 0644
permissions for files. You can modify the permissions mappings in your application’s filesystems
configuration file:
'local' => [
'driver' => 'local',
'root' => storage_path('app'),
'permissions' => [
'file' => [
'public' => 0644,
'private' => 0600,
],
'dir' => [
'public' => 0755,
'private' => 0700,
],
],
'throw' => false,
],
Testing files
See here.