1. php
  2. /frameworks
  3. /codeigniter

CodeIgniter Framework

Introduction to CodeIgniter

CodeIgniter is a lightweight, simple, and elegant PHP framework with a small footprint. It's known for its ease of use, gentle learning curve, and excellent documentation. CodeIgniter follows the MVC pattern and provides a rich set of libraries for common tasks.

Key Features

  1. Lightweight and Fast: Small footprint with excellent performance
  2. Simple MVC Pattern: Easy to understand architecture
  3. Rich Library Set: Built-in libraries for common tasks
  4. Excellent Documentation: Clear and comprehensive guides
  5. Flexible Routing: Powerful URL routing system
  6. Active Record Database: Simple database abstraction layer

Installation and Setup

Installing CodeIgniter 4

# Using Composer
composer create-project codeigniter4/appstarter my-project

# Navigate to project
cd my-project

# Start development server
php spark serve

Project Structure

my-project/
├── app/
│   ├── Controllers/
│   ├── Models/
│   ├── Views/
│   ├── Config/
│   ├── Database/
│   └── Filters/
├── public/
│   └── index.php
├── tests/
├── writable/
│   ├── cache/
│   └── logs/
└── vendor/

MVC Architecture

Controllers

<?php
// app/Controllers/Home.php
namespace App\Controllers;

class Home extends BaseController
{
    public function index()
    {
        $data = [
            'title' => 'Welcome to CodeIgniter',
            'message' => 'Hello World!'
        ];
        
        return view('welcome_message', $data);
    }
    
    public function about()
    {
        $data = [
            'title' => 'About Us',
            'content' => 'This is the about page.'
        ];
        
        return view('pages/about', $data);
    }
}

Advanced Controller Example

<?php
// app/Controllers/UserController.php
namespace App\Controllers;

use App\Models\UserModel;
use CodeIgniter\RESTful\ResourceController;

class UserController extends ResourceController
{
    protected $modelName = 'App\Models\UserModel';
    protected $format = 'json';
    
    public function index()
    {
        $users = $this->model->findAll();
        
        return $this->respond([
            'status' => 'success',
            'data' => $users
        ]);
    }
    
    public function show($id = null)
    {
        $user = $this->model->find($id);
        
        if (!$user) {
            return $this->failNotFound('User not found');
        }
        
        return $this->respond([
            'status' => 'success',
            'data' => $user
        ]);
    }
    
    public function create()
    {
        $rules = [
            'name' => 'required|min_length[3]|max_length[255]',
            'email' => 'required|valid_email|is_unique[users.email]',
            'password' => 'required|min_length[8]'
        ];
        
        if (!$this->validate($rules)) {
            return $this->failValidationErrors($this->validator->getErrors());
        }
        
        $data = [
            'name' => $this->request->getPost('name'),
            'email' => $this->request->getPost('email'),
            'password' => password_hash($this->request->getPost('password'), PASSWORD_DEFAULT)
        ];
        
        $userId = $this->model->insert($data);
        
        return $this->respondCreated([
            'status' => 'success',
            'message' => 'User created successfully',
            'data' => ['id' => $userId]
        ]);
    }
    
    public function update($id = null)
    {
        $user = $this->model->find($id);
        
        if (!$user) {
            return $this->failNotFound('User not found');
        }
        
        $rules = [
            'name' => 'required|min_length[3]|max_length[255]',
            'email' => "required|valid_email|is_unique[users.email,id,{$id}]"
        ];
        
        if (!$this->validate($rules)) {
            return $this->failValidationErrors($this->validator->getErrors());
        }
        
        $data = [
            'name' => $this->request->getJSON()->name,
            'email' => $this->request->getJSON()->email
        ];
        
        $this->model->update($id, $data);
        
        return $this->respond([
            'status' => 'success',
            'message' => 'User updated successfully'
        ]);
    }
    
    public function delete($id = null)
    {
        $user = $this->model->find($id);
        
        if (!$user) {
            return $this->failNotFound('User not found');
        }
        
        $this->model->delete($id);
        
        return $this->respondDeleted([
            'status' => 'success',
            'message' => 'User deleted successfully'
        ]);
    }
}

Models

Basic Model

<?php
// app/Models/UserModel.php
namespace App\Models;

use CodeIgniter\Model;

class UserModel extends Model
{
    protected $table = 'users';
    protected $primaryKey = 'id';
    protected $useAutoIncrement = true;
    protected $returnType = 'array';
    protected $useSoftDeletes = true;
    
    protected $allowedFields = [
        'name', 'email', 'password', 'status'
    ];
    
    protected $useTimestamps = true;
    protected $createdField = 'created_at';
    protected $updatedField = 'updated_at';
    protected $deletedField = 'deleted_at';
    
