CodeIgniter 2.0.3 中 Active Record 中奇怪的反引号行为
Posted
技术标签:
【中文标题】CodeIgniter 2.0.3 中 Active Record 中奇怪的反引号行为【英文标题】:Weird backticks behaviour in Active Record in CodeIgniter 2.0.3 【发布时间】:2011-11-20 21:47:17 【问题描述】:以前我的所有查询在 CI 2.0 版中运行良好,但是当我升级到 2.0.3 时,我的一些 SELECT 查询被破坏了。
CI 会自动添加 反引号 (``),但在旧版本中它会按原样运行。
CI 用户手册已指示在
中添加第二个参数db->选择
作为
错误
但还是不行。
代码如下:
class Company_model extends MY_Model
----------------
$this->db->select(' count('.$fieldname. ') as num_stations');
$this->db->select(" CONCAT_WS(',', clb_company.address1, clb_company.address2, clb_company.city, clb_company.state, clb_company.zipcode ) as companyAddress");
$this->db->from($this->_table);
$this->db->join($this->_table_device, $fieldname1. " = ". $fieldname2, 'LEFT');
$this->db->where($blablafield , '0');
----------------
错误如下:
Error Number: 1064
You have an error in your SQL syntax; check the manual that corresponds to your mysql server version for the right syntax to use near
'FROM (`clb_device`) JOIN `clb_company` ON `clb_company`.`id` = `clb_device`.`com' at line 2
SELECT `clb_device`.`id` as deviceId, `clb_pricing_specifications`.`name` as pricingSpecName, `clb_company`.`name` as companyName, `clb_device`.`mac_address` as deviceMacAddress,
`clb_device`.`reseller_model_number` as deviceModelNumber, `clb_pricing_spec_grouping`.`pricing_master_spec_id` as pricingSpecId, `clb_device`.`address` as deviceAddress,
`clb_device`.`is_home` as deviceIsHomeCharger, CONCAT(clb_company.portal_line1, `'/'`, `clb_device`.`name)` as deviceDisplayName FROM (`clb_device`) JOIN `clb_company`
ON `clb_company`.`id` = `clb_device`.`company_id` LEFT JOIN `clb_pricing_group_devices` ON `clb_device`.`id` = `clb_pricing_group_devices`.`device_id` and clb_pricing_group_devices.is_active = 1
LEFT JOIN `clb_pricing_spec_grouping` ON `clb_pricing_group_devices`.`pricing_spec_id` = `clb_pricing_spec_grouping`.`pricing_master_spec_id` LEFT JOIN `clb_pricing_specifications` ON
`clb_pricing_spec_grouping`.`pricing_spec_id` = `clb_pricing_specifications`.`id` WHERE clb_company.vendor_id is not null AND cast(substr(clb_devi
ce.software_version, 1, 3) as decimal(2,1)) > 2.0 AND clb_device.device_state > 0 GROUP BY `clb_device`.`id` ORDER BY CONCAT(trim(clb_company.portal_line1), `'/'`, trim(clb_device.name)) desc LIMIT 20
看看 CONCAT(trim(clb_company.portal_line1), `'/'`, trim(clb_device.name))
请提出解决方法。
【问题讨论】:
我原以为反引号对查询没有真正的影响,因为如果您使用echo $this->db->last_query();
并发布可以让我们更清楚地了解它的代码。
@simnom - 它正在制造问题,例如CONCAT(trim(table1.field1), '/', trim(table2.field2)) 被解析为 CONCAT(trim(table1.field1), '/'
, trim(table2.field2))
请在问题中包含您的活动记录代码。
@Louis --- 已经包含了有问题的代码示例,抱歉耽搁了
【参考方案1】:
在查询前使用这一行:
$this->db->_protect_identifiers=false;
这将停止向已构建的查询添加反引号。
【讨论】:
【参考方案2】:解决方法很简单: 在数据库配置文件 (./application/config/database.php) 中,使用默认设置向数组中添加一个新元素。
$db['default']['_protect_identifiers']= FALSE;
这个解决方案对我有用,而且更优雅、更专业。
【讨论】:
这对安全有影响吗?【参考方案3】:所有其他答案都很旧,这个适用于 CI 2.1.4
// set this to false so that _protect_identifiers skips escaping:
$this->db->_protect_identifiers = FALSE;
// your order_by line:
$this -> db -> order_by('FIELD ( products.country_id, 2, 0, 1 )');
// important to set this back to TRUE or ALL of your queries from now on will be non-escaped:
$this->db->_protect_identifiers = TRUE;
【讨论】:
【参考方案4】:class Company_model extends MY_Model
----------------
$this->db->select(" count('$fieldname') as num_stations",false);
$this->db->select(" CONCAT_WS(',', clb_company.address1, clb_company.address2, clb_company.city, clb_company.state, clb_company.zipcode ) as companyAddress",false);
$this->db->from($this->_table);
$this->db->join($this->_table_device, $fieldname1. " = ". $fieldname2, 'LEFT');
$this->db->where($blablafield , '0');
----------------
你说的false
是需要的,你可以试试上面的代码,把输出的内容复制粘贴给我们
echo $this->db->last_query();
这将向我们展示 DB 类正在准确创建什么,并且我们可以看到哪些工作正常/哪些不工作。可能是别的东西(你没有给出由此产生的错误,有时 sql 错误可能会产生误导。)
来自docs:
$this->db->select()
接受可选的第二个参数。如果您将其设置为FALSE
,CodeIgniter 将不会尝试使用反引号保护您的字段或表名称。如果您需要复合选择语句,这很有用。
【讨论】:
路易斯,我已经包含了查询和错误,请看一下。 这可能是一个很长的镜头,但您是否将错误参数放在公司信息上,而不是放在给出错误的查询上? (如您在此文件中是否使用了多个 concat?-示例代码和错误不匹配,可能只是您使用示例代码,也可能不是我不确定。)【参考方案5】:CI 只会保护你的 ACTIVE RECORD 调用,所以如果你运行$this->db->query();
你会没事的,并且根据注释你应该安全地使用 AD 调用来禁用反引号(不知道你为什么说他们不'不起作用,但我没有看到你的完整代码,所以我不能确定)
$this->db->select('(SELECT SUM(payments.amount) FROM payments WHERE payments.invoice_id=4') AS amount_paid', FALSE);
$query = $this->db->get('mytable');
确保FALSE
没有单引号(使其成为字符串),并且它可能无法验证(未经我测试)。
【讨论】:
感谢 Jakub 的解释,当您使用一些以逗号作为分隔符的内置函数时会出现真正的问题,例如我给出的示例 CONCAT(field1, '-', field2) 并且您想出了 concat (field1
, '-'
, field2
)【参考方案6】:
我认为你应该检查DB_driver.php文件,有一个名为protect_identifier的变量,重点是当你检查旧版本的CI时,你会看到新版本中缺少一个条件,escape检查可空性的变量,从旧版本粘贴该条件,你会没事的
【讨论】:
【参考方案7】:CI_DB_active_record::where()
有第三个参数用于转义,这对我来说比打开和关闭 CI_DB_driver::_protect_identifiers
效果更好
public function where($key, $value = NULL, $escape = TRUE)
不确定这是在哪个 CI 版本中添加的。
某人
【讨论】:
【参考方案8】:这是一个对我有用的技巧。替换这一行
$this->db->join($this->_table_device, $fieldname1. " = ". $fieldname2, 'LEFT');
用这个:
$this->db->join($this->_table_device, $fieldname1. " IN(". $fieldname2 .")", 'LEFT');
这将防止 CI 逃离您的领域。这并不理想,但比其他选择要好。
【讨论】:
【参考方案9】:我刚刚阅读了一个简单的解决方案...
我更改了 var $_escape_char 的值 (system/database/drivers/mysql/mysql_driver.php, line 36..
原来是
var $_escape_char = '`';
改为
var $_escape_char = ' ';
现在它可以工作了...但是如果我遇到任何安全问题我很害怕..
谢谢
【讨论】:
绝对是Roopa,你打开了INJECTIONS的门,不推荐,恢复原码。以上是关于CodeIgniter 2.0.3 中 Active Record 中奇怪的反引号行为的主要内容,如果未能解决你的问题,请参考以下文章
codeigniter 中是不是有子查询库?或者我如何在codeigniter 3中进行子查询?
CodeIgniter 4 项目中未定义的常量“CodeIgniter\Database\MySQLi\MYSQLI_STORE_RESULT”