Home » Php » Laravel 4 : Best Practice to Trim Input before Validation

Laravel 4 : Best Practice to Trim Input before Validation

Posted by: admin October 29, 2017 Leave a comment

Questions:

Now, I do trim for each input separately like below code:

$username = trim(Input::get('username'));
$password = trim(Input::get('password'));
$email    = trim(Input::get('email'));

$validator = Validator::make(array('username' => $username, 
                                   'password' => $password, 
                                   'email'    => $email), 
                             array('username' => 'required|min:6', 
                                   'password' => 'required|min:6', 
                                   'email'    => 'email'));

Is any approach to do Trim at the same time with

Input::all() or Input::only('username', 'password', 'email')?

And what is the best practice to do this?

Answers:

Note: This solution won’t work if any of your inputs are arrays (such as “data[]”).

You may try this, trim using this one line of code before validation:

Input::merge(array_map('trim', Input::all()));

Now do the rest of your coding

$username = Input::get('username'); // it's trimed 
// ...
Validator::make(...);

If you want to exclude some inputs from trimming then you may use following instead if all()

Input::except('password');

Or you may use

Input::only(array('username'));

Update: Since Laravel 5.4.* inputs are trimmed because of new TrimStringsmiddleware. So, no need to worry about it because this middleware executes on every request and it handles array inputs as well.

Questions:
Answers:

Depending on your project, the below might be too intrusive/generalized/etc for your needs; customize as needed.

  • I’m making use of this little recursive array map function in order to process arrays of inputs without error.
  • Any field named password (and its confirmation) is excluded since people might want to use space as part of further obscuring their passwords.
  • Space has special meaning in some types of text. For example in Markdown, two or more spaces at the end of a line inserts <br>. Though you probably won’t need this at the start or at the end of the blob. YMMV.

app/helpers.php

/**
 * @param callable $callback
 * @param array    $array
 *
 * @return mixed
 *
 * @link http://php.net/manual/en/function.array-map.php#112857
 */
function array_map_recursive($callback, $array)
{
    foreach ($array as $key => $value) {
        if (is_array($array[$key])) {
            $array[$key] = array_map_recursive($callback, $array[$key]);
        } else {
            $array[$key] = call_user_func($callback, $array[$key]);
        }
    }

    return $array;
}

app/filters.php

App::before(
    function (\Illuminate\Http\Request $request) {
        // Trim all input
        $request->merge(
            array_map_recursive(
                "trim",
                array_except(
                    $request->all(),
                    ["password", "password_confirmation"]
                )
            )
        );
    }
);

Questions:
Answers:

Maybe you can use the array_map function of php, to trim the content of your input array.

$validator = Validator::make(array_map('trim',Input::all()),
                             array('username' => 'required|min:6', 
                                   'password' => 'required|min:6', 
                                   'email'    => 'email'));

Or if you want a variable you can use later:

$inputs = array_map('trim', Input::only('username', 'password', 'email'))

Questions:
Answers:
$attributes = Input::only('username', 'password', 'email');

foreach ($attributes as &$value) {
    $value = trim($value);
    //and any further preprocessing you want
}

$validator = Validator::make($attributes, array(
    'username' => 'required|min:6', 
    'password' => 'required|min:6', 
    'email'    => 'email'
));

//now you may pass preprocessed $attributes to the model create() method,
//still having the original input untouched if you may need it

Usually, I also use this approach to replace optional values with null when they’re empty, because I prefer to store them in DB as NULL rather than empty strings.

Questions:
Answers:

It’s a better practice to do trimming in the model instead of in controllers because then you don’t have to duplicate code in all your controllers to trim the same things over and over:

public function setUsernameAttribute($value)
{
  $this->attributes['username'] = trim($value);
}

This way, you never have to remember to trim anything model attributes in your controllers. The model will take care of it and you don’t have to worry about it ever again.

As far as trimming everything at once vs. individually, I think the difference is so small that no human would ever notice the difference.

Questions:
Answers:

A combination of the above is best. Generally you’ll want to filter on all input apart from password and password_confirmation fields. Also doing it with a single line in a filter is nice.

// app/filters.php

App::before(function($request)
{
    // Trim all input
    Input::merge(array_map('trim', Input::except(['password', 'password_confirmation'])));

});

Questions:
Answers:

an improvement in Halil Özgür code to remove all spaces, <br>, <br >, <br class="asdasd">, &nbsp, etc

// filters.php
App::before(function (\Illuminate\Http\Request $request) {
    $request->merge(
        array_map_recursive(
            "preg_replace",
            array_except(
                $request->all(),
                ["password", "password_confirmation"]
            )
        )
    );
});

// helpers.php
function array_map_recursive($callback, $array)
{
    foreach ($array as $key => $value) {
        if (is_array($array[$key])) {
            $array[$key] = array_map_recursive($callback, $array[$key]);
        } else {
            $array[$key] = call_user_func_array($callback, ['#(( ){0,}<br( {0,})(/{0,1})>){1,}$#i', '', $array[$key]]);
        }
    }

    return $array;
}