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
- Lightweight and Fast: Small footprint with excellent performance
- Simple MVC Pattern: Easy to understand architecture
- Rich Library Set: Built-in libraries for common tasks
- Excellent Documentation: Clear and comprehensive guides
- Flexible Routing: Powerful URL routing system
- 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.