Using CodeIgniter 4's Validation Service to Secure Form Input
Learn how CodeIgniter 4’s Validation service lets you declare field rules, run them all at once, collect errors, and repopulate forms with the Form Helper.
27 Dec 2025, 04:33 UTC

The problem: unreliable form data
When a user submits a form, missing or malformed fields can slip through to your business logic, leading to broken records or security issues. Manually checking each field with isset() or filter_var() quickly becomes tedious and error‑prone, especially as the form grows.
Thesis: CodeIgniter 4’s Validation service centralises rule definition and error collection
The framework ships with a reusable validation component that lets you declare rules per field, run them all at once, and retrieve a structured list of messages. It works hand‑in‑hand with the Form Helper to repopulate fields after a failed submission.
Setting up the validation service in a controller
First, load the service via the service locator. This must happen before you call run(); otherwise the service returns true without checking anything.
use CodeIgniter\Controller;
use Config\Services;
class User extends Controller
{
public function register()
{
$validation = Services::validation();
// … rule definition and execution …
}
}
Defining rules and executing the check
You can set rules with a fluent API. The example below validates a username (required, 3‑20 alphanumeric characters) and an email (required, valid format).
$validation->setRules([
'username' => [
'label' => 'Username',
'rules' => 'required|alpha_numeric_space|min_length[3]|max_length[20]',
'errors' => [
'required' => 'You must provide a {field}.',
'alpha_numeric_space' => 'The {field} may only contain letters, numbers and spaces.',
'min_length' => 'The {field} must be at least {param} characters long.',
'max_length' => 'The {field} may not exceed {param} characters.'
]
],
'email' => [
'label' => 'Email Address',
'rules' => 'required|valid_email',
'errors' => [
'required' => 'Please enter your {field}.',
'valid_email' => 'The {field} must be a valid email address.'
]
]
]);
$data = $this->request->getPost();
if (!$validation->run($data)) {
// validation failed
$errors = $validation->getErrors();
// pass $errors and old input to the view
return view('user/register', ['errors' => $errors, 'old' => $data]);
}
// validation succeeded – proceed with business logic
After calling run(), you can verify that $validation->getErrors() returns an associative array where each key matches a field name and the value is the corresponding error message (or an array of messages if multiple rules failed).
Repopulating the form with the Form Helper
In the view, load the Form Helper and use set_value() to show the user’s previous input.
'username', 'value' => set_value('username', old('username') ?? '')])
= esc($errors['username']) ?>
'email', 'value' => set_value('email', old('email') ?? '')])
= esc($errors['email']) ?>
When validation fails, the fields retain the values the user typed, reducing friction and improving usability.
Trade‑offs and limitations
- Order matters: Rules must be loaded via
setRules()beforerun(). Forgetting this step silently passes validation. - Custom callbacks: If you use a callback rule (e.g.,
is_unique[users.username]), the method must be public and reside on the same controller or a loaded library; otherwise the validation service ignores it. - Scope: The validation service checks data integrity only. It does not replace prepared statements or output escaping for SQL/XSS protection.
Actionable next steps
Add the validation service to every controller that processes form input. Write a simple unit test that posts invalid data and asserts that $validation->getErrors() contains the expected keys. Over time, you’ll catch missing fields early and keep your controllers focused on business logic rather than repetitive checks.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.