DEV Community

Tyler Smith
Tyler Smith

Posted on

Validating an upload as an image OR a video with Laravel

Laravel's Validator makes it simple to validate a request's file field as an image using the 'image' rule, and you can hack together rules for validating a video by restricting MIME types.

$request->validate([
    'image_upload' => 'image|max:1024',
    'video_upload' => 'mimetypes:video/avi,video/mpeg,video/quicktime|max:102400'
]);
Enter fullscreen mode Exit fullscreen mode

But what happens if you have a single upload field that should accept a video that's up to ten megabytes, or accept an image that's a megabyte or less? That's a lot trickier with Laravel's Validator: there doesn't seem to be an elegant solution for this using Laravel's built-in validation rules.

Thankfully, Laravel allows us to create our own custom validation rules. We can create a custom rule closure that checks if the upload is an image or a video, then validates the rules based on the upload type.

$request->validate([
    'file', // Confirm the upload is a file before checking its type.
    function ($attribute, $value, $fail) {
        $is_image = Validator::make(
            ['upload' => $value],
            ['upload' => 'image']
        )->passes();

        $is_video = Validator::make(
            ['upload' => $value],
            ['upload' => 'mimetypes:video/avi,video/mpeg,video/quicktime']
        )->passes();

        if (!$is_video && !$is_image) {
            $fail(':attribute must be image or video.');
        }

        if ($is_video) {
            $validator = Validator::make(
                ['video' => $value],
                ['video' => "max:102400"]
            );
            if ($validator->fails()) {
                $fail(":attribute must be 10 megabytes or less.");
            }
        }

        if ($is_image) {
            $validator = Validator::make(
                ['image' => $value],
                ['image' => "max:1024"]
            );
            if ($validator->fails()) {
                $fail(":attribute must be one megabyte or less.");
            }
        }
    }
]);
Enter fullscreen mode Exit fullscreen mode

I'll be the first to admit: this code looks pretty inelegant. But it works, and the closure leverages existing Validator rules like 'image' and 'max'.

If you prefer a more object-oriented approach, you could extract this code to a Custom Rule Object, and maybe extract methods for is_video() and is_image(). You could even make the max upload sizes configurable in the Rule object's constructor–the sky is the limit!

Hopefully this post saves you some time if you run into this particular challenge in one of your own projects. Also, please drop a comment if you know a more elegant way of accomplishing this!

Discussion (0)