    protected $validationRules = [
        'name' => 'required|min_length[3]|max_length[255]',
        'email' => 'required|valid_email|is_unique[users.email,id,{id}]',
        'password' => 'required|min_length[8]'
    ];
    
    protected $validationMessages = [
        'name' => [
            'required' => 'Name is required',
            'min_length' => 'Name must be at least 3 characters'
        ],
        'email' => [
            'required' => 'Email is required',
            'valid_email' => 'Please provide a valid email',
            'is_unique' => 'Email already exists'
        ]
    ];
    
    protected $skipValidation = false;
    
    // Custom methods
    public function findByEmail($email)
    {
        return $this->where('email', $email)->first();
    }
    
    public function getActiveUsers()
    {
        return $this->where('status', 'active')->findAll();
    }
    
    public function searchUsers($term)
    {
        return $this->like('name', $term)
                   ->orLike('email', $term)
                   ->findAll();
    }
}

Advanced Model with Relationships

<?php
// app/Models/PostModel.php
namespace App\Models;

use CodeIgniter\Model;

class PostModel extends Model
{
    protected $table = 'posts';
    protected $primaryKey = 'id';
    protected $returnType = 'array';
    protected $useSoftDeletes = true;
    
    protected $allowedFields = [
        'title', 'content', 'slug', 'user_id', 'status', 'published_at'
    ];
    
    protected $useTimestamps = true;
    
    protected $validationRules = [
        'title' => 'required|min_length[3]|max_length[255]',
        'content' => 'required|min_length[10]',
        'slug' => 'required|is_unique[posts.slug,id,{id}]',
        'user_id' => 'required|is_not_unique[users.id]'
    ];
    
    // Get posts with user information
    public function getPostsWithUsers()
    {
        return $this->select('posts.*, users.name as author_name')
                   ->join('users', 'users.id = posts.user_id')
                   ->where('posts.status', 'published')
                   ->orderBy('posts.published_at', 'DESC')
                   ->findAll();
    }
    
    // Get paginated posts
    public function getPaginatedPosts($perPage = 10)
    {
        return $this->select('posts.*, users.name as author_name')
                   ->join('users', 'users.id = posts.user_id')
                   ->where('posts.status', 'published')
                   ->orderBy('posts.published_at', 'DESC')
                   ->paginate($perPage);
    }
    
    // Get posts by user
    public function getPostsByUser($userId)
    {
        return $this->where('user_id', $userId)
                   ->where('status', 'published')
                   ->orderBy('published_at', 'DESC')
                   ->findAll();
    }
}

Views and Templates

Basic Views

<?php
// app/Views/layouts/main.php
?>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title><?= esc($title ?? 'CodeIgniter App') ?></title>
    <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
    <nav class="navbar navbar-expand-lg navbar-dark bg-dark">
        <div class="container">
            <a class="navbar-brand" href="<?= base_url() ?>">My App</a>
            <div class="navbar-nav">
                <a class="nav-link" href="<?= base_url() ?>">Home</a>
                <a class="nav-link" href="<?= base_url('posts') ?>">Posts</a>
                <a class="nav-link" href="<?= base_url('about') ?>">About</a>
            </div>
        </div>
    </nav>
    
    <main class="container mt-4">
        <?= $this->renderSection('content') ?>
    </main>
    
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>
<?php
// app/Views/posts/index.php
$this->extend('layouts/main');
$this->section('content');
?>

<h1>Blog Posts</h1>

<div class="row">
    <?php foreach ($posts as $post): ?>
        <div class="col-md-6 mb-4">
            <div class="card">
                <div class="card-body">
                    <h5 class="card-title"><?= esc($post['title']) ?></h5>
                    <p class="card-text"><?= esc(substr($post['content'], 0, 150)) ?>...</p>
                    <p class="text-muted">
                        By <?= esc($post['author_name']) ?> on 
                        <?= date('M d, Y', strtotime($post['published_at'])) ?>
                    </p>
                    <a href="<?= base_url("posts/{$post['slug']}") ?>" class="btn btn-primary">Read More</a>
                </div>
            </div>
        </div>
    <?php endforeach; ?>
</div>

<?= $pager->links() ?>

<?php $this->endSection(); ?>

Routing

Basic Routing

<?php
// app/Config/Routes.php
use CodeIgniter\Router\RouteCollection;

/**
 * @var RouteCollection $routes
 */
$routes->get('/', 'Home::index');
$routes->get('/about', 'Home::about');

// Blog routes
$routes->group('posts', function($routes) {
    $routes->get('/', 'PostController::index');
    $routes->get('create', 'PostController::create');
    $routes->post('create', 'PostController::store');
    $routes->get('(:segment)', 'PostController::show/$1');
    $routes->get('(:segment)/edit', 'PostController::edit/$1');
    $routes->post('(:segment)/edit', 'PostController::update/$1');
    $routes->delete('(:segment)', 'PostController::delete/$1');
});

