php 104 lines · 3 tabs

Resize and Store User Avatars with Intervention Image in Laravel

Shared by codesnips Jul 2026
3 tabs
<?php

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;

class StoreAvatarRequest extends FormRequest
{
    public function authorize(): bool
    {
        return $this->user() !== null;
    }

    public function rules(): array
    {
        return [
            'avatar' => [
                'required',
                'file',
                'image',
                'mimes:jpeg,png,webp',
                'dimensions:min_width=128,min_height=128',
                'max:2048',
            ],
        ];
    }

    public function messages(): array
    {
        return [
            'avatar.dimensions' => 'The image must be at least 128x128 pixels.',
            'avatar.max' => 'The avatar may not be larger than 2MB.',
        ];
    }
}
3 files · php Explain with highlit

This snippet shows the full path of an avatar upload in Laravel: validating the incoming file, resizing it to a fixed square, writing both the derivative and (optionally) the original to a storage disk, and persisting the resulting path on the user model. Splitting the work across a Form Request, a controller, and a dedicated service keeps the controller thin and makes the resize logic reusable and testable.

In StoreAvatarRequest, the upload is constrained before any processing happens. The image rule rejects non-images, mimes narrows the accepted encodings, dimensions enforces a minimum size so tiny images are not upscaled into a blurry mess, and max caps the file at two megabytes to protect memory during decoding. Validating dimensions matters because Intervention decodes the whole bitmap into RAM, so an unchecked file is a denial-of-service risk.

AvatarService owns the actual transformation. store runs everything inside a DB::transaction so the database row and the files stay consistent, then deletes the previous avatar via deleteExisting to avoid orphaned blobs accumulating on disk. The resize uses cover() (a crop-to-fill) so every avatar comes out as a uniform 256x256 square regardless of the source aspect ratio, which keeps the UI grid tidy. The processed image is encoded to WebP with toWebp(80) for a good size-to-quality trade-off, and stored under a hashed, unpredictable filename so paths cannot be guessed. Using Storage::disk('public') means the same code works locally and against S3 by swapping configuration only.

AvatarController wires the pieces together: it type-hints StoreAvatarRequest so validation runs automatically, delegates to the service, refreshes the user, and returns the public URL through Storage::url. Note the file('avatar') accessor returns an UploadedFile, and the service treats it as a stream source rather than trusting the client-supplied name or extension.

The main trade-offs: encoding synchronously in the request keeps things simple but blocks the response, so under heavy load this work is often pushed to a queued job that reads the temp file. Storing WebP also assumes browser support, which is universal enough today but worth confirming for the target audience. This pattern is the right reach whenever user-generated images must be normalized to consistent dimensions and formats before serving.

Share this code

Here's the card — post it anywhere.

Resize and Store User Avatars with Intervention Image in Laravel — share card
Link copied