← webdev
meica.ch/werkstatt/webdev/ateliercms-asset-pipeline
← Webdev

AtelierCMS: asset pipeline fix — images were being served unoptimised

Found by accident: AtelierCMS was serving original uploaded images with no optimisation. A client uploaded a 6MB DSLR photo and it went straight to <img src>. The Lighthouse score was not great.

The CMS doesn’t have a built-in image pipeline. I added one — a small PHP script that sits between the URL and the filesystem.

// resize.php — called as /img/resize?src=uploads/photo.jpg&w=800
$src  = realpath(BASE_PATH . '/' . $_GET['src']);
$w    = (int) $_GET['w'];

// Guard: only serve files inside uploads/
if (!str_starts_with($src, realpath(BASE_PATH . '/uploads'))) {
    http_response_code(403); exit;
}

$cache_path = CACHE_DIR . '/' . md5($src . $w) . '.webp';

if (!file_exists($cache_path)) {
    $img = imagecreatefromstring(file_get_contents($src));
    // ... resize and save as WebP
    imagewebp($img, $cache_path, 82);
}

header('Content-Type: image/webp');
readfile($cache_path);

Cache is keyed by source path + width. On-demand generation, then served from cache. WebP output at quality 82 — good enough, not perfect.

Average file size went from ~3MB to ~180KB for typical site images. Not a complete image pipeline but it solves the 80% of the problem with 20% of the work.

The path traversal guard is not optional.