How to do form validation with custom rules in CodeIgniter 4

CodeIgniter 4 form validation can be done using built-in validation rules as well as by creating custom validation rules. In this topic, we will create a registration form and validate the form data when user submits this form. In case validation fails, we will display error message. We will use callback validation as well in this example by creating custom rules.

We will assume you have already got CodeIgniter 4 installed in your project root. All you have to do run below command in command line. For our example, we installed it in D:/projects.

 composer create-project codeigniter4/appstarter form

It creates a folder named 'form' in D:/projects and CodeIgniter4 is installed in that folder.

If you want to know how to install and configure CodeIgniter 4, you can read the topic How to Install and Test CodeIgniter 4 in Your Local Computer

Below is a screenshot of the registration page:

Codeigniter 4 Form Validation Tutorial with Example

Form Validation Example in Codeigniter 4 For Beginners	Folders and Files

As we mentioned before, we have created a folder named 'projects' in D:\ drive and installed CodeIgniter4 in 'form' folder under projects. So, the project root directory is D:/projects/form.

We will have Controller - Candidate.php, Model - ModelCandidate.php and the view - register.php.

There is a custom validation rule for age check. This is for age validation, as our form will accept only ages between 18 to 40, we need to validate the age value entered by the user.

If you are using XAMPP and want to use Apache Web Server instead of PHP built-in server, then you can install CodeIgniter 4 under xampp/htdocs/<your folder name>. In our case this folder name is 'form'. I will show necessary configuration changes and testing the application for both the web servers.

Step 1 - Create a MySQL table

Our table name is 'candidates' in MySQL database.

Table: candidates

It stores details of all the candidates who completed registration.

CodeIgniter 4 Form Validation Example

Below are the columns in this table.

  1. candidate_id - Primary key and auto incremented candidate id
  2. name - Name of the candidate
  3. address - Address of the candidate
  4. email_id - Email Id of the candidate
  5. age - Age of the candidate
  6. registration_dt - Date of Registration


