league/glide
On-demand image manipulation server for PHP. Resize, crop, and apply effects via a simple HTTP API. Automatically caches transformed images with far-future headers, supports GD/Imagick/libvips, Flysystem storage, multiple response types, and signed URLs for security.
## Getting Started
### Minimal Setup
1. **Installation**:
```bash
composer require league/glide
use League\Glide\ServerFactory;
$server = ServerFactory::create([
'source' => storage_path('app/public/images'), // Original images
'cache' => storage_path('app/public/cache'), // Processed images cache
]);
/images/{filename} to a controller method:
public function serveImage(Request $request, string $filename) {
return $server->outputImage($filename, $request->query());
}
<img src="/images/profile.jpg?w=200&h=200&fit=crop">
source (original images) and cache (processed images) paths.ServerFactory::create() for quick setup.?w=500&h=500).Dynamic Image Serving:
outputImage() with $request->query() to dynamically handle all URL parameters (e.g., ?w=300&h=300&fit=crop).$server->outputImage('product.jpg', $request->query());
Static Transformations:
<img src="/images/hero.jpg?w=1200&fm=webp&q=80">
Framework Integration:
public function handle(Request $request, Closure $next) {
$path = $request->path();
if (str_starts_with($path, 'images/')) {
$filename = substr($path, 7);
return $server->outputImage($filename, $request->query());
}
return $next($request);
}
Route::prefix('images')->group(function () {
Route::get('{filename}', [ImageController::class, 'serve']);
});
Caching Strategies:
cache path).Cache-Control headers automatically.$server->getCache()->delete('path/to/cached/image.jpg');
Custom Manipulators:
League\Glide\Api\Manipulator\AbstractManipulator to add new effects (e.g., watermarks).$manipulators = [
// Default manipulators...
new App\Glide\Manipulators\Watermark(),
];
$api = new League\Glide\Api\Api($imageManager, $manipulators);
$server = new League\Glide\Server($source, $cache, $api);
Signed URLs:
$server->setSignatureKey('your-secret-key');
$signedUrl = $server->getSignedUrl('image.jpg', ['w' => 500], '+1 hour');
Storage Integration:
$source = new League\Flysystem\Filesystem(
new League\Flysystem\AwsS3Adapter(...)
);
Batch Processing:
$server->outputImage('original.jpg', ['w' => 100, 'h' => 100]);
$server->outputImage('original.jpg', ['w' => 300, 'h' => 300]);
Path Mismatches:
source path matches the actual location of original images.base_url to avoid prefix conflicts (e.g., /images/ in URLs but not in filesystem paths).Cache Invalidation:
Driver Limitations:
imagick or libvips for performance.phpinfo() for availability.URL Encoding:
my image.jpg → my%20image.jpg).Memory Limits:
memory_limit. Adjust or use imagick/libvips for better handling.Check Cache Path:
cache directory is writable and has sufficient space.Log Manipulations:
$server->getApi()->setDebug(true);
Validate Parameters:
try-catch for invalid parameters (e.g., negative width):
try {
$server->outputImage('image.jpg', $request->query());
} catch (\League\Glide\Exceptions\InvalidManipulationException $e) {
abort(400, $e->getMessage());
}
Test Locally:
php artisan serve to test image URLs before deploying.Predefined Sizes:
Format Selection:
webp for smaller file sizes (supported in modern browsers):
<img src="/image.jpg?fm=webp&q=80">
Driver Prioritization:
ServerFactory:
ServerFactory::create([
'source' => storage_path('images'),
'cache' => storage_path('cache'),
'driver' => 'imagick', // or 'libvips'
]);
Lazy Loading:
lazy directive for offscreen images:
<img src="/image.jpg?w=500" loading="lazy">
Custom Responses:
League\Glide\Response\AbstractResponse.Middleware Integration:
outputImage().Event Listeners:
glide.image.processed) to log or analyze usage.Testing:
Server in unit tests:
$mockServer = Mockery::mock(League\Glide\Server::class);
$mockServer->shouldReceive('outputImage')->andReturn('mocked-response');
```markdown
### Laravel-Specific Tips
1. **Service Provider Setup**:
- Bind Glide to the container for dependency injection:
```php
public function register() {
$this->app->singleton(League\Glide\Server::class, function ($app) {
return ServerFactory::create([
'source' => $app->storagePath('app/public/images'),
'cache' => $app->storagePath('app/public/cache'),
'driver' => config('glide.driver', 'gd'),
]);
});
}
```
2. **Configuration File**:
- Add to `config/glide.php`:
```php
return [
'driver' => env('GLIDE_DRIVER', 'gd'),
'source' => storage_path('app/public/images'),
'cache' => storage_path('app/public/cache'),
'base_url' => '/images',
];
```
3. **Artisan Command**:
- Create a command to clear the cache:
```php
php artisan glide:clear-cache
```
4. **View Composers**:
- Inject the Glide server into views:
```php
View::composer('*', function ($view) {
$view->with('glide', app(League\Glide\Server::class));
});
```
Usage in Blade:
```html
<img src="{{ $glide->getSignedUrl('image.jpg', ['w' => 300], '+1 hour') }}">
```
5. **Queue Processing**:
- Offload heavy processing to queues:
```php
dispatch(new ProcessImageJob('image.jpg', ['w' => 1000, 'h' =>
How can I help you explore Laravel packages today?