Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

GiacomoM's avatar

Why don't use this?

$request->merge(array('inputname' => 'new value'));

its clean and unobtrusive.

7 likes
sharq's avatar

Thanks @jhauraw, still this is the best answer! However I think you can simplify by removing the return from the sanitizeInput function.

I like @martinbean solution very much, but the problem with that it doesn't keep the request consistent. It only works in your validator or if you accessing your variables through the all method. If you need the variable later for example you need to call: Input::get('firstname') it doesn't work, and you will never notice...

<?php namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;

abstract class Request extends FormRequest {

    /**
     * Validate the input.
     *
     * @param  \Illuminate\Validation\Factory  $factory
     * @return \Illuminate\Validation\Validator
     */
    public function validator($factory)
    {
        return $factory->make(
            $this->sanitizeInput(), $this->container->call([$this, 'rules']), $this->messages()
        );
    }

    /**
     * Sanitize the input.
     *
     * @return array
     */
    protected function sanitizeInput()
    {
        if (method_exists($this, 'sanitize'))
        {
            $this->container->call([$this, 'sanitize']);
        }

        return $this->all();
    }
}
// Individual Request Class

/**
 * Sanitize input before validation.
 *
 * @return array
 */
public function sanitize()
{
    $input = $this->all();

    $input['phone'] = phoneToDigits($input['phone']);

    $this->replace($input);
}
2 likes
Indemnity83's avatar

I refactored @jhauraw's method a bit to keep the individual request classes as clean and dry as possible, no doubt there's still room for improvement but I'm happy with this so far:

<?php

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;

abstract class Request extends FormRequest
{
    /**
     * The attributes that are expected in the request
     *
     * @var array
     */
    protected $expectedFields = [];

    /**
     * Validate the input.
     *
     * @param  \Illuminate\Validation\Factory $factory
     * @return \Illuminate\Validation\Validator
     */
    public function validator($factory)
    {
        return $factory->make(
            $this->sanitizeInput(), $this->container->call([$this, 'rules']), $this->messages()
        );
    }

    /**
     * Sanitize the input.
     *
     * @return array
     */
    protected function sanitizeInput()
    {
        array_filter($this->expectedFields, function ($field) {
            $this->existsOrCreate($field);
            $this->sanitizeField($field);
        }, ARRAY_FILTER_USE_BOTH);

        return $this->all();
    }

    /**
     * Check if a field exists in the input array, if it does not, a default.
     *
     * @param      $field
     * @param null $default
     */
    protected function existsOrCreate($field, $default = null)
    {
        $input = $this->all();
        if (!isset($input[$field])) {
            $input[$field] = $default;
            $this->replace($input);
        }
    }

    /**
     * Call the sanitize method for each field if it exists
     *
     * @param $field
     */
    protected function sanitizeField($field)
    {
        $input = $this->all();
        if (method_exists($this, 'sanitize' . studly_case($field))) {
            $input[$field] = $this->container->call([$this, 'sanitize' . studly_case($field)], [$input[$field]]);
            $this->replace($input);
        }
    }

}
// Individual Request Classes

    /**
     * The attributes that are expected in the request
     *
     * @var array
     */
    protected $expectedFields = ['phone', 'street', 'city', 'postal-code'];

    /**
     * Sanitize function for the phone field.
     * 
     * @param $input
     * @return string
     */
    public function sanitizePhone($input)
    {
        return phoneToDigits($input);
    }

    /**
     * Sanitize function for the postal-code field.
     *
     * @param $input
     * @return string
     */
    public function sanitizePostalCode($input)
    {
        return postalToAlphaNum($input);
    }
5 likes
drilon's avatar

