Image manipulation
Server-side image-transform met disk-cache + nginx-static-fallback. Eerste hit doet PHP/Imagick, daarna serveert nginx direct van schijf. Zie IMAGE_MANIPULATION.md in project-root voor het volledige design.
Interne file — sha256-hash uit FileStorage
URL bevat hash + transform-spec + extensie. Immutable: zelfde input → zelfde URL.
return $image->url(
'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa',
width: 800,
height: 600,
fit: FitMode::Cover,
format: Format::Webp,
);/img/aa/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/800x600-cover-q75.webp
Auto-format via Accept-header
Format::Auto kijkt naar de huidige request — avif > webp > jpeg. URL bevat altijd een concreet formaat.
return [
'auto' => $image->url('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', width: 800, format: Format::Auto),
'webp' => $image->url('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', width: 800, format: Format::Webp),
'avif' => $image->url('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', width: 800, format: Format::Avif),
'jpeg' => $image->url('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', width: 800, format: Format::Jpeg),
];Array
(
[auto] => /img/aa/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/800-cover-q75.jpg
[webp] => /img/aa/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/800-cover-q75.webp
[avif] => /img/aa/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/800-cover-q75.avif
[jpeg] => /img/aa/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/800-cover-q75.jpg
)
Externe URL — HMAC-signed
Eerste request fetcht de remote bytes en ingest ze in FileStorage. Tampered sig → 403.
return $image->url(
'https://upload.wikimedia.org/wikipedia/commons/2/27/PNG_transparency_demonstration_1.png',
width: 600,
height: 400,
fit: FitMode::Cover,
format: Format::Webp,
);/img/extern/19/19982d272daba44d9ead20a09ad0f4d19f2ac019d295988c85bc0b77e438c2b4/600x400-cover-q75.webp?u=aHR0cHM6Ly91cGxvYWQud2lraW1lZGlhLm9yZy93aWtpcGVkaWEvY29tbW9ucy8yLzI3L1BOR190cmFuc3BhcmVuY3lfZGVtb25zdHJhdGlvbl8xLnBuZw&sig=H43sPge2cg8pp0-8yELtRJM4p8Jjh5EwIZ11bCSYop8
Fit-modes vergeleken
Cover (vult+snijdt), Contain (letterbox), Fit (geen padding), Crop (exacte uitsnede).
return [
'cover' => $image->url('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', width: 400, height: 300, fit: FitMode::Cover),
'contain' => $image->url('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', width: 400, height: 300, fit: FitMode::Contain),
'fit' => $image->url('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', width: 400, height: 300, fit: FitMode::Fit),
'crop' => $image->url('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', width: 400, height: 300, fit: FitMode::Crop),
];Array
(
[cover] => /img/aa/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/400x300-cover-q75.jpg
[contain] => /img/aa/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/400x300-contain-q75.jpg
[fit] => /img/aa/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/400x300-fit-q75.jpg
[crop] => /img/aa/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/400x300-crop-q75.jpg
)
DPR / retina-variant
dpr=2 op een 800×600-design levert een 1600×1200-render — en een aparte cache-bucket.
return [
'1x' => $image->url('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', width: 800, height: 600, dpr: 1),
'2x' => $image->url('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', width: 800, height: 600, dpr: 2),
];Array
(
[1x] => /img/aa/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/800x600-cover-q75.jpg
[2x] => /img/aa/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/800x600-cover-q75-dpr2.jpg
)
Productie-checklist:
apt install php-imagick— voor image-transformapt install ffmpeg— alleen voor video-thumbnails.env:IMAGE_SIGNING_SECRET=$(php -r "echo bin2hex(random_bytes(32));")- Symlink:
ln -s ../data/cache/img public/img(zodat nginx static-fallback werkt) - nginx:
location ^~ /img/ { try_files $uri /index.php$is_args$args; expires 1y; add_header Cache-Control "public, immutable"; }