codeigniter 3 中需执行原生 sql 时,应使用 query() 方法或在 query builder 方法中设第三个参数为 false 来绕过自动转义;涉及用户输入时必须手动过滤,严禁直接拼接未验证数据。

CodeIgniter 3 中默认会对查询语句中的变量做自动转义(通过 $this->db->escape() 或类似机制),但有时你需要执行**完全原生、不被转义的 SQL**,比如含复杂函数、子查询、UNION、自定义变量或存储过程调用等场景。CI3 并没有“全局关闭自动转义”的开关,而是需在具体执行环节绕过转义逻辑。
使用 query() 直接执行原生 SQL
这是最直接的方式:跳过 Query Builder(Active Record),不经过任何自动转义处理,把字符串原样交给数据库驱动执行。
- 确保 SQL 字符串由你完全控制(如硬编码、拼接前已严格过滤)
- 避免拼接用户输入——若必须含动态值,应手动调用
$this->db->escape()或escape_str()单独处理 - 示例:
$this->db->query("SELECT * FROM users WHERE status = 'active' AND created_at > DATE_SUB(NOW(), INTERVAL 7 DAY)");
禁用 Query Builder 的自动转义行为
当你仍想用 select()、where() 等链式方法,但需要某字段/值不被转义(例如调用 MySQL 函数或字段别名含表达式),可用以下方式:
-
第三个参数设为
false:在where()、like()、or_where()等方法中,第三个参数控制是否转义 - 示例:
$this->db->where('DATE(created_at)', 'CURDATE()', false);→ 生成WHERE DATE(created_at) = CURDATE(),不加引号 - 对字段名或表达式使用反引号时也需设
false:$this->db->select('COUNT(*) as total', false);
临时关闭全局转义(不推荐,仅限可信上下文)
CI3 的 $this->db->escape_str() 是底层转义入口,但无法全局禁用。若你在自定义模型方法中批量处理可信 SQL 片段,可:
- 继承
CI_DB_query_builder并重写_escape_identifiers()或_protect_identifiers()方法(高风险,影响范围大) - 更安全的做法是:封装一个专用方法,如
raw_where($sql),内部直接拼入$this->qb_where[]数组并标记为 raw - 注意:此类操作会破坏 Query Builder 的可移植性(如换数据库可能报错),且丧失防注入保障
关键提醒:安全永远优先
关闭转义 ≠ 放弃防护。只要涉及用户输入,就必须手动净化:
- 用
$this->db->escape()处理字符串值 - 用
(int)或filter_var($x, FILTER_SANITIZE_NUMBER_INT)处理数字 - 白名单校验字段名、表名(如用
in_array($field, ['id','name','status'])) - 永远不要把未验证的
$_GET或$_POST直接拼进 raw SQL