still not an official solution ? :(

1 like
GuntarV's avatar

How about overwriting it directly like this: $request->attribute = 'new value';

aantigual's avatar

For me it works well like this:

$data = new Model();
$data->fill($request->all());
$myinputClean = $this->sanitizeInput($data->myinputToSave)
$data->myinputToSave = myinputClean;
$data->save();
giorgiosaud's avatar

only add this to your LoginController


/**
     * Get the login username to be used by the controller using login as nickname or email field to check.
     *
     * @return string
     */
    public function username()
    {
        if(Request::has('login')){
            $field = filter_var(Request::input('login'), FILTER_VALIDATE_EMAIL) ? 'email' : 'username';
            Request::merge([$field => Request::input('login')]);
            Request::offsetUnset('login');
        }

        if(Request::has('email')){
          return 'email';
        }
        return 'username';
    }

and in your views.auth.login replace the email field with an login text field

luoshiben's avatar

Apologies for commenting on this well after the post was created, but as far as I can tell there's still not an official solution for this. FWIW, here's my take (which combines some of the offered solutions) if it helps anyone else. I've tested on Laravel 5.3, though it probably works for Laravel 5.x.

First, create a SanitizesInput trait:

trait SanitizesInput
{
    /**
     * @Override Illuminate\Foundation\Http\FormRequest::getValidatorInstance
     */
    protected function getValidatorInstance()
    {
        $this->sanitizeInput();
        return parent::getValidatorInstance();
    }

    /**
     * Sanitize the input.
     */
    protected function sanitizeInput()
    {
        if (method_exists($this, 'sanitize')) {
            $input = $this->all();
            $sanitizedInput = $this->container->call([$this, 'sanitize'], ['input' => $input]);
            $input = array_merge($input, $sanitizedInput);
            $this->replace($input);
        }
    }
}

Now, use this trait on an Request class (likely, your abstract "base" request class).

Finally, in your request class you can define a sanitize() method to sanitize any input values as needed. Example:

class FooCreateRequest extends Request
{
    public function authorize()
    {
        return true;
    }

    public function rules()
    {
        return [
            'email' => 'email',
        ];
    }

    public function sanitize(array $input)
    {
        return [
            'email' => preg_replace('/\s+/', '', strtolower($input['email']))
        ];
    }
}
meigwilym's avatar

As I've just come accross this, here's my solution mostly inspired by pmall's idea.

Personally I think this is a middleware problem, i.e. to modify the request before it hits the app.

The class, on all non-GET requests, checks for all input types that are strings (not arrays, files etc) and trims them.

<?php

namespace App\Http\Middleware;

use Closure;

class TrimMiddleware
{
    /**
     * Trim all form fields on all requests that aren't GET
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
        if(!$request->isMethod('GET'))
        {
            $input = $request->all();

            // trim strings only
            $request->merge(array_map(function($item){
                return (is_string($item)) ? trim($item) : $item;
            }, $input));
        }

        return $next($request);
    }
}

I currently have no need to have non-trimmed string fields, so this works fine for my use case.

Indemnity83's avatar

Laravel 5.4 added middleware out of the box to trim strings and convert empty strings to null which covers the most common use cases here. But it also adds a TransformsRequest middleware that can be extended to cover the less common transformations you might have.

For example, to ucfirst the name fields:

<?php
namespace App\Http\Middleware;

class UCWords extends TransformsRequest
{
    /**
     * The attributes that should be transformed.
     *
     * @var array
     */
    protected $attributes = [
        'first_name',
        'last_name',
    ];

    /**
     * Transform the given value.
     *
     * @param  string  $key
     * @param  mixed  $value
     * @return mixed
     */
    protected function transform($key, $value)
    {
        if (in_array($key, $this->attributes)) {
            return is_string($value) ? ucwords($value) : $value;
        }

        return $value;
        
    }
}

Then register the middleware and add it to the appropriate routes (or controller constructor)

// Within App\Http\Kernel Class...

protected $routeMiddleware = [
    // existing middleware
    'ucwords' => \App\Middleware\UCWords::class,
];
Route::post('admin/profile', function () {
    //
})->middleware('ucwords');
3 likes
Florian Bolka's avatar

I think the best way to modify any input is to override the prepareForValidation method of the ValidatesWhenResolvedTrait.

Here is a quick example of how I did it.

/**
 * Modify the input values
 *
 * @return void
 */
protected function prepareForValidation() {

    // get the input
    $input = array_map('trim', $this->all());

    // check newsletter
    if (!isset($input['newsletter'])) {
        $input['newsletter'] = false;
    }

    // replace old input with new input
    $this->replace($input);
}

Hope it helps!

2 likes
Nitro's avatar

@Indemnity83 Thanks for the class. I'm new to Laravel. Where should I place the 'phoneToDigits' and 'postalToAlphaNum' methods? They'll be used in more than one request.

Indemnity83's avatar

phoneToDigits and postalToAlphaNum were just psudo-code; you need to write the real code or methods for those yourself and place them wherever it makes sense in your application.

msbrime's avatar

I extended the FormRequest class and overrode the prepareForValidation method which is called before validation happens.

// anything I don't want trimmed here
protected $untrimmable = [];

// replace the request with trimmed request here
protected function prepareForValidation()
{
    return $this->replace($this->trimData($this->all()));
}

// recursively trim the fields in the request here
protected function trimData($data,$keyPrefix = '')
{
    $trimmedFields = array_map(function($value,$field) use ($keyPrefix){
        // if the value is an array handle it as
        // a request array and send along the prefix
        if(is_array($value)){
            return $this->trimData($value,$this->dotIndex($keyPrefix,$field));
        }
        
        // if the field is not in the specified fields to be
        // left untrimmed
        if(
            !in_array($this->dotIndex($keyPrefix,$field),$this->dontTrim) && 
            !in_array($this->dotIndex($keyPrefix,$field), $this->untrimmable)
        ) {
            return trim((string) $value);
        }
        
        return $value;
        
    }, $data,array_keys($data));
    
    return array_combine(array_keys($data),$trimmedFields);
}

What it does:

  1. Replace request with a new one with trimmed inputs
  2. Set all fields I don't want trimmed in an untrimmable property.
  3. Handles nested inputs with dot notation .

Check out the gist here

1 like
biniyam20's avatar

@gpcee Thanks for creating the PR to call prepareForValidation! :)

For anyone who is trying to figure out how to replace a specific value in the request data without replacing the entire data set, you can use the merge method! Merge is essentially a wrapper for the array_replace method which replaces the value with the same key or adds the key value pairing if not present.

Merge method: https://github.com/laravel/framework/blob/master/src/Illuminate/Http/Request.php#L294 Underlying Symphony add method: https://github.com/symfony/http-foundation/blob/master/ParameterBag.php Underlying array_replace method: http://php.net/manual/en/function.array-replace.php

It was probably overkill to dig this deep but I thought it would be fun :-)

    protected function prepareForValidation()
    {
        return $this->merge(['isbn'=> Helpers::removeDashes($this->isbn)]);
    }
aahelali's avatar

Replace this method in your Form Request:

protected function validationData(){
        $this->merge([
            'new_key' => 'Value',
        ]);

        return $this->all();
}
2 likes
Previous

Please or to participate in this conversation.