opheliadesign's avatar

Validate to see if an image is horizontal

Hi everyone,

I am trying to limit image uploads for a Blog to only horizontal photos. The following code works but I would like to include this into the validation errors if possible. Would a custom validator be able to handle this task? The image will not always be present, only if the user uploads one. Not sure where to begin with this, any help would be appreciated..

$image = $request->file('post_image');
            list($width, $height) = getimagesize($image);
            if ($width < $height)
            {
                // Need to add to errors, view uses $errors->all()
            }
0 likes
14 replies
Kryptonit3's avatar

you could put it in the form request under the authorize section

public function authorize()
{
    if ($this->request->has('image-name')) {
        $image = $this->request->get('image-name');
        if ($image->width < $image->height) {
            session()->flash('error', 'Image must be horizontal!');
            return false;
        }
    }
    
    // the above either wasn't required, or passed
    return true;
}

public function forbiddenResponse()
{
    return $this->redirector->to($this->getRedirectUrl())
        ->withInput($this->except($this->dontFlash));
}

You could also leave out the forbidden response message part, but on my sites I check for error or success in the session and have a flash banner.

https://mattstauffer.co/blog/laravel-5.0-form-requests#4.-create-your-formrequest

absiddiqueLive's avatar

After Validation Hook

The validator also allows you to attach callbacks to be run after validation is completed. This allows you to easily perform further validation and even add more error messages to the message collection. To get started, use the after method on a validator instance:

$validator = Validator::make(...);

$validator->after(function($validator) {
    if ($this->somethingElseIsInvalid()) {
        $validator->errors()->add('field', 'Something is wrong with this field!');
    }
});

if ($validator->fails()) {
    //
}
opheliadesign's avatar

Wow, thanks for the quick replies! I left out a key detail, I am using a Form Request. @Kryptonit3 would your method add the error to the $errors array so I can still use $errors->all() as would be the case with @absiddiqueLive's suggestion?

Kryptonit3's avatar

@opheliadesign if authorize() fails, it doesn't even traverse the rules() part of the form request. I suppose you could add a custom error to the $errors bag.

public function authorize()
{
    if ($this->request->has('image-name')) {
        $image = $this->request->get('image-name');
        if ($image->width < $image->height) {
            return false;
        }
    }
    
    // the above either wasn't required, or passed
    return true;
}

public function forbiddenResponse()
{
    return $this->redirector->to($this->getRedirectUrl())
        ->withInput()
        ->withErrors(['error-key' => 'Image must be horizontal!']);
}

and set error-key to whatever you are checking for in the html ( $errors->has('error-key') )

Not sure if the $this->except($this->dontFlash) is needed either. Play around with both ideas.

absiddiqueLive's avatar

@opheliadesign You may follow

$validator = Validator::make(...);
$image = $request->file('post_image');
list($width, $height) = getimagesize($image);

$validator->after(function($validator) use ($width, $height) {
    if ($width < $height) {
        $validator->errors()->add('post_image', 'Horizontal Image require !');
    }
});

if ($validator->fails()) {
    //
}
opheliadesign's avatar

@absiddiqueLive so you're suggesting validating twice, in other words? @Kryptonit3 I tried this and still run into the same error, Call to a member function all() on a non-object - because it is just flashing an Errors array, whereas I'm using $errors->all() in my view.

Also, the Authorize function is in use to check for Admin.. so I tried using a boolean to catch only this particular case. But, to be honest, I don't really like hacking the Authorize method like this..

<?php namespace App\Http\Requests;

use App\Http\Requests\Request;
use Auth;

class BlogPostRequest extends Request
{
    private $imageInvalid = false;

    /**
     * Determine if the user is authorized to make this request.
     *
     * @return bool
     */
    public function authorize()
    {
        if (!Auth::user()->is_admin) {
            return false;
        }

        if ($this->request->has('post_image')) {
            $image = $this->request->file('post_image');
            list($width, $height) = getimagesize($image);
            if ($width < $height)
            {
                $this->imageInvalid = true;
                return false;
            }
        }

        return true;
    }

    public function forbiddenResponse()
    {
        if ($this->imageInvalid)
        {
            return $this->redirector->to($this->getRedirectUrl())
                ->withInput()
                ->withErrors(['post_image' => 'Image must be horizontal - width longer than height']);
        }
    }

    /**
     * Get the validation rules that apply to the request.
     *
     * @return array
     */
    public function rules()
    {
        return [
            'title' => 'required',
            'body' => 'required',
            'post_image' => ['mimes:jpg,jpeg,gif,png', 'max:8000']
        ];
    }

}
Kryptonit3's avatar

yeah, just make a new rule called horizontal with your logic and just add it to the rules() array for the field in question.

public function rules()
{
    return [
        'title' => 'required',
        'body' => 'required',
        'post_image' => 'mimes:jpg,jpeg,gif,png|max:8000|horizontal' // why not use pipe character? |
    ];
}
opheliadesign's avatar

@Kryptonit3 make a new rule where? LOL

I understand that you can extend Validation but I'm not dealing with text here - will that work with files? I really like the idea of placing this logic in the Form Request. But I may just need to move the validator to the controller. I'm trying to avoid having logic spread all over the place, it's a pretty small project - just want it simple.

opheliadesign's avatar

Because this form request was so simple I just moved everything into the controller, problem solved... I'll explore this in more depth when I have more time.

Thanks guys :)

Please or to participate in this conversation.