alinauf / laravel-azure-storage
Azure Blob Storage filesystem driver for Laravel using REST API
Requires
- php: ^8.2
- illuminate/contracts: ^11.0|^12.0
- illuminate/http: ^11.0|^12.0
- illuminate/support: ^11.0|^12.0
- league/flysystem: ^3.0
Requires (Dev)
- laravel/pint: ^1.0
- orchestra/testbench: ^9.0|^10.0
- phpunit/phpunit: ^11.0
README
Azure Blob Storage filesystem driver for Laravel using the Azure REST API directly. No deprecated SDK dependencies.
Features
- Full Flysystem Integration - Works seamlessly with Laravel's Storage facade
- REST API Based - Uses Azure Blob Storage REST API directly, no deprecated SDKs
- Shared Key Authentication - Secure HMAC-SHA256 authentication
- SAS Token Support - Generate temporary signed URLs for secure access
- Full CRUD Operations - Read, write, delete, copy, move files
- Directory Operations - List contents, delete directories
- Metadata Support - Get file size, last modified time, MIME type
- CDN Support - Custom URL support for Azure CDN or custom domains
Requirements
- PHP 8.2+
- Laravel 11.0+ or 12.0+
Installation
Install the package via Composer:
composer require alinauf/laravel-azure-storage
The service provider will be auto-discovered by Laravel.
Publish Configuration (Optional)
php artisan vendor:publish --tag=azure-storage-config
Configuration
Add the following environment variables to your .env file:
AZURE_STORAGE_ACCOUNT_NAME=your-account-name AZURE_STORAGE_ACCOUNT_KEY=your-account-key AZURE_STORAGE_CONTAINER=your-container-name AZURE_STORAGE_URL=https://your-cdn-url.com # Optional: for CDN or custom domain
Then configure a disk in config/filesystems.php:
'disks' => [ 'azure' => [ 'driver' => 'azure', 'account_name' => env('AZURE_STORAGE_ACCOUNT_NAME'), 'account_key' => env('AZURE_STORAGE_ACCOUNT_KEY'), 'container' => env('AZURE_STORAGE_CONTAINER'), 'url' => env('AZURE_STORAGE_URL'), // Optional ], ],
Usage
Basic File Operations
use Illuminate\Support\Facades\Storage; // Use the azure disk $disk = Storage::disk('azure'); // Upload a file $disk->put('path/to/file.txt', 'Contents'); // Upload from a stream $disk->putStream('path/to/file.txt', fopen('/local/file.txt', 'r')); // Read a file $contents = $disk->get('path/to/file.txt'); // Check if file exists if ($disk->exists('path/to/file.txt')) { // ... } // Delete a file $disk->delete('path/to/file.txt'); // Copy a file $disk->copy('source.txt', 'destination.txt'); // Move a file $disk->move('old-location.txt', 'new-location.txt');
Getting File Information
// Get file size in bytes $size = $disk->size('path/to/file.txt'); // Get last modified timestamp $timestamp = $disk->lastModified('path/to/file.txt'); // Get MIME type $mimeType = $disk->mimeType('path/to/file.txt');
Directory Operations
// List files in a directory $files = $disk->files('path/to/directory'); // List all files recursively $allFiles = $disk->allFiles('path/to/directory'); // List directories $directories = $disk->directories('path/to/directory'); // Delete a directory and all its contents $disk->deleteDirectory('path/to/directory');
URLs
// Get the public URL $url = $disk->url('path/to/file.jpg'); // Returns: https://your-account.blob.core.windows.net/container/path/to/file.jpg // Generate a temporary signed URL (SAS token) $url = $disk->temporaryUrl('path/to/file.jpg', now()->addHours(1)); // With custom permissions $url = $disk->temporaryUrl('path/to/file.jpg', now()->addHours(1), [ 'permissions' => 'rw', // read + write ]);
Using as Default Disk
To use Azure as your default filesystem disk, set in your .env:
FILESYSTEM_DISK=azure
Then you can use the Storage facade directly:
use Illuminate\Support\Facades\Storage; Storage::put('file.txt', 'Contents'); $url = Storage::url('file.txt');
Private Files & Temporary URLs
Azure Blob Storage controls access at the container level, not per-file like S3. This means all blobs in a container share the same access level. The recommended approach for serving private files is:
- Keep your container private (the default)
- Use
temporaryUrl()to generate time-limited SAS-signed URLs for frontend display
Visibility Model
| Azure Access Level | Flysystem Visibility | Description |
|---|---|---|
| Private (no header) | private |
No anonymous access. All requests require authentication or SAS token. |
| Blob | public |
Anonymous read access for individual blobs only. |
| Container | public |
Anonymous read and list access for all blobs. |
Recommended Workflow
use Illuminate\Support\Facades\Storage; $disk = Storage::disk('azure'); // Store a file (private by default) $disk->put('invoices/invoice-001.pdf', $pdfContents); // Generate a temporary URL for display (expires in 30 minutes) $url = $disk->temporaryUrl('invoices/invoice-001.pdf', now()->addMinutes(30)); // Use in a Blade template // <a href="{{ $url }}">Download Invoice</a> // <img src="{{ $url }}" alt="Preview">
Visibility Configuration
Add visibility settings to your disk config in config/filesystems.php:
'azure' => [ 'driver' => 'azure', 'account_name' => env('AZURE_STORAGE_ACCOUNT_NAME'), 'account_key' => env('AZURE_STORAGE_ACCOUNT_KEY'), 'container' => env('AZURE_STORAGE_CONTAINER'), 'visibility' => [ 'default' => env('AZURE_STORAGE_VISIBILITY', 'private'), 'allow_set' => env('AZURE_STORAGE_ALLOW_SET_VISIBILITY', false), ], ],
visibility.default— The fallback visibility when the container access level cannot be determined. Defaults toprivate.visibility.allow_set— Whenfalse(default), callingsetVisibility()throws an exception with a helpful message. Set totrueto allow changing the container's public access level via the Flysystem API.
// Check the container's visibility $visibility = $disk->getVisibility('any-path'); // 'public' or 'private' // Set visibility (only when allow_set is true) $disk->setVisibility('any-path', 'private');
Note: Since Azure controls access at the container level, the
$pathargument tovisibility()andsetVisibility()is ignored — the operation applies to the entire container.
SAS Token Generation
For advanced SAS token generation, you can use the SasTokenGenerator directly:
use AliNauf\AzureStorage\Support\SasTokenGenerator; $generator = new SasTokenGenerator( accountName: config('azure-storage.account_name'), accountKey: config('azure-storage.account_key'), ); // Generate a blob SAS token $sas = $generator->generateBlobSas( container: 'mycontainer', blob: 'path/to/file.jpg', expiry: now()->addHours(2), permissions: 'r', // read only ); // Generate a full signed URL $url = $generator->generateSignedUrl( container: 'mycontainer', blob: 'path/to/file.jpg', expiry: now()->addHours(2), ); // Generate a container-level SAS token $containerSas = $generator->generateContainerSas( container: 'mycontainer', expiry: now()->addDays(7), permissions: 'rl', // read + list );
SAS Permissions
| Permission | Description |
|---|---|
r |
Read |
w |
Write |
d |
Delete |
l |
List |
a |
Add |
c |
Create |
Direct Client Usage
For advanced use cases, you can use the client directly:
use AliNauf\AzureStorage\AzureBlobStorageClient; $client = new AzureBlobStorageClient( accountName: config('azure-storage.account_name'), accountKey: config('azure-storage.account_key'), container: config('azure-storage.container'), ); // Upload a blob $response = $client->putBlob('path/to/file.txt', 'Contents', 'text/plain'); // Get blob properties $properties = $client->getBlobProperties('path/to/file.txt'); // Returns: ['content_length' => 123, 'content_type' => 'text/plain', 'last_modified' => 1234567890, 'etag' => '...'] // List blobs with prefix $result = $client->listBlobs('path/to/', 100); // Returns: ['blobs' => [...], 'next_marker' => '...'] // Copy a blob $response = $client->copyBlob('source.txt', 'destination.txt');
Testing
composer test
Changelog
Please see CHANGELOG for more information on what has changed recently.
Contributing
Contributions are welcome! Please see CONTRIBUTING.md for details on:
- Setting up the development environment
- Running tests
- Code style guidelines
- Submitting pull requests
Security
If you discover a security vulnerability, please email directly instead of using the issue tracker.
Credits
License
The MIT License (MIT). Please see License File for more information.