carone / laravel-media
Adds media functionality to laravel apps
Installs: 1
Dependents: 0
Suggesters: 0
Security: 0
Stars: 0
Watchers: 0
Forks: 0
Open Issues: 0
pkg:composer/carone/laravel-media
Requires
- php: ^8.2
- carone/laravel-common: ^1.0
- illuminate/database: ^12.0
- illuminate/support: ^12.0
- intervention/image-laravel: ^1.5
Requires (Dev)
- illuminate/http: ^12.0
- mockery/mockery: ^1.6
- orchestra/testbench: ^10.0
- phpunit/phpunit: ^11.0
This package is auto-updated.
Last update: 2025-12-31 15:40:43 UTC
README
A comprehensive media management package for Laravel applications that provides a clean, facade-based API for handling various media types including images, videos, audio files, and documents.
Installation
Install the package via Composer:
composer require carone/laravel-media
Publish the configuration file:
php artisan vendor:publish --provider="Carone\Media\CaroneMediaServiceProvider" --tag="config"
Run the migrations:
php artisan migrate
⚠️ IMPORTANT: Public API
This package provides ONLY ONE public interface: the Media facade.
External projects should NEVER directly access internal classes like:
- ❌
Carone\Media\Services\* - ❌
Carone\Media\Strategies\* - ❌
Carone\Media\Models\* - ❌
Carone\Media\Contracts\*
Always use the facade:
- ✅
Carone\Media\Facades\Media
Basic Usage
All media operations are performed through the Media facade:
use Carone\Media\Facades\Media; // Store a new media file $media = Media::store([ 'file' => $uploadedFile, 'name' => 'My Image', 'description' => 'A beautiful landscape photo', 'type' => 'image' ]); // Get media by ID $media = Media::getById(1); // Get media by type with pagination $result = Media::getByType('image', limit: 10, offset: 0); // Search media $result = Media::search('landscape', type: 'image', limit: 5); // Serve media file return Media::serve('image', 'filename.jpg'); // Serve thumbnail return Media::thumbnail('image', 'filename.jpg'); // Delete media Media::delete(1); // Delete multiple media files $result = Media::deleteMultiple([1, 2, 3]); // Delete all media of a specific type $result = Media::deleteByType('image'); // Clean up orphaned files $result = Media::cleanupOrphanedFiles('image'); // Get enabled media types $types = Media::getEnabledTypes();
Configuration
Configure media types and settings in config/media.php:
return [ 'enabled_types' => [ 'image' => [ 'enabled' => true, 'max_file_size' => 10240, // KB 'allowed_extensions' => ['jpg', 'jpeg', 'png', 'gif', 'webp'], 'thumbnails' => [ 'enabled' => true, 'width' => 300, 'height' => 300, ], ], 'video' => [ 'enabled' => true, 'max_file_size' => 102400, // KB 'allowed_extensions' => ['mp4', 'avi', 'mov', 'wmv'], ], // ... other types ], 'storage' => [ 'disk' => 'public', 'path' => 'media', ], ];
Media Types
The package supports four media types:
- Image: JPEG, PNG, GIF, WebP with automatic thumbnail generation
- Video: MP4, AVI, MOV, WMV
- Audio: MP3, WAV, OGG, AAC
- Document: PDF, DOC, DOCX, TXT
Each type can be individually enabled/disabled in the configuration.
API Response Format
Public Search Endpoints (GET /api/media/search, GET /api/media/type/{type})
These public endpoints return a minimal, SEO-friendly format:
{
"data": [
{
"id": 1,
"name": "My Image",
"description": "A beautiful landscape photo",
"date": "2025-01-15",
"type": "image",
"thumbnail_url": "https://example.com/media/thumbnails/1",
"media_url": "https://example.com/media/images/photo.jpg"
}
],
"total": 50,
"limit": 20,
"offset": 0
}
Public Response Fields:
id- Media resource ID (for detail pages, routing)name- Display namedescription- Optional description (for alt text, tooltips)date- ISO date stringtype- Media type (image, video, audio, document)thumbnail_url- Thumbnail URL (null if no thumbnail)media_url- Direct URL to media file
Single Media Resource (GET /api/media/{id})
The detail endpoint returns complete information:
{
"id": 1,
"name": "My Image",
"description": "A beautiful landscape photo",
"type": "image",
"file_name": "image_20231025_123456.jpg",
"file_size": 2048576,
"mime_type": "image/jpeg",
"source": "local",
"path": "/storage/media/images/image_20231025_123456.jpg",
"thumbnail_path": "/storage/media/images/thumbnails/image_20231025_123456.jpg",
"meta_data": {
"width": 1920,
"height": 1080,
"exif": {...}
},
"created_at": "2023-10-25T12:34:56.000000Z",
"updated_at": "2023-10-25T12:34:56.000000Z"
}
Paginated Results
Public browsing and search endpoints return simplified data:
{
"current_page": 1,
"data": [
{
"id": 1,
"name": "example.jpg",
"description": "Example image",
"date": "2024-01-01",
"type": "image",
"thumbnail_url": "http://localhost/media/thumbnails/1",
"media_url": "http://localhost/media/uploads/2024/01/example.jpg"
}
],
"per_page": 15,
"total": 100
}
Management endpoints return complete resource data:
{
"id": 1,
"name": "example.jpg",
"description": "Example image",
"date": "2024-01-01",
"type": "image",
"file_extension": "jpg",
"file_size": 1024000,
"thumbnail_id": 1234,
"metadata": {
"dimensions": {"width": 1920, "height": 1080},
"exif": {...}
},
"created_at": "2024-01-01T12:00:00.000000Z",
"updated_at": "2024-01-01T12:00:00.000000Z"
}
Search Results
{
"data": [...], // Array of media resources (format depends on endpoint)
"total": 10,
"offset": 0,
"limit": 20,
"query": "landscape",
"type": "image"
}
Media Serving
Path-Based URLs
Media files are served using clean, SEO-friendly path-based URLs:
GET /media/{path}
Examples:
- /media/images/2024/photo.jpg
- /media/documents/reports/annual-report.pdf
- /media/videos/demo.mp4
The path corresponds directly to the file's location in storage, making URLs predictable and clean.
Thumbnails
Thumbnails are served by ID (since they can be on different disks):
GET /media/thumbnails/{id}
Example:
- /media/thumbnails/1
URL Generation
The public search endpoints automatically generate these URLs:
{
"media_url": "https://example.com/media/images/photo.jpg",
"thumbnail_url": "https://example.com/media/thumbnails/1"
}
Security
- All file uploads are validated for type and size
- File extensions are strictly checked against allowed lists
- MIME type validation prevents malicious uploads
- Automatic cleanup of orphaned files
Error Handling
The facade will throw appropriate exceptions:
try { $media = Media::store($data); } catch (\InvalidArgumentException $e) { // Invalid media type or validation failed } catch (\Exception $e) { // Other storage errors }
Testing
Run the package tests:
composer test
Package Architecture (Internal)
⚠️ WARNING: The following information is for package development only.
External projects should NEVER access these internal components directly. Always use the Media facade.
Internal Structure
src/
├── Facades/
│ └── Media.php # ✅ PUBLIC API - Use this
├── MediaManager.php # ❌ INTERNAL - Do not use
├── CaroneMediaServiceProvider.php # ❌ INTERNAL - Do not use
├── Contracts/ # ❌ INTERNAL - Do not use
├── Services/ # ❌ INTERNAL - Do not use
├── Strategies/ # ❌ INTERNAL - Do not use
├── Models/ # ❌ INTERNAL - Do not use
├── Enums/ # ❌ INTERNAL - Do not use
└── Utilities/ # ❌ INTERNAL - Do not use
Key Internal Components
- MediaManager: Central orchestrator (accessed via facade)
- Services: Business logic layer
- Strategies: Media type-specific processing
- Models: Database entities
- Contracts: Service interfaces
License
This package is open-sourced software licensed under the MIT license.
Contributing
Please see CONTRIBUTING for details.
Changelog
Please see CHANGELOG for more information on what has changed recently.
A configurable media management package for Laravel applications. Easily handle media uploads, storage, and metadata (images, videos, audio, and documents) in your Laravel backend projects using clean, reusable Actions and the Strategy Pattern.
💡 Perfect for projects where you want consistent, reusable media logic across multiple Laravel apps.
Features
- 🎯 Action-Based Architecture - Clean, reusable Actions for all media operations
- 🏗️ Strategy Pattern - Extensible design for different media types
- 🖼️ Automatic Thumbnails - Generate thumbnails for images
- 📁 Multiple Storage - Support for local and external media
- 🔍 Search & Filter - Built-in search and pagination
- 🛡️ File Validation - Configurable validation rules per media type
- 🚀 Ready-to-use API - Complete REST API endpoints
- 📝 Comprehensive Logging - Detailed error logging and debugging
Installation
Require the package via Composer:
composer require carone/laravel-media
Laravel will auto-discover the service provider.
Configuration
Publish the configuration file (optional):
php artisan vendor:publish --provider="Carone\Media\CaroneMediaServiceProvider" --tag=config
This creates a config/media.php file in your app.
Database Migration
Run the included migration to create the media_resources table
php artisan migrate
Table structure: (Required fields are marked with *)
| Column | Type | Description |
|---|---|---|
| id* | bigint | Primary key |
| type* | enum(image, video, audio, document) | Type of media |
| source* | enum(local, external) | File source |
| file_name* | string | Original file name (with extension) |
| path | string | Local storage path |
| url | string | External URL (if any) |
| name* | string | Readable name |
| description | text | Description |
| date | date | Date |
| meta | json | Extra metadata |
| timestamps* | — | Created/updated time |
Quick Start
Upload Media
use Carone\Media\Actions\StoreMediaAction; // Upload a local image $media = StoreMediaAction::run([ 'type' => 'image', 'file' => $request->file('image'), 'name' => 'My Beautiful Image', 'description' => 'A description of the image', ]); // Upload external media $media = StoreMediaAction::run([ 'type' => 'video', 'source' => 'external', 'url' => 'https://www.youtube.com/watch?v=example', 'name' => 'External Video', ]);
Get Media
use Carone\Media\Actions\GetMediaAction; // Get media by type with pagination $images = GetMediaAction::byType('image', $limit = 20, $offset = 0); // Get single media item $media = GetMediaAction::byId(1); // Search media $results = GetMediaAction::make()->search('vacation photos', 'image');
Delete Media
use Carone\Media\Actions\DeleteMediaAction; // Delete single media $success = DeleteMediaAction::run($mediaId); // Bulk delete $result = DeleteMediaAction::make()->deleteMultiple([1, 2, 3]);
Serve Files
The package automatically provides routes for serving files:
<!-- Original image --> <img src="/media/image/my-image.jpg" alt="My Image"> <!-- Thumbnail (images only) --> <img src="/media/image/thumbnails/my-image.jpg" alt="Thumbnail">
API Endpoints
The package provides ready-to-use REST API endpoints:
GET /api/media/types # Get available media types
GET /api/media/type/{type} # Get media by type (paginated)
GET /api/media/search # Search media
POST /api/media/upload # Upload media
GET /api/media/{id} # Get media by ID
DELETE /api/media/{id} # Delete media
DELETE /api/media/bulk # Bulk delete media
GET /media/{type}/{filename} # Serve media files
GET /media/{type}/thumbnails/{filename} # Serve thumbnails
Migration from Existing Controllers
Replace your existing controller logic with Actions:
// Before (your existing controller) public function uploadMedia(MediaUploadRequest $request) { // ... complex upload logic ... } // After (using this package) public function uploadMedia(Request $request) { $media = StoreMediaAction::run([ 'type' => $request->input('type'), 'file' => $request->file('file'), 'name' => $request->input('name'), ]); return response()->json(['success' => true, 'media' => $media]); }
Advanced Features
Custom Validation
Configure validation rules per media type:
// config/media.php 'validation' => [ 'image' => ['mimes:jpg,jpeg,png,gif', 'max:5120'], // 5MB max 'video' => ['mimes:mp4,mov', 'max:51200'], // 50MB max 'audio' => ['mimes:mp3,wav', 'max:10240'], // 10MB max 'document' => ['mimes:pdf,doc,docx', 'max:10240'], ],
Storage Configuration
'disk' => env('DEFAULT_MEDIA_STORAGE_DISK', 'public'), // Main media files disk (not customizable per upload) 'storage_path' => 'media/{path}', 'enabled_types' => ['image', 'video', 'audio', 'document'], // Thumbnail configuration 'thumbnails' => [ 'enabled' => true, 'disk' => null, // If null, uses same disk as media. Can be customized per upload. 'storage_path' => 'media/thumbnails/{path}', ],
Important: The main media disk is configured globally and cannot be overridden per upload. This ensures consistent, path-based media URLs. Thumbnails can still use custom disks.
Route Protection
The package provides separate public and protected routes:
Public Routes (no authentication required):
GET /api/media/types- Get enabled media typesGET /api/media/type/{type}- Browse media by typeGET /api/media/search- Search mediaGET /api/media/{id}- Get media detailsGET /media/{path}- Serve media filesGET /media/thumbnails/{id}- Serve thumbnails
Protected Routes (authentication required by default):
POST /api/media/upload- Upload mediaDELETE /api/media/{id}- Delete mediaDELETE /api/media/bulk- Bulk delete media
Configure protection in config/media.php:
'management_middleware' => ['auth'], // Default: require authentication // Examples: 'management_middleware' => ['auth:sanctum'], // Use Sanctum 'management_middleware' => ['auth', 'admin'], // Require admin role 'management_middleware' => [], // No protection (not recommended for production)
Error Handling
All Actions throw appropriate exceptions:
try { $media = StoreMediaAction::run($data); } catch (\InvalidArgumentException $e) { // Handle validation errors } catch (\Exception $e) { // Handle general errors }
Image Processing Driver Setup
The package supports two image processing drivers: Imagick and GD. Choose based on your application's needs.
Driver Comparison
| Feature | Imagick | GD |
|---|---|---|
| Installation | Requires php-imagick extension | Usually built-in with PHP |
| Memory Usage | Streams data (~20-30 MB for 4000×4000) | Loads full image (~180-200 MB for 4000×4000) |
| Large Images | Handles efficiently | Requires high memory_limit |
| Performance | Generally faster | Adequate for small images |
| Availability | Needs separate installation | Built into most PHP installs |
Understanding Memory Behavior
Imagick processes images by streaming data in chunks:
4000 × 4000 image = ~25-30 MB memory usage
GD loads the entire decompressed image into memory:
4000 × 4000 × 4 bytes (RGBA) = 64 MB base
+ Source buffer + processing buffers
= 180-200 MB total memory usage
Which Driver to Choose?
Choose Imagick if:
- You handle large images (>2000px dimensions)
- You have high-volume image uploads
- You need optimal memory efficiency
- You can install the php-imagick extension
Choose GD if:
- Your images are typically small (<2000px)
- You have low upload volumes
- Imagick is not available in your environment
- You want to avoid additional dependencies
Both drivers are fully supported. The package defaults to Imagick but will automatically fall back to GD if Imagick is not installed.
Installation
Ubuntu/Debian
sudo apt-get update
sudo apt-get install php-imagick
sudo systemctl restart php-fpm # or apache2/nginx
Windows
- Download the appropriate DLL from PECL or windows.php.net
- Place it in your PHP
extdirectory (e.g.,C:\php\ext\php_imagick.dll) - Edit
php.iniand add:extension=imagick - Restart your web server
macOS
brew install imagemagick pecl install imagick
Then add to your php.ini:
extension=imagick.so
Verification
After installation, verify your setup:
php artisan media:info
This will display:
- Active image driver and available extensions
- PHP memory limit and recommendations
- General media package configuration
Or check directly:
php -m | grep imagick
Configuration
The driver is configured in config/media.php:
'image_driver' => env('IMAGE_DRIVER', 'imagick'),
To use GD:
IMAGE_DRIVER=gd
Oversized Image Handling
The package can automatically scale down very large images to prevent memory issues and reduce storage:
// config/media.php 'processing' => [ 'image' => [ 'scale_oversized_images' => true, // Enable/disable automatic scaling 'max_dimension_before_encode' => 3000, // Threshold for scaling 'scaled_max_dimension' => 2560, // Target size (2.5K, still HD) ], ],
When enabled:
- 4000×4000 image → scaled to 2560×2560
- 2000×1500 image → kept at original size
- Works with both Imagick and GD drivers
Automatic Fallback
If Imagick is configured but not installed, the package will:
- Log a warning
- Automatically fall back to GD
Memory Recommendations
Recommended Settings
For applications handling large images, configure adequate memory:
# php.ini memory_limit = 256M # Minimum recommended for large images (4000×4000)
Memory Requirements by Image Size
| Image Size | Minimum memory_limit | Recommended |
|---|---|---|
| Up to 2000×2000 | 128M | 256M |
| Up to 4000×4000 | 256M | 512M |
| Larger than 4000×4000 | 512M+ | 1G |
Note: Imagick uses less memory than GD for the same images. With scale_oversized_images enabled, memory requirements are further reduced.
Check Your Settings
Run the info command to see your current configuration:
php artisan media:info
This will warn you if your memory limit is below the recommended 256M.
Troubleshooting
Error: "Imagick class not found"
- Extension is not installed or not enabled in php.ini
- Run:
php -m | grep imagickto check
Error: "Call to undefined function imagick_..."
- Wrong version of PHP or Imagick
- Reinstall:
pecl uninstall imagick && pecl install imagick
Still getting memory errors with Imagick
- Check PHP memory limit:
php -i | grep memory_limit - Increase if needed:
memory_limit = 256M(minimum) - Verify Imagick is actually being used:
php artisan media:info - Enable
scale_oversized_imagesin config
Images look worse quality
- Check quality settings in
config/media.php:'quality' => 85, // 0-100, higher = better quality
- Verify
scale_oversized_imagessettings if images are being scaled unexpectedly
Want to disable automatic scaling
- Set
scale_oversized_imagestofalsein config - Ensure adequate memory_limit for your image sizes
Performance Comparison
Testing with a 4000×4000 JPEG (5 MB on disk):
| Operation | GD | Imagick |
|---|---|---|
| Load image | ~180 MB RAM | ~25 MB RAM |
| Resize to 2560×2560 | ~220 MB RAM | ~30 MB RAM |
| Generate thumbnail | ~250 MB RAM | ~35 MB RAM |
| Total time | 3.2s | 1.8s |
Results may vary based on server configuration and image complexity.
Summary
Both drivers work well for their intended use cases:
- Imagick: Best for applications with large images or high upload volumes
- GD: Suitable for applications with small images or where Imagick is unavailable
The package is configured to use Imagick by default but will work seamlessly with either driver.
Documentation
For detailed usage examples and advanced features, see USAGE.md.
Architecture
This package uses:
- Actions (via
lorisleiva/laravel-actions) for clean, reusable operations - Strategy Pattern for handling different media types
- Dependency Injection for extensibility
- Laravel's Storage system for file management
License
This package is open-sourced software licensed under the MIT license.
💬 About
carone/laravel-media is built for developers who need consistent, configurable media handling across multiple Laravel projects — without duplicating models, migrations, or upload logic.
Designed for backend efficiency.
Presentation is up to you. 🎨