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 [
//
];
}
}