Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save croxton/2923657 to your computer and use it in GitHub Desktop.
Save croxton/2923657 to your computer and use it in GitHub Desktop.
CodeIgniter 2.1.0 alias escaping problems
CI 2.1-stable Active Record tries to escape db tables, fields and aliases with backticks, however it can trip up on queries such as...
$this->CI->db->where("last_activity < {$expire}");
... which is an example actually used in the Session class in 2.1-stable.
So out of the box you will get an SQL error when using database sessions.
Of course that should probably be rewritten:
$this->CI->db->where("last_activity <", $expire);
However, this type of query also generates an SQL error:
$this->CI->db->select('DATE_FORMAT(news.date_start, "%a, %d %b %Y %T") as news_date');
Note that passing a second parameter as FALSE does not disable the attempted escaping of field aliases
(it only stops backticks around table names and fields). This also throws an SQL error:
$this->CI->db->select('DATE_FORMAT(news.date_start, "%a, %d %b %Y %T") as news_date', FALSE);
The following is a quick workaround which allows the above to work as expected, but only by disabling backticks
for select / where statements like the above. Note that it will only work if your table names, field names
and aliases use only alphanumeric characters and underscores and you are not using reserved names for any of these:
function _protect_identifiers() in /system/database/DB_driver.php
------- Replace this -------
// If the item has an alias declaration we remove it and set it aside.
// Basically we remove everything to the right of the first space
if (preg_match('/^([^\s]+) (AS )*(.+)$/i', $item, $matches))
{
$item = $matches[1];
// Escape the alias
$alias = ' '.$matches[2].$this->_escape_identifiers($matches[3]);
}
else
{
$alias = '';
}
// This is basically a bug fix for queries that use MAX, MIN, etc.
// If a parenthesis is found we know that we do not need to
// escape the data or add a prefix. There's probably a more graceful
// way to deal with this, but I'm not thinking of it -- Rick
if (strpos($item, '(') !== FALSE)
{
return $item.$alias;
}
------- With this -------
// If the item has an alias declaration we remove it and set it aside.
// Basically we remove everything to the right of the first space
if (preg_match('/^([^\s]+) (AS )*([a-zA-Z0-9_]+)$/i', $item, $matches))
{
$item = $matches[1];
// escape the alias
if ($protect_identifiers === TRUE)
{
$alias = ' '.$matches[2].$this->_escape_identifiers($matches[3]);
}
else
{
$alias = ' '.$matches[2].$matches[3];
}
}
else
{
$alias = '';
}
// This is a bug fix for queries that use MAX, MIN, DATE_FORMAT, <= etc.
// If the the identifier contains any character that is NOT alphanumeric or underscore
// we assume that we do not need to escape the identifier or add a prefix.
if (preg_match('/^([a-zA-Z0-9_\.]+)$/', $item) == 0)
{
return $item.$alias;
}
@stefkes
Copy link

stefkes commented Jun 15, 2012

I fail to reproduce this error on a clean 2.1 install so I'll try to track down why it happens to some of us. Will follow up.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment