Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Thumbnailbundle Laravel Package

just/thumbnailbundle

Just ThumbnailBundle integrates thumbnail generation into Symfony apps, providing configurable image filters, resizing, and caching for serving optimized previews from templates or controllers. It simplifies creating and managing thumbnail variants with minimal setup.

View on GitHub
Deep Wiki
Context7

Getting Started

Reality check first: just/thumbnailbundle is a Symfony 2/3/4 bundle, not a Laravel package. There is no service provider, no facade, no Blade integration, and no config/thumbnailbundle.php. Composer will install it into a Laravel app (it's just PHP), but nothing will auto-register — you'd be wiring Symfony's DI container and Twig by hand. Treat it as a reference implementation to mine, not a dependency to require.

If you're evaluating it for a Symfony project (or porting ideas to Laravel):

  1. composer require just/thumbnailbundle — then check composer.json for symfony/* version constraints before anything else. A bundle last tagged in 2025 but targeting Symfony 2/3/4 is the classic "maintained tag, stale internals" smell. Run composer why-not symfony/framework-bundle ^6.0 to see what blocks it.
  2. Register the bundle (bundles.php on modern Symfony, AppKernel on legacy) and publish its config — expect a key like just_thumbnail with cache path, image driver (GD/Imagick), quality, and default dimensions.
  3. Look here first: Resources/config/services.yml (or services.xml) and the bundle's routing file. That's where the actual value is — the route that serves /thumb/{path}/{width}/{height} and the service that wraps the image driver.

First use case to validate: in a Twig template, something like {{ asset('images/hero.jpg')|thumbnail(300, 200) }} should emit a URL to the bundle's generation route, which lazily writes a cached file on first request and serves it thereafter. If that round-trip works, the bundle is functional; if the filter is missing or the route 404s, stop there.

For a Laravel app, the fastest path is to read that controller + service pair (roughly 100–200 lines) and reimplement it with intervention/image and a Route::get('/thumbs/{path}') — you'll spend less time than fighting the framework mismatch.

Implementation Patterns

Symfony pattern the bundle encodes (copy this shape):

  • On-demand generation with filesystem-as-cache. No queue, no pre-generation. Request comes in → check if cache/thumbs/{hash}.jpg exists → if yes, X-Sendfile/readfile; if no, generate, write, serve. The URL is the cache key.
  • Dimensions in the URL path, so the web server or CDN can cache per-size and you get free horizontal scaling.
  • Twig filter as the ergonomic surface. Templates never call services; they pipe an asset path through |thumbnail(w, h) and get a URL. This is the single best idea in the bundle and it translates directly to a Blade directive: @thumb($path, 300, 200).
  • Driver abstraction over GD/Imagick. Swap the driver in config rather than in code.

Laravel translation, day-to-day:

// routes/web.php — mirror the bundle's route shape
Route::get('/thumbs/{size}/{path}', ThumbController::class)
    ->where('size', '\d+x\d+')
    ->where('path', '.*');

// controller: cache-first, generate-on-miss
$key = "thumbs/{$size}/".md5($path).'.jpg';
if (! Storage::disk('public')->exists($key)) {
    Image::make(Storage::disk('public')->path($path))
        ->fit(...explode('x', $size))
        ->save(Storage::disk('public')->path($key), 80);
}
return Storage::disk('public')->response($key, headers: ['Cache-Control' => 'public, max-age=31536000, immutable']);

Integration tips that carry over from the bundle's design:

  • Emit srcset from the same URL structure — 150x150, 300x300, 600x600 — and let the browser pick. The bundle's "size in the URL" model makes this trivial.
  • Pre-warm hot images with a queued job that hits the same URLs; the controller is idempotent, so warm-up is just a Http::get() loop.
  • Put the thumb route behind a cheap middleware (signed URL or a directory allowlist) rather than auth — you want CDN-cacheable, unauthenticated responses.

Gotchas and Tips

  • Path traversal is the headline risk. Any on-the-fly thumbnailer taking a {path} segment is an LFI and disk-fill vector. The bundle was written in the Symfony 2 era, when this was routinely overlooked. If you port the code, resolve the path with realpath() and assert it starts with your configured media root. Never pass user input straight to Image::make().
  • Unclamped dimensions = memory exhaustion. ?w=50000&h=50000 on a 12MP source will OOM PHP-FPM. Enforce a max width/height and a whitelist of allowed sizes; return 404 for anything else.
  • Stale thumbnails. If the URL is only path + size, changing the source image leaves the old thumb cached forever with immutable headers. The bundle's approach typically misses this — add a source mtime or content hash into the URL (/thumbs/300x200/{hash}/photo.jpg) so new content gets a new URL.
  • Cache directory permissions and web-server bypass. Debug order: (1) is the request even hitting PHP, or is nginx serving the file directly? (2) does the cache dir exist and is it writable by www-data? (3) is the driver extension (gd/imagick) actually installed? Silent blank images are almost always #3.
  • Check PHP 8 compatibility before committing. composer.json constraints, each()/create_function, and dynamic properties are the usual breakers in Symfony-2-era code. Run the test suite against your target PHP version, or just read the source — at this size it's a 20-minute read.
  • Extension points worth knowing: the image driver service (swap GD for Imagick or a cloud driver), the cache-path config, and the Twig filter itself (you can register a variant with different default quality). For Laravel, the equivalents are an ImageManager binding, config('thumbs.path'), and a Blade directive.
  • Project health signal: 3 stars, 0 dependents, and a score of 0.115 means nobody is filing issues against it. You are the only person who will ever debug this code. Budget accordingly — and for a Laravel app, the intervention/image + custom route above is roughly an afternoon of work with a package that has actual community support.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
elsayed85/laravel-api-exceptions
ouhssini/laravel-demo-mode
daworks/ncloud-outbound-mailer-driver
gp247/cms
ignibyte/aic-gates
nexa-merchant/blog
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
cgv/localized-resource