mcpField
C
codeigniter

codeigniter

github.com/yasserstudio开发9205 次安装28 周前更新
代码仓库

关于 codeigniter

面向 CodeIgniter 开发者的开发指导,覆盖 CI3 和 CI4,并要求先识别项目版本再编写代码。内容包括框架模式、安全实践、常见功能及 CI3 到 CI4 的迁移参考。

主要功能

  1. 01识别 CI3 与 CI4 项目版本
  2. 02指导控制器、模型和路由实现
  3. 03涵盖查询、表单与会话模式
  4. 04提供两版本安全检查清单
  5. 05参考 CI3 到 CI4 迁移映射

适用场景

  1. 01为现有 CodeIgniter 项目编写功能
  2. 02确认代码应遵循的版本模式
  3. 03检查输入处理与输出转义安全
  4. 04规划 CI3 项目迁移到 CI4

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/yasserstudio/codeigniter-skills --skill codeigniter

安装后在 Claude Code 中输入/codeigniter确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

references/
ci3.md
ci4.md
deployment.md

详细介绍

CodeIgniter 开发

你是 CodeIgniter 专家,熟悉 CI3(3.1.x)和 CI4(4.x,最新稳定版 4.7.x),并了解它们在架构上的根本差异。编写任何代码前,务必先确认项目使用的版本。

如需深入了解特定版本的功能,请参阅:

  • CI3 深入指南 — 文件上传、电子邮件、缓存、分页、库、HMVC、钩子、辅助函数、日志记录
  • CI4 深入指南 — REST 控制器、实体、过滤器、迁移、数据填充器、上传、电子邮件、缓存、服务、事件、视图、单元格、Spark CLI、测试、Shield 身份验证、内容协商
  • 部署与迁移 — 服务器配置、生产环境检查清单、完整的 CI3→CI4 迁移对照表

版本检测

特征版本
存在 system/core/CodeIgniter.phpCI3
$this->load->model() / $this->load->view()CI3
application/config/config.phpCI3
存在 app/Config/App.phpCI4
控制器中有 namespace App\Controllers;CI4
项目根目录下有 spark CLICI4
composer.json 依赖 codeigniter4/frameworkCI4

CI3 — 核心模式

项目结构
project/
├── application/
│   ├── config/        # autoload.php, config.php, database.php, routes.php, hooks.php
│   ├── controllers/
│   ├── models/
│   ├── views/
│   ├── libraries/
│   ├── helpers/
│   ├── hooks/
│   ├── core/          # MY_Controller, MY_Model overrides
│   └── third_party/
├── system/            # framework core — never edit
└── index.php          # front controller
控制器
<?php
defined('BASEPATH') or exit('No direct script access allowed');

class Products extends CI_Controller
{
    public function __construct()
    {
        parent::__construct();
        $this->load->model('product_model');
        $this->load->helper('url');
    }

    public function index()
    {
        $data['products'] = $this->product_model->get_all();
        $this->load->view('products/index', $data);
    }

    public function view($id)
    {
        $data['product'] = $this->product_model->get($id);
        if (empty($data['product'])) {
            show_404();
        }
        $this->load->view('products/view', $data);
    }
}

规则: 类名必须与文件名一致(首字母大写)。务必调用 parent::__construct()。在 Linux 上,文件名区分大小写。

模型
<?php
defined('BASEPATH') or exit('No direct script access allowed');

class Product_model extends CI_Model
{
    protected $table = 'products';

    public function get_all()
    {
        return $this->db->get($this->table)->result();
    }

    public function get($id)
    {
        return $this->db->get_where($this->table, ['id' => $id])->row();
    }

    public function insert($data)
    {
        $this->db->insert($this->table, $data);
        return $this->db->insert_id();
    }

    public function update($id, $data)
    {
        $this->db->where('id', $id);
        return $this->db->update($this->table, $data);
    }

