Codeigniter Active Record中如何在WHERE子句使用SOUNDS LIKE?
解决CodeIgniter Active Record中SOUNDS LIKE的语法错误问题
问题分析
你遇到的问题是CodeIgniter的Active Record自动把SOUNDS当成了字段名,给它加上了反引号,导致生成的SQL语句出现语法错误。从你提供的错误SQL能明显看到:
OR `name` `SOUNDS` LIKE 'technolog'
这里SOUNDS被错误地加上了反引号,但SOUNDS LIKE是MariaDB/MySQL的原生语法,根本不需要被转义或加反引号。
解决方案
要搞定这个问题,你得告诉CodeIgniter不要对SOUNDS LIKE这部分条件做转义处理,同时还要注意规避SQL注入风险,推荐两种安全的处理方式:
方法1:关闭单个条件的转义
用or_where的第二个参数FALSE,明确告诉CI不要转义当前条件:
foreach($qes as $k){ // 第二个参数FALSE阻止CI转义这个条件 $this->db->or_where("name SOUNDS LIKE '$k'", FALSE); }
不过这种方式直接拼接变量$k存在SQL注入风险,如果你能确保$k已经被安全过滤,可以用;否则更推荐下面的方法。
方法2:使用查询绑定(更安全)
CodeIgniter支持查询绑定,会自动处理变量的转义,同时不会破坏SOUNDS LIKE的语法:
foreach($qes as $k){ // 使用?作为占位符,第二个参数传入变量,CI自动处理转义 $this->db->or_where("name SOUNDS LIKE ?", $k); }
另外,你原代码里SOUNDEX(name) IN({$q})的写法也有SQL注入隐患,同样可以改成绑定形式:
// 假设$q是单个值,如果是多个值可以传数组 $this->db->where("SOUNDEX(name) IN(?)", $q);
修正后的完整代码
function _search($type, $q, $qes, $sort = null, $start = 0) { $type = strtolower($type); $q = strtolower($q); $this->db->select("*"); $this->db->from("books"); // 用绑定方式替换直接拼接,规避注入风险 $this->db->where("SOUNDEX(name) IN(?)", $q); foreach($qes as $k){ // 使用查询绑定处理SOUNDS LIKE,避免语法错误和注入 $this->db->or_where("name SOUNDS LIKE ?", $k); } foreach($qes as $k){ // 模糊查询也用绑定更安全 $this->db->or_where("name LIKE ?", "%$k%"); } $this->db->where("status", 1); if ($type != NULL) { $this->db->where("LOWER(type)", $type); } $this->db->limit(BWK_MAX_BOOK_SIZE, $start); switch ($sort) { case 1: break; case 2: $this->db->order_by("sellingPrice", "ASC"); break; case 3: $this->db->order_by("sellingPrice", "DESC"); break; case 4: $this->db->order_by("created", "DESC"); break; } }
验证效果
修正后生成的SQL会变成正确的形式:
SELECT * FROM `books` WHERE SOUNDEX(name) IN('t254') OR name SOUNDS LIKE 'technolog' OR name LIKE '%technologi%' AND `status` = 1 AND LOWER(type) = 'school' LIMIT 50
这样既不会有语法错误,还能避免SQL注入的风险。
内容的提问来源于stack exchange,提问作者lokesh jain
相关产品推荐
相关产品推荐

