In today's digital world, data breaches in web applications have become more common. One of the primary causes is the lack of proper input validation for data submitted by users. Common attacks resulting from weak validation include SQL Injection, Cross-Site Scripting (XSS), and Cross-Site Request Forgery (CSRF). Fortunately, Laravel, one of the most popular PHP frameworks, provides a simple yet powerful input validation mechanism. This article will demonstrate how to implement input validation in Laravel to secure your forms from invalid data.
Why Is Input Validation Important in Web Applications?
Input validation is crucial because invalid data can compromise both the security and performance of an application. Laravel offers a straightforward yet effective way to ensure that form inputs meet certain criteria, such as validating emails, ensuring the length of submitted values, and matching data types. By enforcing proper validation, you can prevent various attacks that could jeopardize your web application.
Also read: How to Create an Image Preview Feature Before Uploading with JavaScript.
Setting Up a Laravel Project
Before diving into validation, let's assume you already have a Laravel project connected to a database. In this example, we will use Laravel's default users table structure. Don’t forget to run the following command to activate the table migration:
php artisan migrate
Next, create a controller named UserController
. You can generate this using the command:
php artisan make:controller UserController
Implementing Input Validation in Laravel
Within the UserController
, add the following code to validate input data submitted through the form:
<?php
namespace AppHttpControllers;
use AppModelsUser;
use IlluminateHttpRequest;
class UserController extends Controller
{
public function index() {
return view('users');
}
public function store(Request $request) {
// input validation
$validatedData = $request->validate([
'name' => 'required|string|min:3|max:50',
'email' => 'required|email:dns|unique:users,email',
'password' => 'required|string|min:8|max:32',
'confirm_password' => 'required|string|same:password'
]);
// code will execute only if validation passes
unset($validatedData['confirm_password']);
User::create($validatedData);
return redirect()->back()->with('success', 'User successfully added');
}
}
The code above ensures that name
must be a string between 3 and 50 characters long, email
must be valid and unique in the users
table, password
must be at least 8 characters long, and confirm_password
must match the password
.
Creating the Form View with Blade
Next, create an HTML form view for adding user data. Save the following code in the users.blade.php
file located in resources/views
:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Input Validation - By Kode Fiksi</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<div class="container">
<form action="{{ route('users.store') }}" method="POST" class="mt-5 mx-auto col-lg-6">
@if (session('success'))
<div class="alert alert-success alert-dismissible fade show" role="alert">
{{ session('success') }}
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
</div>
@endif
@csrf
<div class="mb-3">
<label for="name" class="form-label">Name</label>
<input type="text" class="form-control @error('name') is-invalid @enderror" id="name" name="name" value="{{ old('name') }}">
@error('name')
<div class="invalid-feedback">{{ $message }}</div>
@enderror
</div>
<div class="mb-3">
<label for="email" class="form-label">Email</label>
<input type="text" class="form-control @error('email') is-invalid @enderror" id="email" name="email" value="{{ old('email') }}">
@error('email')
<div class="invalid-feedback">{{ $message }}</div>
@enderror
</div>
<div class="mb-3">
<label for="password" class="form-label">Password</label>
<input type="password" class="form-control @error('password') is-invalid @enderror" id="password" name="password">
@error('password')
<div class="invalid-feedback">{{ $message }}</div>
@enderror
</div>
<div class="mb-3">
<label for="confirm_password" class="form-label">Confirm Password</label>
<input type="password" class="form-control @error('confirm_password') is-invalid @enderror" id="confirm_password" name="confirm_password">
@error('confirm_password')
<div class="invalid-feedback">{{ $message }}</div>
@enderror
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
</div>
</body>
</html>
Adding Routes for the Controller
To make the form functional, add routes that connect to the functions in UserController
. Update the web.php
file with the following lines:
<?php
use AppHttpControllersUserController;
use IlluminateSupportFacadesRoute;
Route::controller(UserController::class)
->group(function () {
Route::get('/', 'index')->name('users.index');
Route::post('/', 'store')->name('users.store');
});
Explaining Input Validation in Laravel
In this example, validation is done using the validate()
method in the controller. Laravel provides various validation rules, such as:
required
: Field is mandatory.string
: Data must be a string.min
: Minimum number of characters.max
: Maximum number of characters.unique:users,email
: Data must be unique in theusers
table for the email column.same:password
: Must match the input password.
Laravel also includes CSRF protection to safeguard against Cross-Site Request Forgery attacks. The CSRF token is automatically inserted into the form using the @csrf
directive.
Optimizing Validation with Form Requests
For more complex validations, Laravel allows you to separate validation logic into Form Requests. To create a Form Request, run:
php artisan make:request UserPostRequest
Move the validation rules from the controller into the UserPostRequest.php
file. It should look like this:
<?php
namespace AppHttpRequests;
use IlluminateFoundationHttpFormRequest;
class UserPostRequest extends FormRequest
{
public function authorize(): bool
{
return true; // allow all users
}
public function rules(): array
{
return [
'name' => 'required|string|min:3|max:50',
'email' => 'required|email:dns|unique:users,email',
'password' => 'required|string|min:8|max:32',
'confirm_password' => 'required|string|same:password'
];
}
}
Then, modify the store()
function in UserController.php like this:
public function store(UserPostRequest $request) {
// input validation
$validatedData = $request->validated();
// ...
}
Don’t forget to import the class at the top of the file:
use App\Requests\UserPostRequest;
Now, try testing the input validation by submitting values that don't meet any of the set validation rules. If successful, it will appear as shown in the image below.
Conclusion
Implementing input validation in Laravel is essential for securing web applications against attacks like SQL Injection, XSS, and CSRF. Laravel offers easy-to-use and flexible validation features to ensure that the data received by your application is valid. By separating validation logic into Form Requests, you can keep your code clean and readable. Always apply input validation to enhance the security and performance of your web applications.