    public function delete($id)
    {
        return $this->db->delete($this->table, ['id' => $id]);
    }
}
查询构造器
// SELECT with chaining
$results = $this->db
    ->select('p.*, c.name as category_name')
    ->from('products p')
    ->join('categories c', 'c.id = p.category_id', 'left')
    ->where('p.active', 1)
    ->where('p.price >', 10)
    ->order_by('p.name', 'ASC')
    ->limit(20, $offset)
    ->get()
    ->result();

// INSERT / UPDATE / DELETE
$this->db->insert('products', ['name' => $name, 'price' => $price]);
$this->db->where('id', $id)->update('products', ['price' => $new_price]);
$this->db->where('id', $id)->delete('products');

// Transactions
$this->db->trans_start();
$this->db->insert('orders', $order_data);
$this->db->insert('order_items', $item_data);
$this->db->trans_complete();
if ($this->db->trans_status() === FALSE) { /* failed */ }

// Raw query (always bind params)
$this->db->query('SELECT * FROM products WHERE slug = ?', [$slug]);
路由
$route['default_controller'] = 'home';
$route['404_override'] = 'errors/page_missing';
$route['products'] = 'catalog/index';
$route['products/(:num)'] = 'catalog/view/$1';
$route['api/products/(:any)'] = 'api/products/$1';
输入与安全
// ALWAYS use $this->input — never raw $_POST/$_GET
$name = $this->input->post('name', TRUE);  // TRUE = XSS filter
$id   = $this->input->get('id');

// CSRF — enable in config.php
$config['csrf_protection'] = TRUE;

// Output escaping in views
<?php echo html_escape($user_input); ?>
表单验证
$this->load->library('form_validation');
$this->form_validation->set_rules('name', 'Name', 'required|min_length[3]|max_length[255]');
$this->form_validation->set_rules('email', 'Email', 'required|valid_email|is_unique[users.email]');

if ($this->form_validation->run() === FALSE) {
    $this->load->view('form', $data);
} else {
    $this->product_model->insert($this->input->post());
    redirect('products');
}
会话
$this->session->set_userdata('user_id', $id);
$user_id = $this->session->userdata('user_id');
$this->session->set_flashdata('success', 'Product created.');

CI4 — 核心模式

项目结构
project/
├── app/
│   ├── Config/        # App.php, Database.php, Routes.php, Filters.php, Services.php, Events.php
│   ├── Controllers/   # BaseController.php
│   ├── Models/
│   ├── Views/
│   ├── Filters/
│   ├── Entities/
│   ├── Cells/
│   ├── Commands/
│   ├── Database/      # Migrations/, Seeds/
│   └── Language/
├── public/            # web root — point server here
│   └── index.php
├── writable/          # cache, logs, session — must be writable by web server
├── tests/
├── .env
├── spark              # CLI tool
└── composer.json
控制器
<?php

namespace App\Controllers;

class Products extends BaseController
{
    public function index()
    {
        $model = model('ProductModel');
        return view('products/index', ['products' => $model->findAll()]);
    }

    public function show($id = null)
    {
        $product = model('ProductModel')->find($id);
        if ($product === null) {
            throw \CodeIgniter\Exceptions\PageNotFoundException::forPageNotFound();
        }
        return view('products/show', ['product' => $product]);
    }

    public function create()
    {
        if (! $this->validate([
            'name'  => 'required|min_length[3]|max_length[255]',
            'price' => 'required|numeric|greater_than[0]',
        ])) {
            return view('products/create', ['validation' => $this->validator]);
        }
        model('ProductModel')->insert($this->request->getPost());
        return redirect()->to('/products')->with('success', 'Product created.');
    }
}
模型
<?php

namespace App\Models;

use CodeIgniter\Model;

class ProductModel extends Model
{
    protected $table         = 'products';
    protected $primaryKey    = 'id';
    protected $returnType    = 'array';
    protected $useSoftDeletes = true;
    protected $useTimestamps  = true;

    protected $allowedFields = ['name', 'price', 'category_id', 'active'];

    protected $validationRules = [
        'name'  => 'required|min_length[3]|max_length[255]',
        'price' => 'required|numeric|greater_than[0]',
    ];
}

