league/flysystem
Flysystem is a filesystem abstraction for PHP that lets you work with local disks, S3, FTP, and more through one consistent API. Swap storage backends without changing your code, with adapters, streams, and strong integration across frameworks like Laravel.
## Getting Started
### Minimal Setup in Laravel
Install via Composer:
```bash
composer require league/flysystem
Register the service provider in config/app.php (Laravel 8+ auto-discovers it):
'providers' => [
League\Flysystem\FilesystemServiceProvider::class,
],
Publish the config (optional):
php artisan vendor:publish --provider="League\Flysystem\FilesystemServiceProvider"
use League\Flysystem\Filesystem;
use League\Flysystem\Local\LocalFilesystemAdapter;
$adapter = new LocalFilesystemAdapter('/path/to/storage', 'public');
$filesystem = new Filesystem($adapter);
// Write a file
$filesystem->write('file.txt', 'Hello, FlySystem!');
// Read a file
$contents = $filesystem->read('file.txt');
// List files
$files = $filesystem->listContents();
use League\Flysystem\AwsS3v3\AwsS3V3Adapter;
use Aws\S3\S3Client;
$s3 = new S3Client([
'version' => 'latest',
'region' => 'us-east-1',
'credentials' => [
'key' => 'your-key',
'secret' => 'your-secret',
]
]);
$adapter = new AwsS3V3Adapter($s3, 'your-bucket-name');
$filesystem = new Filesystem($adapter);
public function uploadFile(Request $request)
{
$request->validate([
'file' => 'required|file|max:10240', // 10MB
]);
$file = $request->file('file');
$path = 'uploads/' . $file->hashName();
$this->filesystem->writeStream($path, fopen($file->getRealPath(), 'r'));
return response()->json(['path' => $path]);
}
// Create directory
$this->filesystem->createDirectory('images/avatars');
// Check if directory exists
if ($this->filesystem->directoryExists('images/avatars')) {
// List directory contents
$contents = $this->filesystem->listContents('images/avatars');
}
// Delete directory (recursively)
$this->filesystem->deleteDirectory('images/avatars');
// Get file metadata
$metadata = $this->filesystem->metadata('file.txt');
// Generate public URL (if supported by adapter)
$url = $this->filesystem->url('file.txt');
// Generate temporary URL (e.g., for S3)
$tempUrl = $this->filesystem->temporaryUrl(
'file.txt',
now()->addMinutes(15)
);
// Set visibility (e.g., for S3)
$this->filesystem->setVisibility('file.txt', 'public');
// Copy with visibility retention
$this->filesystem->copy(
'source.txt',
'destination.txt',
['visibility' => 'public']
);
// Move with visibility retention
$this->filesystem->move(
'source.txt',
'destination.txt',
['visibility' => 'public']
);
Leverage Laravel's built-in storage integration for seamless usage:
// In config/filesystems.php
'disks' => [
'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),
],
'local' => [
'driver' => 'local',
'root' => storage_path('app'),
],
],
// Usage in code
use Illuminate\Support\Facades\Storage;
$contents = Storage::disk('s3')->get('file.txt');
Storage::disk('local')->put('file.txt', 'Hello, Laravel!');
Use MountManager to handle multiple filesystems under a single interface:
use League\Flysystem\MountManager;
$mountManager = new MountManager([
'local' => new Filesystem(new LocalFilesystemAdapter('/path/to/local', 'public')),
's3' => new Filesystem(new AwsS3V3Adapter($s3Client, 'bucket-name')),
]);
// Access filesystems
$localContents = $mountManager->getAdapter('local')->listContents();
$s3Contents = $mountManager->getAdapter('s3')->listContents();
// Write to specific filesystem
$mountManager->getAdapter('s3')->write('file.txt', 'Content');
Extend functionality with decorators or custom adapters:
use League\Flysystem\Filesystem;
use League\Flysystem\StorageAttributes;
use League\Flysystem\AdapterInterface;
// Custom decorator to log file operations
class LoggingAdapter implements AdapterInterface
{
protected $adapter;
public function __construct(AdapterInterface $adapter)
{
$this->adapter = $adapter;
}
public function write($path, $contents, StorageAttributes $attributes)
{
\Log::info("Writing to $path");
return $this->adapter->write($path, $contents, $attributes);
}
// Implement other AdapterInterface methods...
}
$adapter = new LoggingAdapter(new LocalFilesystemAdapter('/path'));
$filesystem = new Filesystem($adapter);
For high-performance async operations with AWS S3:
use League\Flysystem\AsyncAws\AsyncAwsS3Adapter;
use AsyncAws\S3\S3Client;
$s3Client = new S3Client([
'version' => 'latest',
'region' => 'us-east-1',
'credentials' => [
'key' => env('AWS_ACCESS_KEY_ID'),
'secret' => env('AWS_SECRET_ACCESS_KEY'),
],
]);
$adapter = new AsyncAwsS3Adapter($s3Client, 'bucket-name');
$filesystem = new Filesystem($adapter);
// Async write (non-blocking)
$filesystem->write('file.txt', 'Content')->wait();
Issue: Paths are case-sensitive on some filesystems (e.g., Linux) but not on others (e.g., Windows).
Fix: Normalize paths using strtolower() or str_replace() if case sensitivity is a concern.
$path = str_replace('\\', '/', $path); // Ensure forward slashes
$path = strtolower($path); // Normalize case
Issue: Double slashes or trailing slashes can cause issues.
Fix: Use rtrim() and ltrim() to clean paths:
$path = rtrim(ltrim($path, '/'), '/');
Issue: Writing files to a directory may fail if the directory lacks write permissions.
Fix: Ensure the directory exists and has the correct permissions:
if (!$this->filesystem->directoryExists('path/to/dir')) {
$this->filesystem->createDirectory('path/to/dir');
}
Issue: Visibility settings (e.g., public, private) may not apply if the adapter doesn't support them.
Fix: Check adapter documentation or use conditional logic:
if (method_exists($adapter, 'setVisibility')) {
$adapter->setVisibility('file.txt', 'public');
}
S3: Ensure the bucket exists before writing files. Use doesBucketExist() if available.
SFTP: Connection timeouts or authentication failures can silently fail. Use try-catch blocks:
try {
$this->filesystem->write('file.txt', 'Content');
} catch (\League\Flysystem\Exception\ConnectionException $e) {
\Log::error("SFTP Connection failed: " . $e->getMessage());
}
Local: On Windows, ensure the path uses forward slashes (/). Backslashes (\) may cause issues.
try {
$url = $this->filesystem->temporaryUrl('file.txt', now()->addMinutes(15));
} catch (\League\Flysystem\Exception\TemporaryUrlNotSupported $e) {
// Fallback to public URL or generate a new temporary URL
}
Configure
How can I help you explore Laravel packages today?