In Eloquent We Trust, or don’t assume find() always finds something

This short lesson will be both about Laravel and about general software development. One of the most often and common mistakes made by developers is not checking input data. And then not only you get random errors of something “not found”, but sometimes much worse – expose your system to vulnerabilities and attacks. So let’s discuss that with examples from Eloquent world.

Quite often in the code I see lines like this:

$category = Category::with('products')->find(Input::get('category_id'));
foreach ($category->products as $product) {
	// ... some action
}

Or even something like that:

Category::find(Input::get('category_id'))->update(['name' => 'New name']);

Of course, Eloquent offers really convenient methods for writing as little code as possible, sometimes almost all in one line. But. Calling find() actually assumes that the entry might not be found successfully. What then? If we continue without checking the results, then we would get errors.

So, looking at Laravel code, there are couple of things we can do here to feel safe.
First option – check if the entry is found and then proceed:

$category = Category::find(Input::get('category_id'));
if ($category) {
  $category->update(['name' => 'New name']);
  // ... return success or redirect to somwehere
} else {
  // ... return error
}

Second option – same thing, only shorter, without else statement:

$category = Category::find(Input::get('category_id'));
if (!$category) return redirect('error');
$category->update(['name' => 'New name']);

Or even shorter:

if (!$category = Category::find(Input::get('category_id'))) 
	return redirect('error');
$category->update(['name' => 'New name']);

Also – there’s a separate function called findOrFail(). With this one it’s safe to not do any more checking:

$category = Category::findOrFail(Input::get('category_id'));
$category->update(['name' => 'New name']);

In case of entry not found, Laravel will throw an exception of type Illuminate\Database\Eloquent\ModelNotFoundException – and then it’s your choice how to handle it by general error pages or try-catch blocks.

General advice – always check the data

These examples are only a tiny case of the possible errors related to input data. Everything that comes through the browser must be checked – if the parameter is present, if it’s a number when it has to be, whether it doesn’t containt malicious HTML/JavaScript code etc. Quite often amateur developers rely on just Input::get() or $request->get() statements and trust their visitors to always pass the correct URL or POST parameters. Really bad practice.

Getting back to the case of Laravel, there are multiple convenient ways to prevent incorrect data entries. Each of them require thorough explanation, which I won’t do here, but will just list general rules of thumb with links for you to read:

Any more tips to protect the websites from malicious data?

Like our articles?
Check out our Laravel online courses!

2 COMMENTS

  1. I got something like this in App\Http\Requests\FormRequest:

    public function all()
    {
    $inputs = parent::all();
    $toBeIgnored = config(‘app.ignore_clean’);
    $toBeCleaned = array_except($inputs, $toBeIgnored);
    $ignored = array_only($inputs, $toBeIgnored);
    $cleaned = clean($toBeCleaned);

    return array_merge($ignored, $cleaned);
    }

    clean is a helper method from HTMLPurifier for Laravel 5 https://github.com/mewebstudio/Purifier

LEAVE A REPLY

Please enter your comment!
Please enter your name here