Custom notification channels
Advanced5 min read·lv-21-005
Concept
File storage in Laravel is abstracted by the Storage facade, built on the Flysystem library. The same API works with local disk, S3, R2, GCS, FTP, and SFTP — changing the disk config switches backends without touching application code.
Disks: Named storage configurations in config/filesystems.php. The default disk is used by Storage::put() etc. with no disk specified. Storage::disk('s3')->put(...) uses a specific disk.
Key operations:
Storage::put($path, $contents): Write (creates directories automatically).Storage::get($path): Read file contents.Storage::exists($path)/Storage::missing($path).Storage::delete($path)/Storage::delete(['a', 'b']).Storage::move($from, $to): Move/rename.Storage::copy($from, $to): Copy.Storage::url($path): Public URL. Only works for public disks.Storage::temporaryUrl($path, $expiry): Signed URL. S3/R2 only.Storage::size($path): File size in bytes.Storage::lastModified($path): Unix timestamp of last modification.Storage::mimeType($path): MIME type.
Visibility: public = world-readable URL, private = no direct URL access.
Storage::setVisibility($path, 'public').Storage::put($path, $contents, 'public')— third arg sets visibility.
Code Example
php
<?php
use Illuminate\Support\Facades\Storage;
// Write
Storage::put('reports/sales-2024.csv', $csvContent);
Storage::put('images/avatar.jpg', $imageData);
Storage::put('files/doc.pdf', $contents, 'public'); // publicly accessible
// Read
$contents = Storage::get('reports/sales-2024.csv');
$json = json_decode(Storage::get('config/settings.json'), true);
// Check existence
if (Storage::exists('reports/sales-2024.csv')) { ... }
if (Storage::missing('cache/stats.json')) {
// generate and store
}
// Delete
Storage::delete('reports/old-report.csv');
Storage::delete(['img/1.jpg', 'img/2.jpg', 'img/3.jpg']);
// Directory operations
Storage::makeDirectory('reports/2024');
Storage::deleteDirectory('temp');
$files = Storage::files('reports');
$allFiles = Storage::allFiles('reports'); // recursive
$dirs = Storage::directories('reports');
// URLs
$url = Storage::url('images/avatar.jpg'); // public URL (/storage/images/avatar.jpg)
$url = Storage::disk('s3')->url('files/doc.pdf'); // https://bucket.s3.../files/doc.pdf
// Temporary URL (S3/R2) — signed, expires in 30 min
$tempUrl = Storage::disk('s3')->temporaryUrl(
'private-files/contract.pdf',
now()->addMinutes(30)
);
// Share this URL — it expires automatically
// Storing uploaded files
public function uploadAvatar(Request $request, User $user)
{
$path = $request->file('avatar')->store('avatars', 's3');
// Returns: "avatars/random-uuid.jpg"
$user->update(['avatar_path' => $path]);
}
// Cross-disk operations
$contents = Storage::disk('local')->get('exports/data.json');
Storage::disk('s3')->put('backups/data.json', $contents);