Try Live
Add Docs
Rankings
Pricing
Docs
Install
Install
Docs
Pricing
More...
More...
Try Live
Rankings
Enterprise
Create API Key
Add Docs
Laravel Medialibrary
https://github.com/spatie/laravel-medialibrary
Admin
A package that allows you to associate files with Eloquent models, offering a simple API for
...
Tokens:
33,845
Snippets:
210
Trust Score:
-
Update:
5 months ago
Context
Skills
Chat
Benchmark
92.1
Suggestions
Latest
Show doc for...
Code
Info
Show Results
Context Summary (auto-generated)
Raw
Copy
Link
# Laravel Media Library Laravel Media Library is a comprehensive file management package for Laravel applications that associates files with Eloquent models. It provides a powerful and intuitive API for handling file uploads, storing media on any Laravel filesystem disk (local, S3, etc.), and generating multiple image conversions. The package automatically manages file metadata, custom properties, and supports responsive images with lazy loading. The library seamlessly integrates with Laravel's filesystem abstraction, enabling developers to organize media into collections, apply image manipulations through conversions, and serve files through customizable URL generators. It supports various media types including images, PDFs, videos, and SVGs, with automatic conversion and optimization capabilities. Media items are stored in a database table with polymorphic relationships, allowing any Eloquent model to have associated media files. ## Installation and Setup Run migrations to create the media table ```bash php artisan migrate ``` Publish configuration file ```bash php artisan vendor:publish --provider="Spatie\MediaLibrary\MediaLibraryServiceProvider" --tag="config" ``` Add HasMedia interface and InteractsWithMedia trait to your model ```php use Illuminate\Database\Eloquent\Model; use Spatie\MediaLibrary\HasMedia; use Spatie\MediaLibrary\InteractsWithMedia; class Article extends Model implements HasMedia { use InteractsWithMedia; // Optional: Register media collections public function registerMediaCollections(): void { $this->addMediaCollection('featured') ->singleFile() ->acceptsMimeTypes(['image/jpeg', 'image/png']); $this->addMediaCollection('gallery'); } // Optional: Register conversions public function registerMediaConversions(?Media $media = null): void { $this->addMediaConversion('thumb') ->width(100) ->height(100) ->sharpen(10); $this->addMediaConversion('large') ->width(1200) ->height(800) ->performOnCollections('gallery'); } } ``` ## Adding Media from Files Upload file from request ```php use App\Models\Article; $article = Article::find(1); // From uploaded file $article->addMedia($request->file('image')) ->toMediaCollection('featured'); // From file path $article->addMedia('/path/to/image.jpg') ->toMediaCollection('gallery'); // With custom properties $article->addMedia($request->file('document')) ->withCustomProperties(['author' => 'John Doe', 'category' => 'reports']) ->toMediaCollection('documents'); // Preserve original file $article->copyMedia('/path/to/important.pdf') ->toMediaCollection('archives'); // Specify disk $article->addMedia($request->file('video')) ->toMediaCollection('videos', 's3'); ``` ## Adding Media from URLs Download and attach remote files ```php // From URL with mime type validation $article->addMediaFromUrl('https://example.com/photo.jpg', ['image/jpeg', 'image/png']) ->toMediaCollection('images'); // With custom name and filename $article->addMediaFromUrl('https://example.com/document.pdf') ->usingName('Annual Report') ->usingFileName('report-2024.pdf') ->withCustomProperties(['year' => 2024]) ->toMediaCollection('reports'); // From URL without validation $article->addMediaFromUrl('https://example.com/file.zip') ->toMediaCollection('downloads'); ``` ## Adding Media from Base64 Handle base64 encoded files ```php // From base64 string $base64Image = 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg=='; $article->addMediaFromBase64($base64Image, ['image/png', 'image/jpeg']) ->usingFileName('encoded-image.png') ->toMediaCollection('images'); // From data URI $dataUri = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg=='; $article->addMediaFromBase64($dataUri) ->usingFileName('data-uri-image.png') ->toMediaCollection('images'); ``` ## Adding Media from Strings and Streams Create files from text content or streams ```php // From string $article->addMediaFromString('This is the content of my text file.') ->usingFileName('notes.txt') ->usingName('Article Notes') ->toMediaCollection('documents'); // From stream $stream = fopen('https://example.com/video.mp4', 'r'); $article->addMediaFromStream($stream) ->usingFileName('stream-video.mp4') ->toMediaCollection('videos'); ``` ## Adding Multiple Files from Request Batch upload files from request ```php // Multiple files by keys $fileAdders = $article->addMultipleMediaFromRequest(['image1', 'image2', 'image3']); foreach ($fileAdders as $fileAdder) { $fileAdder->toMediaCollection('gallery'); } // All files from request $allFileAdders = $article->addAllMediaFromRequest(); foreach ($allFileAdders as $key => $fileAdder) { $fileAdder->toMediaCollection('uploads'); } // Single file from request by key $article->addMediaFromRequest('featured_image') ->withCustomProperties(['featured' => true]) ->toMediaCollection('images'); ``` ## Retrieving Media Get media items from collections ```php $article = Article::find(1); // Get all media from collection $mediaItems = $article->getMedia('gallery'); // Get first media $firstImage = $article->getFirstMedia('images'); // Get last media $lastImage = $article->getLastMedia('images'); // Check if model has media if ($article->hasMedia('gallery')) { $images = $article->getMedia('gallery'); } // Get media with filters $recentMedia = $article->getMedia('documents', ['created_at' => 'desc']); $filteredMedia = $article->getMedia('images', function($media) { return $media->getCustomProperty('featured') === true; }); ``` ## Getting Media URLs Retrieve URLs for media files ```php $media = $article->getFirstMedia('images'); // Public URL $url = $media->getUrl(); $fullUrl = $media->getFullUrl(); // URL for conversion $thumbUrl = $media->getUrl('thumb'); $largeUrl = $media->getUrl('large'); // Temporary URL (for private S3 files) $temporaryUrl = $media->getTemporaryUrl(now()->addMinutes(30)); $conversionTempUrl = $media->getTemporaryUrl(now()->addHours(1), 'thumb'); // First/Last media URL $firstUrl = $article->getFirstMediaUrl('images'); $firstThumbUrl = $article->getFirstMediaUrl('images', 'thumb'); $lastUrl = $article->getLastMediaUrl('gallery'); ``` ## Getting Media Paths Retrieve filesystem paths for media files ```php $media = $article->getFirstMedia('documents'); // Full path $path = $media->getPath(); // Path for conversion $thumbPath = $media->getPath('thumb'); // Relative path $relativePath = $media->getPathRelativeToRoot(); // First/Last media path $firstPath = $article->getFirstMediaPath('images'); $lastPath = $article->getLastMediaPath('images', 'thumb'); ``` ## Working with Custom Properties Store and retrieve metadata with media ```php $media = $article->getFirstMedia('documents'); // Set custom property $media->setCustomProperty('author', 'Jane Smith') ->setCustomProperty('department', 'Marketing') ->save(); // Get custom property $author = $media->getCustomProperty('author'); $department = $media->getCustomProperty('department', 'Unknown'); // Check if property exists if ($media->hasCustomProperty('author')) { $author = $media->getCustomProperty('author'); } // Forget property $media->forgetCustomProperty('author')->save(); // Add with custom properties during upload $article->addMedia($request->file('file')) ->withCustomProperties([ 'author' => 'John Doe', 'tags' => ['important', 'review'], 'metadata' => ['version' => '1.0'] ]) ->toMediaCollection('files'); ``` ## Defining Media Collections Configure collections with validation and behavior ```php class Product extends Model implements HasMedia { use InteractsWithMedia; public function registerMediaCollections(): void { // Single file collection $this->addMediaCollection('thumbnail') ->singleFile() ->acceptsMimeTypes(['image/jpeg', 'image/png', 'image/webp']); // Limited collection (keep only 5 latest) $this->addMediaCollection('photos') ->onlyKeepLatest(5) ->withResponsiveImages(); // Collection with custom disk $this->addMediaCollection('videos') ->useDisk('s3') ->storeConversionsOnDisk('public'); // Collection with file validation $this->addMediaCollection('documents') ->acceptsFile(function ($file, $model) { return $file->mimeType === 'application/pdf' && $file->size < 5000000; }) ->acceptsMimeTypes(['application/pdf']); // Collection with fallback $this->addMediaCollection('avatar') ->singleFile() ->useFallbackUrl('/images/default-avatar.png') ->useFallbackPath(public_path('images/default-avatar.png')); } } ``` ## Defining Conversions Create image manipulations and transformations ```php use Spatie\MediaLibrary\MediaCollections\Models\Media; class Article extends Model implements HasMedia { use InteractsWithMedia; public function registerMediaConversions(?Media $media = null): void { // Basic resize $this->addMediaConversion('thumb') ->width(150) ->height(150) ->sharpen(10); // Crop and format $this->addMediaConversion('square') ->crop(500, 500) ->format('webp') ->quality(90); // Collection-specific conversion $this->addMediaConversion('preview') ->width(800) ->height(600) ->performOnCollections('gallery', 'images') ->nonQueued(); // Keep original format $this->addMediaConversion('large') ->width(1920) ->keepOriginalImageFormat(); // Conditional conversion $this->addMediaConversion('watermarked') ->width(1200) ->watermark(public_path('watermark.png')) ->when($media?->collection_name === 'public-gallery'); // Video thumbnail $this->addMediaConversion('video-thumb') ->extractVideoFrameAtSecond(5) ->width(640) ->performOnCollections('videos'); // Responsive images $this->addMediaConversion('responsive') ->width(1200) ->withResponsiveImages(); // PDF preview $this->addMediaConversion('pdf-preview') ->pdfPageNumber(1) ->width(600) ->performOnCollections('documents'); } } ``` ## Regenerating Conversions Regenerate conversions after modifying definitions ```bash # Regenerate all conversions php artisan media-library:regenerate # Regenerate for specific model php artisan media-library:regenerate --model="App\Models\Article" # Regenerate for specific IDs php artisan media-library:regenerate --model="App\Models\Article" --ids=1,2,3 # Regenerate only specific conversions php artisan media-library:regenerate --only=thumb,large # Force regeneration php artisan media-library:regenerate --force ``` ## Working with Conversions Check and manage generated conversions ```php $media = $article->getFirstMedia('images'); // Check if conversion exists if ($media->hasGeneratedConversion('thumb')) { $thumbUrl = $media->getUrl('thumb'); } // Get all conversion names $conversions = $media->getMediaConversionNames(); // Returns: ['thumb', 'large', 'square'] // Mark conversion as generated $media->markAsConversionGenerated('thumb'); // Mark as not generated $media->markAsConversionNotGenerated('thumb'); // Get available URL from list of conversions $url = $media->getAvailableUrl(['large', 'medium', 'thumb']); // Returns URL of first available conversion // Get all generated conversions $generatedConversions = $media->getGeneratedConversions(); ``` ## Responsive Images Generate and serve responsive image sets ```php // Enable in collection public function registerMediaCollections(): void { $this->addMediaCollection('images') ->withResponsiveImages(); } // Enable in conversion public function registerMediaConversions(?Media $media = null): void { $this->addMediaConversion('hero') ->width(1920) ->withResponsiveImages(); } // Enable during upload $article->addMedia($request->file('image')) ->withResponsiveImages() ->toMediaCollection('images'); // Get responsive image URLs $media = $article->getFirstMedia('images'); $urls = $media->getResponsiveImageUrls(); // Get srcset attribute $srcset = $media->getSrcset(); $conversionSrcset = $media->getSrcset('hero'); // Check if has responsive images if ($media->hasResponsiveImages()) { echo "<img src='{$media->getUrl()}' srcset='{$media->getSrcset()}' />"; } // In Blade template <img src="{{ $media->getUrl() }}" srcset="{{ $media->getSrcset() }}" sizes="(max-width: 768px) 100vw, 50vw" alt="{{ $media->name }}" /> ``` ## Streaming Media Responses Stream media as HTTP responses ```php use Illuminate\Support\Facades\Route; // Direct download Route::get('/media/{media}/download', function (Media $media) { return $media; }); // Inline display Route::get('/media/{media}/view', function (Media $media) { return $media->toInlineResponse(request()); }); // Custom chunk size for large files Route::get('/media/{media}/stream', function (Media $media) { return $media->setStreamChunkSize(2 * 1024 * 1024) // 2MB chunks ->toResponse(request()); }); // Stream in controller class MediaController extends Controller { public function download(Media $media) { if (!auth()->user()->can('download', $media)) { abort(403); } return $media->toResponse(request()); } } ``` ## Creating ZIP Archives Download multiple media files as ZIP ```php use Spatie\MediaLibrary\Support\MediaStream; // Create ZIP from media collection Route::get('/article/{article}/photos.zip', function (Article $article) { $mediaItems = $article->getMedia('photos'); return MediaStream::create('photos.zip')->addMedia($mediaItems); }); // Multiple collections Route::get('/article/{article}/all-media.zip', function (Article $article) { return MediaStream::create('article-media.zip') ->addMedia($article->getMedia('images')) ->addMedia($article->getMedia('documents')) ->addMedia($article->getMedia('videos')); }); // Custom folder structure in ZIP $article->getMedia('documents')->each(function ($media) { $media->setCustomProperty('zip_filename_prefix', 'documents/'); $media->save(); }); $article->getMedia('images')->each(function ($media) { $media->setCustomProperty('zip_filename_prefix', 'images/'); $media->save(); }); return MediaStream::create('organized.zip') ->addMedia($article->getMedia('documents')) ->addMedia($article->getMedia('images')); // With custom ZIP options return MediaStream::create('archive.zip') ->useZipOptions(function (&$options) { $options['comment'] = 'Generated by Laravel Media Library'; }) ->addMedia($mediaItems); ``` ## Updating and Managing Media Update media properties and manage collections ```php // Update media metadata $media = Media::find(1); $media->name = 'Updated Name'; $media->setCustomProperty('status', 'reviewed'); $media->save(); // Update collection $newMediaArray = [ ['id' => 1, 'name' => 'First Image', 'custom_properties' => ['order' => 1]], ['id' => 2, 'name' => 'Second Image', 'custom_properties' => ['order' => 2]], ]; $article->updateMedia($newMediaArray, 'gallery'); // Clear collection $article->clearMediaCollection('gallery'); // Clear except specific items $keepMedia = $article->getFirstMedia('gallery'); $article->clearMediaCollectionExcept('gallery', $keepMedia); // Delete specific media $article->deleteMedia(1); // by ID $article->deleteMedia($media); // by object // Move media to another model $product = Product::find(1); $media = $article->getFirstMedia('images'); $newMedia = $media->move($product, 'photos'); // Copy media to another model $copiedMedia = $media->copy($product, 'photos', 'public', 'custom-name.jpg'); // Copy with callback $copiedMedia = $media->copy($product, 'photos', '', '', function ($fileAdder) { return $fileAdder->withCustomProperties(['copied_at' => now()]); }); ``` ## Deleting Media Remove media files and database records ```php // Delete media (removes file and database record) $media = Media::find(1); $media->delete(); // Delete model preserving media $article = Article::find(1); $article->deletePreservingMedia(); // Force delete with soft deletes $article->forceDelete(); // deletes media automatically // Clear all media before deleting model $article->clearMediaCollection(); $article->delete(); ``` ## Rendering Media as HTML Generate HTML img tags with attributes ```php $media = $article->getFirstMedia('images'); // Basic img tag echo $media->img(); // Output: <img src="/storage/1/image.jpg" alt="image"> // With conversion echo $media->img('thumb'); // Output: <img src="/storage/1/conversions/image-thumb.jpg" alt="image"> // With custom attributes echo $media->img('thumb', ['class' => 'img-fluid rounded', 'id' => 'hero-image']); // Output: <img src="/storage/1/conversions/image-thumb.jpg" alt="image" class="img-fluid rounded" id="hero-image"> // Using invoke echo $media('large', ['loading' => 'lazy']); // In Blade {!! $media->img('thumb', ['class' => 'thumbnail']) !!} // As Htmlable (automatic escaping) {{ $media }} {{-- Renders as img tag --}} ``` ## Email Attachments Attach media to emails ```php use Illuminate\Mail\Mailable; class InvoiceMail extends Mailable { public function __construct(public Media $invoice) { } public function build() { return $this->view('emails.invoice') ->attach($this->invoice->toMailAttachment()); } } // With conversion $mail->attach($media->mailAttachment('pdf-preview')); // Multiple attachments class ReportMail extends Mailable { public function __construct(public Article $article) { } public function build() { $mail = $this->view('emails.report'); foreach ($this->article->getMedia('documents') as $media) { $mail->attach($media->toMailAttachment()); } return $mail; } } ``` ## Custom Path Generators Customize file storage paths ```php use Spatie\MediaLibrary\Support\PathGenerator\PathGenerator; use Spatie\MediaLibrary\MediaCollections\Models\Media; class CustomPathGenerator implements PathGenerator { public function getPath(Media $media): string { return $media->model_type . '/' . $media->model_id . '/'; } public function getPathForConversions(Media $media): string { return $this->getPath($media) . 'conversions/'; } public function getPathForResponsiveImages(Media $media): string { return $this->getPath($media) . 'responsive/'; } } // Register in config/media-library.php 'path_generator' => CustomPathGenerator::class, // Or per model 'custom_path_generators' => [ App\Models\Article::class => CustomPathGenerator::class, ], ``` ## Custom URL Generators Customize URL generation ```php use Spatie\MediaLibrary\Support\UrlGenerator\BaseUrlGenerator; class CustomUrlGenerator extends BaseUrlGenerator { public function getUrl(): string { $path = $this->getPathRelativeToRoot(); // Custom CDN URL return 'https://cdn.example.com/' . $path; } } // Register in config/media-library.php 'url_generator' => CustomUrlGenerator::class, ``` ## Custom File Namers Customize generated file names ```php use Spatie\MediaLibrary\Support\FileNamer\FileNamer; use Spatie\MediaLibrary\Conversions\Conversion; class CustomFileNamer extends FileNamer { public function originalFileName(string $fileName): string { // Add timestamp to filename $name = pathinfo($fileName, PATHINFO_FILENAME); return $name . '-' . time(); } public function conversionFileName(string $fileName, Conversion $conversion): string { $name = pathinfo($fileName, PATHINFO_FILENAME); return $name . '-' . $conversion->getName(); } public function responsiveFileName(string $fileName): string { return pathinfo($fileName, PATHINFO_FILENAME); } } // Register in config/media-library.php 'file_namer' => CustomFileNamer::class, ``` ## Queuing Conversions Control conversion job execution ```php // Queue all conversions by default (config) 'queue_conversions_by_default' => true, // Non-queued conversion $this->addMediaConversion('thumb') ->width(150) ->nonQueued(); // Queued conversion $this->addMediaConversion('large') ->width(2000) ->queued(); // Custom queue during upload $article->addMedia($request->file('image')) ->onQueue('image-processing') ->toMediaCollection('images'); // Custom queue for conversions public function registerMediaConversions(?Media $media = null): void { $this->addMediaConversion('large') ->width(1920) ->queued(); } ``` ## Working with Media Types Determine media type and properties ```php $media = $article->getFirstMedia('files'); // Get media type $type = $media->type; // 'image', 'pdf', 'video', 'audio', 'other' // Get extension $extension = $media->extension; // 'jpg', 'png', 'pdf', etc. // Get mime type $mimeType = $media->mime_type; // 'image/jpeg', 'application/pdf', etc. // Get file size $size = $media->size; // in bytes $humanSize = $media->humanReadableSize; // '2.5 MB' // Get disk driver $driver = $media->getDiskDriverName(); // 'local', 's3', etc. $conversionDriver = $media->getConversionsDiskDriverName(); // Type checking $typeFromExtension = $media->getTypeFromExtension(); $typeFromMime = $media->getTypeFromMime(); ``` ## Advanced Filtering Filter media collections programmatically ```php // Filter by custom property $featuredMedia = $article->getMedia('images', function ($media) { return $media->getCustomProperty('featured') === true; }); // Filter by mime type $pdfDocuments = $article->getMedia('documents', function ($media) { return $media->mime_type === 'application/pdf'; }); // Filter by size $largeFiles = $article->getMedia('files', function ($media) { return $media->size > 1000000; // larger than 1MB }); // Filter by date $recentMedia = $article->getMedia('images', function ($media) { return $media->created_at->isAfter(now()->subDays(7)); }); // Complex filtering $filteredMedia = $article->getMedia('gallery', function ($media) { return $media->mime_type === 'image/jpeg' && $media->size < 5000000 && $media->hasCustomProperty('approved') && $media->getCustomProperty('approved') === true; }); ``` ## Configuration Examples Common configuration patterns ```php // config/media-library.php return [ // Use S3 for media storage 'disk_name' => env('MEDIA_DISK', 's3'), // Increase max file size to 50MB 'max_file_size' => 1024 * 1024 * 50, // Use Redis queue for conversions 'queue_connection_name' => 'redis', 'queue_name' => 'media-conversions', // Always queue conversions 'queue_conversions_by_default' => true, // Custom path structure 'path_generator' => App\MediaLibrary\CustomPathGenerator::class, // CDN URL generator 'url_generator' => App\MediaLibrary\CdnUrlGenerator::class, // Optimize images aggressively 'image_optimizers' => [ Spatie\ImageOptimizer\Optimizers\Jpegoptim::class => [ '-m80', '--strip-all', '--all-progressive', ], ], // Use Imagick for better quality 'image_driver' => 'imagick', // Temporary URLs valid for 1 hour 'temporary_url_default_lifetime' => 60, // Add cache headers for S3 'remote' => [ 'extra_headers' => [ 'CacheControl' => 'max-age=31536000, public', 'Expires' => gmdate('D, d M Y H:i:s', time() + 31536000) . ' GMT', ], ], ]; ``` ## Laravel Media Library provides a production-ready solution for managing media files in Laravel applications, handling everything from basic file uploads to advanced image processing with conversions and responsive images. The package's flexible architecture allows for extensive customization through path generators, URL generators, and file namers, while its integration with Laravel's queue system ensures optimal performance for resource-intensive operations. The library excels at organizing media through collections, enabling developers to define validation rules, storage locations, and behavior for different types of files. With built-in support for multiple filesystems, automatic image optimization, and polymorphic relationships, it scales seamlessly from small projects to large applications with millions of media files. The comprehensive API covers common use cases like generating thumbnails, creating ZIP downloads, streaming responses, and attaching files to emails, making it the complete media management solution for modern Laravel applications.