重要: $allowedFields 是必需的——未列出的字段会在插入/更新时被静默丢弃。这可以防止批量赋值。

查询构造器
$db = db_connect();

// SELECT with joins + pagination
$model = model('ProductModel');
$data = [
    'products' => $model->where('active', 1)->paginate(20),
    'pager'    => $model->pager,
];

// Raw builder
$results = $db->table('products')
    ->select('products.*, categories.name as category')
    ->join('categories', 'categories.id = products.category_id', 'left')
    ->where('products.active', 1)
    ->orderBy('products.name', 'ASC')
    ->get()
    ->getResultArray();

// Transactions
$db->transStart();
$db->table('orders')->insert($order_data);
$db->table('order_items')->insert($item_data);
$db->transComplete();
if (! $db->transStatus()) { /* failed */ }
路由
$routes->get('/', 'Home::index');
$routes->get('products', 'Products::index');
$routes->get('products/(:num)', 'Products::show/$1');
$routes->post('products', 'Products::create');
$routes->resource('products'); // generates all CRUD routes

$routes->group('api', ['namespace' => 'App\Controllers\Api', 'filter' => 'apiauth'], function ($routes) {
    $routes->resource('products');
});

$routes->get('admin/(:any)', 'Admin::$1', ['filter' => 'auth']);
输入与安全
// ALWAYS use $this->request — never raw $_POST/$_GET
$name = $this->request->getPost('name');
$id   = $this->request->getGet('id');
$data = $this->request->getJSON(true); // JSON API bodies → array

// Output escaping in views — context-aware
<?= esc($user_input) ?>
<?= esc($value, 'attr') ?>
<?= esc($value, 'js') ?>
会话
$session = session();
$session->set('user_id', $id);
$userId = $session->get('user_id');
$session->setFlashdata('success', 'Done.');
$session->setTempdata('otp', $code, 300); // auto-expires in 5 minutes

安全检查清单(两个版本均适用)

  • 切勿使用原始 $_POST/$_GET——使用输入类(CI3)或 $this->request(CI4)
  • 启用 CSRF 保护;仅对无状态 API 端点豁免
  • 使用查询构造器或绑定参数——切勿拼接 SQL
  • 转义输出:在视图中使用 html_escape()(CI3)或 esc()(CI4)
  • 在生产环境中设置 db_debug = FALSE(CI3)/ CI_ENVIRONMENT = production(CI4)
  • 将 system/(CI3)或项目根目录(CI4)置于 Web 根目录之外
  • 在 CI4 模型中使用 $allowedFields,防止批量赋值
  • 验证文件上传——检查 MIME 类型,而不只是扩展名
  • 设置安全的会话配置:database 驱动、httponly、secure 标志
  • HTML 属性使用 esc($var, 'attr'),JS 上下文使用 esc($var, 'js')
  • 为生产环境设置 Content-Security-Policy 标头
  • 全程使用 HTTPS——在 CI4 中设置 app.forceGlobalSecureRequests = true
  • 切勿在生产环境中暴露堆栈跟踪

CI3 → CI4 快速参考

CI3CI4
$this->load->model('x')model('XModel') 或 DI
$this->load->view('x', $data)return view('x', $data)
$this->load->library('x')service('x') 或 new X()
$this->input->post('x')$this->request->getPost('x')
$this->db->get('table')$db->table('table')->get()
$query->result() / ->row()$query->getResult() / ->getRow()
$query->result_array()$query->getResultArray()
redirect('url')return redirect()->to('url')
show_404()throw PageNotFoundException::forPageNotFound()
$this->session->userdata('x')session()->get('x')
html_escape($x)esc($x)
$route['x'] = 'y'$routes->get('x', 'Y::method')
钩子($hook[])过滤器(中间件)
CI_Controller / CI_ModelBaseController / CodeIgniter\Model
无命名空间PSR-4 命名空间
无 CLI 生成器php spark make:*

完整的 30 多项映射迁移对照表、服务器配置和生产部署检查清单,请参阅 deployment.md。

评论

支持 Markdown