overtrue/laravel-qcs
Laravel integration for Qiniu Cloud Storage (QCS) that adds a Qiniu filesystem driver, letting you store, retrieve, and manage files on Qiniu through Laravel's Storage facade. Simple configuration and a familiar API make it easy to offload uploads and assets to the cloud.
composer require <vendor>/<package>:"^4.0".composer require <vendor>/<package>:"^5.0". No manual provider registration is needed — package discovery wires up the image bindings and the validator extensions.ImageServiceProvider entry from config/app.php (and any providers array in bootstrap/providers.php) if you carried it over from the Intervention Image 2 era. Leaving it in is the most likely cause of a container binding conflict on Laravel 13.ims / tms rules to a FormRequest and run one request through it. This exercises three things at once — rule registration on cold start, the image driver binding, and the PNG/JPEG encode path — which is exactly the surface that was broken in this release.class UploadRequest extends FormRequest
{
public function rules(): array
{
return [
'avatar' => ['required', 'file', 'ims'],
'banner' => ['required', 'file', 'tms'],
];
}
}
Prefer the package's rule strings over hand-rolled validation. The tms / ims rules are the package's public contract; hand-writing image checks in a withValidator() closure means you lose the 300px proportional scaling and the PNG/JPEG encoding behaviour that the package guarantees across both drivers.
Keep driver selection in config, not in code. The package supports GD and Imagick and resolves the driver through the container. Set it via the published config / env var rather than calling ImageManager::imagick() directly, so a server without the imagick extension can fall back to GD without a code change.
Drive image work through the package service, not raw Intervention. Since 5.0.0 the package owns an Intervention 4 instance. When you need to post-process (thumbnails, conversions), resolve the package's image service and let it hand you a configured manager — otherwise you re-implement the 300px scaling rule in a second place and drift.
// Preferred: package-managed manager (driver already chosen)
$manager = app(ImageManager::class);
$image = $manager->read($path)
->scale(width: 300) // v4 proportional API
->encode(new PngEncoder(quality: 90));
Storage::disk('public')->put("thumbs/{$name}.png", (string) $image);
Integration tip — queue the encode, not the read. Encoding to PNG/JPEG is the expensive half. Read the upload synchronously in the request (so validation fails fast), persist the original, then do the scale/encode in a job.
Test the cold path explicitly. The bug fixed here only appeared on first use of the rules in a fresh process. A RefreshDatabase-based feature test that boots the app and immediately validates an upload is worth more than a unit test that constructs the validator by hand — the latter never exercises the registration hook.
Cover both drivers in CI. GD is almost always present; Imagick usually is not on the default runner. Matrix the extension so an Imagick-only regression can't ship, and assert PNG and JPEG output independently — they take different encoder branches.
Image::make(), ->resize($w, $h), ->save() and the Intervention\Image\ImageServiceProvider all disappear. In v4 you get a manager, call read(), use scale() (proportional) or resize() (explicit box), and encode() with an encoder object. ->resize() no longer preserves aspect ratio for you — if your code relied on v2's resize($w, null), switch to scale(width: ...) or you will ship squashed images that pass tests because the dimensions are right.intervention/image:^2, the install fails rather than degrades. Run composer why intervention/image before upgrading and resolve it first; composer update --with-all-dependencies only after the constraint is gone.ImageServiceProvider in config/app.php won't fail at boot; it fails on the first image operation with a binding/resolution error. If you see a container error naming an image class, check bootstrap/providers.php and the cached config before debugging anything else — and run php artisan config:clear after editing, since a cached config will keep the old provider list alive.boot() and not at the top of a controller. That's the same class of cold-start failure.How can I help you explore Laravel packages today?