// API routes
$routes->group('api', ['namespace' => 'App\Controllers\API'], function($routes) {
    $routes->resource('users');
    $routes->resource('posts');
});

// Admin routes
$routes->group('admin', ['filter' => 'auth'], function($routes) {
    $routes->get('dashboard', 'AdminController::dashboard');
    $routes->resource('users', ['controller' => 'AdminController']);
});

Database Operations

Query Builder

<?php
// Using Query Builder
$db = \Config\Database::connect();

// Select data
$users = $db->table('users')
            ->select('id, name, email')
            ->where('status', 'active')
            ->orderBy('name', 'ASC')
            ->get()
            ->getResultArray();

// Insert data
$data = [
    'name' => 'John Doe',
    'email' => '[email protected]',
    'password' => password_hash('secret', PASSWORD_DEFAULT)
];
$db->table('users')->insert($data);

// Update data
$db->table('users')
   ->where('id', 1)
   ->update(['name' => 'Jane Doe']);

// Delete data
$db->table('users')->where('id', 1)->delete();

// Complex queries with joins
$posts = $db->table('posts p')
            ->select('p.*, u.name as author_name')
            ->join('users u', 'u.id = p.user_id')
            ->where('p.status', 'published')
            ->orderBy('p.created_at', 'DESC')
            ->get()
            ->getResultArray();

Form Validation

Controller Validation

<?php
// In Controller
public function store()
{
    $rules = [
        'title' => 'required|min_length[3]|max_length[255]',
        'content' => 'required|min_length[10]',
        'email' => 'required|valid_email',
        'image' => 'uploaded[image]|max_size[image,1024]|is_image[image]'
    ];
    
    $messages = [
        'title' => [
            'required' => 'Title is required',
            'min_length' => 'Title must be at least 3 characters'
        ],
        'image' => [
            'uploaded' => 'Please select an image',
            'max_size' => 'Image size must not exceed 1MB'
        ]
    ];
    
    if (!$this->validate($rules, $messages)) {
        return redirect()->back()
                        ->withInput()
                        ->with('errors', $this->validator->getErrors());
    }
    
    // Process valid data
    $data = [
        'title' => $this->request->getPost('title'),
        'content' => $this->request->getPost('content'),
        'email' => $this->request->getPost('email')
    ];
    
    // Handle file upload
    $image = $this->request->getFile('image');
    if ($image && $image->isValid()) {
        $newName = $image->getRandomName();
        $image->move(WRITEPATH . 'uploads', $newName);
        $data['image'] = $newName;
    }
    
    $this->postModel->insert($data);
    
    return redirect()->to('/posts')->with('success', 'Post created successfully');
}

Libraries and Helpers

Using Libraries

<?php
// Email Library
$email = \Config\Services::email();

$email->setFrom('[email protected]', 'Your Name');
$email->setTo('[email protected]');
$email->setSubject('Email Test');
$email->setMessage('Testing the email class.');

if ($email->send()) {
    echo 'Email sent successfully';
} else {
    echo $email->printDebugger(['headers']);
}

// Session Library
$session = session();
$session->set('user_id', 123);
$userId = $session->get('user_id');
$session->remove('user_id');

// File Upload
$file = $this->request->getFile('userfile');

if ($file->isValid() && !$file->hasMoved()) {
    $newName = $file->getRandomName();
    $file->move('/path/to/dir/', $newName);
}

Custom Library

<?php
// app/Libraries/PaymentProcessor.php
namespace App\Libraries;

class PaymentProcessor
{
    private $apiKey;
    private $apiUrl;
    
    public function __construct()
    {
        $this->apiKey = env('PAYMENT_API_KEY');
        $this->apiUrl = env('PAYMENT_API_URL');
    }
    
    public function processPayment($amount, $cardToken)
    {
        $client = \Config\Services::curlrequest();
        
        $response = $client->post($this->apiUrl . '/charge', [
            'headers' => [
                'Authorization' => 'Bearer ' . $this->apiKey,
                'Content-Type' => 'application/json'
            ],
            'json' => [
                'amount' => $amount,
                'source' => $cardToken,
                'currency' => 'usd'
            ]
        ]);
        
        return json_decode($response->getBody(), true);
    }
}

// Usage in Controller
$payment = new \App\Libraries\PaymentProcessor();
$result = $payment->processPayment(1000, $cardToken);

Security Features

CSRF Protection

<?php
// In form view
echo form_open('posts/create', ['class' => 'form']);
echo csrf_field(); // Automatically adds CSRF token
?>

