ez-php / storage
File storage abstraction for the ez-php framework — local filesystem and S3-compatible drivers
Requires
- php: ^8.5
- ext-curl: *
- ez-php/contracts: ^1.0
- ez-php/http: ^1.0
Requires (Dev)
- ez-php/docker: ^1.0
- friendsofphp/php-cs-fixer: ^3.94
- phpstan/phpstan: ^2.1
- phpstan/phpstan-deprecation-rules: ^2.0
- phpstan/phpstan-strict-rules: ^2.0
- phpunit/phpunit: ^13.0
README
File storage abstraction for the ez-php framework.
Provides a unified interface (put, get, delete, exists, url) over pluggable drivers. Ships with a LocalDriver (filesystem) and an S3Driver (AWS S3 and S3-compatible APIs via cURL + AWS Signature V4). Integrates with UploadedFile from ez-php/http.
Installation
composer require ez-php/storage
Configuration
Add config/storage.php to your application:
return [ 'driver' => env('STORAGE_DRIVER', 'local'), 'local' => [ 'root' => env('STORAGE_ROOT', storage_path('app')), 'url' => env('STORAGE_URL', ''), ], 's3' => [ 'key' => env('AWS_ACCESS_KEY_ID'), 'secret' => env('AWS_SECRET_ACCESS_KEY'), 'region' => env('AWS_DEFAULT_REGION', 'us-east-1'), 'bucket' => env('AWS_BUCKET'), 'endpoint' => env('AWS_ENDPOINT'), // optional: MinIO, R2, etc. 'url' => env('AWS_URL'), // optional: CDN base URL 'url_expiry' => 3600, ], ];
Register the provider in provider/modules.php:
\EzPhp\Storage\StorageServiceProvider::class,
Usage
Via static façade
use EzPhp\Storage\Storage; Storage::put('avatars/user-1.jpg', $imageBytes); $data = Storage::get('avatars/user-1.jpg'); Storage::exists('avatars/user-1.jpg'); // true Storage::url('avatars/user-1.jpg'); // public URL or presigned URL Storage::delete('avatars/user-1.jpg');
Storing an uploaded file
Storage::putUploadedFile('uploads/' . $file->originalName(), $file);
Via dependency injection
use EzPhp\Storage\StorageInterface; class AvatarController { public function __construct(private readonly StorageInterface $storage) {} public function upload(Request $request): Response { $file = $request->file('avatar'); $this->storage->putUploadedFile('avatars/' . $file->originalName(), $file); // ... } }
Drivers
LocalDriver
Stores files under a configurable root directory. Creates nested directories automatically.
$driver = new LocalDriver('/var/www/storage', 'https://cdn.example.com'); $driver->put('docs/readme.txt', 'Hello'); $driver->url('docs/readme.txt'); // https://cdn.example.com/docs/readme.txt
S3Driver
Uploads and retrieves objects using cURL with AWS Signature Version 4. Works with AWS S3 and any S3-compatible service (MinIO, Cloudflare R2, DigitalOcean Spaces).
url()returns a presigned GET URL (valid forurl_expiryseconds)- If a custom
url(CDN) is configured,url()returns{url}/{path}instead - Custom
endpointoverrides the default{bucket}.s3.{region}.amazonaws.comhost
$driver = new S3Driver('key', 'secret', 'eu-west-1', 'my-bucket'); $driver->put('report.pdf', file_get_contents('/tmp/report.pdf')); $driver->url('report.pdf'); // presigned URL
Running Tests
docker compose exec app composer full
S3 integration tests are skipped unless AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, and AWS_BUCKET are set in the environment.