Filter Input Values In Form Request

In Laravel's Eloquent ORM, you may also use the create method to save a new model in one operation, rather than setting values one by one. The inserted model instance will be returned to you from the method. However, before doing so, you will need to specify either a fillable or guarded attribute on the model. It is also known as Mass Assignment.

A mass-assignment vulnerability occurs when a user passes an unexpected HTTP parameter through a request, and that parameter changes a column in your database you did not expect. For example, a malicious user might send an is_admin parameter through an HTTP request, which is then passed into your model's create method, allowing the user to escalate themselves to an administrator.

You can easily set $fillable in the model to allow those fields for mass assignment.

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class User extends Model
{
    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $fillable = ['name'];
}

Now, think of you've set multiple fillable values to your model, and you have different HTTP endpoints for updating users' data.

  • [update] /admin/user/{user}
  • [update]  /user

The first route is for administrators to update users' data. It's designed to update any fields of any user.

The second route is for users themselves updating their personal data. However, some of the fields is constrained to be modified, like email address, some status fields.

Of course you can limit the updated fields by doing so:

<?php

// ...

$user->update(
    $request->only(['name', 'phone', 'address'])
);

// ...

But I suggest there's another elegant way for this purpose like what we do in Eloquent.

We make a trait for providing $fillable availability for Form Request in Laravel. The sample code is shown below:

<?php

namespace App\Support\Traits;

trait RequestFillable
{
    /**
     * Prepare the data for validation.
     *
     * @return void
     */
    protected function prepareForValidation()
    {
        if (empty($this->fillable)) {
            return;
        }

        foreach ($this->keys() as $key) {
            if (! in_array($key, $this->fillable)) {
                $this->request->remove($key);
            }
        }
    }
}

In Laravel's Form Request, it will call prepareForValidation function before validate input data. This function exists in Illuminate\Validation\ValidatesWhenResolvedTrait and has no default action.

And now you can filter your inputs in Form Request by just setting $fillable property:

<?php

namespace App\Http\Requests\Foo;

use App\Support\Traits\RequestFillable;
use Illuminate\Foundation\Http\FormRequest;

class StoreFoo extends FormRequest
{
    use RequestFillable;

    $fillable = ['name', 'address'];

    /**
     * Determine if the user is authorized to make this request.
     *
     * @return bool
     */
    public function authorize()
    {
        return true;
    }

    /**
     * Get the validation rules that apply to the request.
     *
     * @return array
     */
    public function rules()
    {
        return [
            //
        ];
    }
}