<!-- Or manually -->
<input type="hidden" name="<?= csrf_token() ?>" value="<?= csrf_hash() ?>" />

XSS Protection

<?php
// Auto-escape in views
echo esc($userInput); // Escapes HTML entities

// In templates
<h1><?= esc($title) ?></h1>
<p><?= esc($content, 'html') ?></p>

Authentication Filter

<?php
// app/Filters/AuthFilter.php
namespace App\Filters;

use CodeIgniter\HTTP\RequestInterface;
use CodeIgniter\HTTP\ResponseInterface;
use CodeIgniter\Filters\FilterInterface;

class AuthFilter implements FilterInterface
{
    public function before(RequestInterface $request, $arguments = null)
    {
        $session = session();
        
        if (!$session->get('user_id')) {
            return redirect()->to('/login')->with('error', 'Please login first');
        }
    }
    
    public function after(RequestInterface $request, ResponseInterface $response, $arguments = null)
    {
        // Nothing to do here
    }
}

// Register in app/Config/Filters.php
public $aliases = [
    'auth' => \App\Filters\AuthFilter::class,
];

Configuration and Environment

Environment Variables

# .env file
CI_ENVIRONMENT = development

database.default.hostname = localhost
database.default.database = ci4_app
database.default.username = root
database.default.password = 
database.default.DBDriver = MySQLi

app.baseURL = 'http://localhost:8080'
app.sessionDriver = 'CodeIgniter\Session\Handlers\FileHandler'
app.sessionSavePath = WRITEPATH . 'session'

Custom Configuration

<?php
// app/Config/Blog.php
namespace Config;

use CodeIgniter\Config\BaseConfig;

class Blog extends BaseConfig
{
    public $postsPerPage = 10;
    public $allowComments = true;
    public $moderateComments = true;
    public $allowedImageTypes = ['jpg', 'jpeg', 'png', 'gif'];
    public $maxImageSize = 1024; // KB
}

// Usage
$config = config('Blog');
$perPage = $config->postsPerPage;

Testing

Unit Testing

<?php
// tests/unit/UserModelTest.php
namespace Tests\Unit;

use CodeIgniter\Test\CIUnitTestCase;
use CodeIgniter\Test\DatabaseTestTrait;

class UserModelTest extends CIUnitTestCase
{
    use DatabaseTestTrait;
    
    protected $migrate = true;
    protected $migrateOnce = false;
    protected $refresh = true;
    
    public function testFindUserByEmail()
    {
        $model = new \App\Models\UserModel();
        
        // Insert test data
        $model->insert([
            'name' => 'John Doe',
            'email' => '[email protected]',
            'password' => password_hash('secret', PASSWORD_DEFAULT)
        ]);
        
        $user = $model->findByEmail('[email protected]');
        
        $this->assertNotEmpty($user);
        $this->assertEquals('John Doe', $user['name']);
    }
}

Feature Testing

<?php
// tests/feature/PostControllerTest.php
namespace Tests\Feature;

use CodeIgniter\Test\CIUnitTestCase;
use CodeIgniter\Test\FeatureTestTrait;
use CodeIgniter\Test\DatabaseTestTrait;

class PostControllerTest extends CIUnitTestCase
{
    use FeatureTestTrait, DatabaseTestTrait;
    
    protected $migrate = true;
    
    public function testGetPostsIndex()
    {
        $result = $this->get('/posts');
        
        $result->assertStatus(200);
        $result->assertSee('Blog Posts');
    }
    
    public function testCreatePost()
    {
        $data = [
            'title' => 'Test Post',
            'content' => 'This is a test post content.',
            'slug' => 'test-post'
        ];
        
        $result = $this->post('/posts', $data);
        
        $result->assertRedirectTo('/posts');
        $this->seeInDatabase('posts', ['title' => 'Test Post']);
    }
}

CLI Commands

Creating Custom Commands

<?php
// app/Commands/GenerateReport.php
namespace App\Commands;

use CodeIgniter\CLI\BaseCommand;
use CodeIgniter\CLI\CLI;

class GenerateReport extends BaseCommand
{
    protected $group = 'app';
    protected $name = 'generate:report';
    protected $description = 'Generate monthly user report';
    
    public function run(array $params)
    {
        CLI::write('Generating monthly report...', 'green');
        
        $userModel = new \App\Models\UserModel();
        $users = $userModel->where('created_at >=', date('Y-m-01'))
                          ->countAllResults();
        
        CLI::write("New users this month: {$users}", 'yellow');
        CLI::write('Report generated successfully!', 'green');
    }
}

// Usage: php spark generate:report

CodeIgniter provides a simple yet powerful framework for rapid web development with its intuitive MVC pattern, extensive documentation, and minimal configuration requirements.