CREATE TABLE `candidates` (
  `candidate_id` int(11) NOT NULL,
  `name` varchar(100) NOT NULL,
  `address` varchar(200) NOT NULL,
  `email_id` varchar(100) NOT NULL,
  `age` smallint(6) NOT NULL,
  `registration_dt` date NOT NULL

ALTER TABLE `candidates`
  ADD PRIMARY KEY (`candidate_id`);

ALTER TABLE `candidates`

Step 2 - Create the view for registration (register.php)

validation in codeigniter 4 with example

We will simply create a registration form with input fields Name, Email Id, Address and Age. This topic is more about form validation. So let's take a look at the code first:


<!DOCTYPE html>
<html lang="en">
  <title>Candidate Registration</title>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="stylesheet" href="">
  <link rel="stylesheet" href="/assets/css/style.css">
  <div class="container">
    <h2>Candidate Registration</h2>
    <p class="error "><?= $err_msg ?></p>
    <p class="success"><?= $succ_msg ?></p>
    <?php $validation = \Config\Services::validation(); ?>
    <?= session()->getFlashdata('error') ?>
    <form id ="frm" action = "register" method = "post">
      <?= csrf_field() ?>
      <div class="form-group col-md-12">
        <input type = "text" name="name" id = "name" class="form-control" maxlength="100" value="<?php echo set_value('name');?>" placeholder="Enter Your Name">
        <span class="error"><?= esc($validation->getError('name'));?> </span>
      <div class="form-group col-md-12">
        <label>Email Id</label>
        <input type = "text" name="email" id = "email" class="form-control"  maxlength="100" value="<?php echo set_value('email');?>" placeholder="Enter Your Email">
        <span class="error"><?= esc($validation->getError('email'));?> </span>
      <div class="form-group col-md-12">
            <textarea name="addr" id = "addr" class="form-control" maxlength="200" placeholder="Enter Your Address" ><?php echo set_value('addr');?></textarea>
       <span class="error"><?= esc($validation->getError('addr'));?> </span>
      <div class="form-group col-md-12">
        <label>Age <small>(Must be between 18 and 40 only)</small></label>
        <input type = "number" name="age" id = "age" class="form-control" value="<?php echo set_value('age');?>" placeholder="Enter Your Age in Years">
        <span class="error"><?= esc($validation->getError('age'));?> </span>
      <div class="col-md-12 text-center">
        <input type ="submit" name="signup" class="btn btn-primary" value="Submit">

You can see in line 15, we have used $validation = \Config\Services::validation(), this will load the validation settings with rulesets which we can use in our validation. For each input field, an error message will be displayed in case validation fails for that field. Once the form is submitted register() method of the Candidate controller is called.

Database setup and other configuration changes are discussed in step 5.

Step 3 - Write Controller code (Candidate.php)

Our controller function will have an index() method to display the register page and register() method to process submitted data. We will use the model ModelCandidate.php, so we need to create an instance of the model also. See below code at the beginning of the controller:

protected $model;
protected $uri;
protected $validation;
public function __construct() {
  helper(['form', 'url']);
  $this->uri = service('uri');
  $this->validation = service('validation');
  $this->model = new ModelCandidate();

public function index() {
  $element['succ_msg'] = "";
  $element['err_msg'] = "";
  echo view('register',$element);

In the construct method, form and url helper are loaded. 'uri' and 'validation' services are also loaded. Then an instance of the model is created. index() method is executed by default in a controller. In this method it just loads the view to display registration form.

Controller Method register()

In this method we will do all the validations for the various input fields in the form.

If the form is submitted, it does validation for the input fields using validation rules. If validation fails, it reloads the view with error message displayed. But if all fields are validated successfully, this method inserts the data in the table using the model. Let's see the code for register() method.

if ($this->request->getMethod() === 'post') {
			$rules = [
				'name' => [
					'label' => 'Name',
					'rules' => 'trim|required',
				'email' => [
					'label' => 'Email Id',
					'rules' => 'trim|required|valid_email|is_unique[candidates.email_id]',
				'addr' => [
					'label' => 'Address',
					'rules' => 'required',
				'age' => [
					'label' => 'Age',
					'rules' => 'required|ageCheck'

			$errors = [
				'name' =>[
					'required' => 'You must enter a {field}'
				'email' => [
					'required' => 'You must enter an {field}',
					'valid_email' => '{value} is not a valid email address',
					'is_unique' => '{value} already registered'
				'addr' => [
					'required' => 'You must enter an {field}'
				'age' => [
					'required' => 'You must enter an {field}',
					'ageCheck' => '{field} must be between 18 and 40',
			if (!$this->validate($rules, $errors)) {
				echo view('register',$element);
			else {
			// validations are successful, go for registration
				$name = $this->request->getPost('name');
				$email = $this->request->getPost('email');
				$addr = $this->request->getPost('addr');
				$age = $this->request->getPost('age');
				$data = array('name'=>$name, 'address'=>$addr, 'email_id'=>$email, 'age'=>$age);
				$result = $this->model->save($data);
				if ($result){
					$msg = 'Registration successful';
					$element['succ_msg'] = $msg;
					$msg = "Error in Registration";
					$element['err_msg'] = $msg;
				echo view('register',$element);
		else {  // load the form
			echo view('register',$element);

Just check for 'age' validation. We have used a custom rule 'ageCheck'. This is to validate allowed range of valid ages. We will discuss that how it is defined. $errors is for custom error messages in case validation fails.

If validation is successful, $this->model->save() method will insert the row in database table and return true or false.

Age validation

For age validation, we need to create a custom validation method. See the code below in ProjectRules.php under app/CustomValidation. This is like callback method used in CodeIgniter 3.

namespace App\CustomValidation;
class ProjectRules {
	public function ageCheck(string $str) {
      	if (!empty($str)){
      		if ((int) $str <18 || (int) $str >40) {
      			return false;
      			return true;
      	return false;

In this method, it checks the value of the input, if it falls between 18 and 40. If not, it returns false. Based on this, validation error message is displayed in the form.

Step 4 - Write Model code (ModelCandidate.php)

Our model is very simple, just defines the table name and updatable columns.

namespace App\Models;
use CodeIgniter\Model;

class ModelCandidate extends Model{
  protected $table = 'candidates';
  protected $allowedFields = ['name','email_id','address','age', 'registration_dt'];

Stylesheet for all these views.


	text-align: center;
	margin-top: 50px;

  text-align: center;
  font-size: 20px;
  text-align: center;
  font-size: 20px;

  min-height: 20px;
  font-size: 17px;

	font-weight: bold;
 #frm {
  margin: 5px auto;
  padding-top: 21px;
  padding-bottom: 40px;
  border: 1px solid #09168d;
  border-radius: 7px;
  background: #fff;
  width: 47%;
	resize: none !important;
	height: 100px !important;

Step 5 - Update Configuration files and Test the Application

We will update few setup files under Config folder and also, we will update .env file in the root directory.

  1. Update config file (app/Config/App.php) for $baseURL and $index
    public $baseURL = 'http://localhost:8080/';
    public $indexPage = '';
  2. Update database setup file (app/Config/Database.php) for database name with userid 'root' and password. Update $default as below:
    public $default = [
            'DSN'      => '',
            'hostname' => 'localhost',
            'username' => 'root',
            'password' => '',
            'database' => 'demo',
            'DBDriver' => 'MySQLi',
            'DBPrefix' => '',
            'pConnect' => false,
            'DBDebug'  => (ENVIRONMENT !== 'production'),
            'charset'  => 'utf8',
            'DBCollat' => 'utf8_general_ci',
            'swapPre'  => '',
            'encrypt'  => false,
            'compress' => false,
            'strictOn' => false,
            'failover' => [],
            'port'     => 3306,
  3. Update Routes file (app/Config/Routes.php) as below:
     * --------------------------------------------------------------------
     * Router Setup
     * --------------------------------------------------------------------
     * --------------------------------------------------------------------
     * Route Definitions
     * --------------------------------------------------------------------
    // We get a performance increase by specifying the default
    // route since we don't have to scan directories.
    $routes->get('/', 'Candidate::index');
    $routes->get('/register', 'Candidate::register');
    $routes->post('/register', 'Candidate::register');
  4. Update .env to set the environment to development. This file is in root directory.

    # CI_ENVIRONMENT = production
    CI_ENVIRONMENT = development

    If you have not already copied env file to .env file, make a copy of env to .env. Open .env file in notepad and go to the line containing "# CI_ENVIRONMENT = production". Now copy this line and paste it as next line, then update the environment from production to development and remove # from the beginning of the line as shown above.

Test the Application

You can test the application using built-in PHP server or you can use Apache web server if you are using xampp.

Test using PHP built-in server

Open command prompt and go to your CI4 project root. In my case it is D:/projects/form. Then type php spark serve and enter. This will start the server in port 8080.

custom validation codeigniter 4

Run http://localhost:8080/ in the browser. This will open the home page.

validation error in codeigniter 4

Test the validation for all the fields. Just try to submit incomplete form. You should see the proper validation messages. Also check the validation for age.

Test using Apache web server

If you are using XAMPP make sure your root folder is xampp/htdocs/form, i.e., you have to install CI4 in this folder. Open httpd-vhosts.conf file in notepad from xampp\apache\conf\extra folder. Add below line at the end of it.

DocumentRoot "D:/xampp/htdocs/form/public"

email validation in ci4

Save it and restart the Apache service from xampp controller.

Now in app/Config/App.php, update base url as below:

public $baseURL = 'http://localhost/';

Open the browser and run http://localhost. You will see the page as displayed below:

custom validation codeigniter 4

Do the same testing described above.

That's it! Our development and testing are done for this CodeIgniter4 application. Hope you could successfully develop and test it.

Custom Validation Rule in CodeIgniter 4Conclusion

Form validation is an important part for any project development. We must ensure that correct and only desired data are stored in the system. Hope this gives you a starting point for form validation in CodeIgniter4.