Form Validation

Never trust incoming data. Every value arriving via $_POST, $_GET, or a JSON request body could be missing, malformed, or deliberately hostile, and checking it by hand with a pile of if statements gets messy and error-prone fast. CodeIgniter 4 ships a dedicated Validation library specifically to solve this: you describe the rules a piece of data must satisfy as a simple array, hand that array to the library, and it tells you exactly what passed and what didn't — along with ready-to-display error messages for each failure.

1. Running Validation in a Controller

There are two equivalent ways to reach the Validation library. The first is explicit, going through the same Config\Services factory introduced on the previous page:

$validation = \Config\Services::validation();

In practice, though, almost every CodeIgniter controller uses the far more convenient shortcut: every controller extending BaseController has a $this->validate() method built in, which runs the Validation service against the current request's input and returns a simple boolean:

<?php

namespace App\Controllers;

use App\Models\ArticleModel;

class Articles extends BaseController
{
    public function store()
    {
        $rules = [
            'title' => 'required|min_length[3]|max_length[255]',
            'email' => 'required|valid_email',
        ];

        if (!$this->validate($rules)) {
            return view('articles/create', [
                'errors' => $this->validator->getErrors(),
            ]);
        }

        $model = new ArticleModel();
        $model->insert([
            'title' => $this->request->getPost('title'),
        ]);

        return redirect()->to('/articles');
    }
}

$this->validate($rules) automatically pulls the data straight out of the current request (POST fields by default), checks every rule, and returns true or false. When it fails, the framework's built-in $this->validator property holds onto the results so you can immediately ask it for the details.

2. Common Built-in Rules

Rules are written as a single pipe-separated string per field, and CodeIgniter ships dozens of them covering the vast majority of everyday validation needs. Here are the ones you'll reach for constantly:

RuleWhat it checks
requiredThe field must be present and not empty
min_length[3]String must be at least the given number of characters
max_length[255]String must not exceed the given number of characters
valid_emailValue must be a syntactically valid email address
numericValue must consist only of numeric characters
is_unique[table.column]No existing row in that table/column already has this value — ideal for unique usernames or emails
matches[field]Value must match another field exactly — commonly used for password confirmation
alpha_numericValue must contain only letters and numbers

Rules for one field are combined by chaining them with the pipe character, and rules needing a parameter take it in square brackets:

'username' => 'required|min_length[3]|max_length[30]|is_unique[users.username]'

3. Retrieving and Displaying Errors

When validation fails, getErrors() returns an associative array keyed by field name, with each value being the specific message for that field's first broken rule. Passing that array into a view lets you show each error right next to the field it belongs to:

// app/Views/articles/create.php
<?php if (!empty($errors)): ?>
  <div class="alert alert-danger">
    <ul>
      <?php foreach ($errors as $field => $message): ?>
        <li><?= esc($message) ?></li>
      <?php endforeach; ?>
    </ul>
  </div>
<?php endif; ?>

Wrapping each message in esc() before printing it matters here just as much as anywhere else user-influenced text ends up in a view — the Views lesson covers exactly why. If you'd rather check a single field's error individually (handy for placing a message right under one input box), the validator instance also offers a per-field lookup:

<?= $validation->getError('email') ?>

4. Reusable Named Rule Groups

Typing the same rule array out in every controller that touches "articles" invites drift — one controller's rules quietly fall out of sync with another's. CodeIgniter's answer is to define rule groups once, centrally, in app/Config/Validation.php, then reference them everywhere by name.

// app/Config/Validation.php
<?php

namespace Config;

use CodeIgniter\Config\BaseConfig;

class Validation extends BaseConfig
{
    public $article = [
        'title' => 'required|min_length[3]|max_length[255]',
        'body'  => 'required|min_length[10]',
    ];

    public $article_errors = [
        'title' => [
            'required' => 'Please give your article a title.',
        ],
    ];
}

Any controller can then validate against that named group instead of repeating the rule array:

if (!$this->validate('article')) {
    // same $this->validator->getErrors() as before
}
Tip: Named rule groups aren't just about avoiding repetition — they also give you one obvious place to look when a validation rule needs to change, instead of hunting through every controller that happens to touch that data.
Note: Validation is your primary line of defense against malformed or malicious form and API input, but it works hand in hand with the topics on the next page — sessions, CSRF protection, and output escaping — to keep an application genuinely secure.
Next steps: Continue to Sessions & Security to see how CodeIgniter tracks data across requests and protects your forms from CSRF and XSS attacks.