繁体   English   中英

Codeigniter 问题与 escaping 值在 where 子句中使用“in”传递数组进行查询时

[英]Codeigniter issue with escaping values when passing array to query with “in” in the where clause

我在 codeigniter 项目的 model 中有下面的 function,变量$id是一个数组,例如,包含(1,2,3) 现在我正在重新审视它,我认为我实际上并不是 escaping 我的数组$id 我想我必须将行$this->db->escape($id)更改$id = $this->db->escape($id)

如果我这样做,那么它会在数组中的每个元素周围加上单引号,并将其视为一个长字符串,如下所示: '(1,2,3)'

有人可以确认我实际上不是 escaping 我的变量并建议解决方案或让我知道这是否是 codeigniter 框架中的错误?

function get_ratings($id)
    {

        $this->db->escape($id); // had to manually escape the variable since it's being used in an "in" in the where clause. 

        $sql = "select * from toys t
                 where t.toy_id in ($id)";

        $query = $this->db->query($sql, $id);

        if($query->num_rows() > 0)
        {
            return $query->result_array();
        }
        else
        {
            return false;
        }
    }

您可能对使用 CI活动记录class 感兴趣:

除了简单之外,使用 Active Record 功能的一个主要好处是它允许您创建独立于数据库的应用程序,因为查询语法是由每个数据库适配器生成的。 它还允许更安全的查询,因为系统会自动转义这些值。

您重写的查询将如下所示(假设$id是一个数组):

$this->db->where_in('toy_id', $id)->get('toys');

旁白:我承认我有点困惑,因为看起来$ids将是一个更合适的变量名,而您在查询中使用它的方式,我会假设它是一个字符串......

如果您不喜欢活动记录,您可能还会发现查询绑定很有用:

使用绑定的第二个好处是值会自动转义,从而产生更安全的查询。 您不必记住手动转义数据; 引擎会自动为您完成。


编辑:稍后回顾一下,看起来这就是你想要做的。 在这种情况下,请尝试替换:

$sql = "select * from toys t where t.toy_id in ($id)";

和:

$sql = "select * from toys t where t.toy_id in (?)";

并将$id作为第二个参数传递给query() ,但作为逗号分隔的字符串( implode(',', $id)如果$id确实是一个数组)。


否则你可能想使用$this->db->escape_str()

$this->db->escape_str() 这个 function 对传递给它的数据进行转义,无论类型如何。

以下是 mysql 驱动程序源代码的摘录,或许可以让您放心。

function escape_str($str, $like = FALSE)
{
    if (is_array($str))
    {
        foreach ($str as $key => $val)
        {
            $str[$key] = $this->escape_str($val, $like);
        }

        return $str;
    }
   // continued...

它循环通过 arrays 并转义它们的值。

看来$this->db->escape escape 确实不适用于 arrays。

$this->db->escape() 这个 function 确定数据类型,以便它只能转义字符串数据。

这是来源:

function escape($str)
{
    if (is_string($str))
    {
        $str = "'".$this->escape_str($str)."'";
    }
    elseif (is_bool($str))
    {
        $str = ($str === FALSE) ? 0 : 1;
    }
    elseif (is_null($str))
    {
        $str = 'NULL';
    }

    return $str;
}

看起来它忽略了 arrays。

无论如何,希望您找到适合您的解决方案。 我投票支持 Active Record。

您想要做的是转义数组中的各个值。 所以你可以先在数组上使用array_map

$id = array_map('some_escape_function', $id);

参见: http://php.net/manual/en/function.array-map.php

然后你可以这样做:

$in = join(",",$id);

您的 SQL 将是:

WHERE t.toy_id in ($in)

这给了你:

WHERE t.toy_id in ('1','2','3')

这是我使用 CI 2.1.2 的解决方案:

1) 将 /system/database/DB.php 复制到 application/database/DB.php,在第 123 行附近,使其看起来像:

...
if ( ! isset($active_record) OR $active_record == TRUE)
{
    require_once(BASEPATH.'database/DB_active_rec.php');
    require_once(APPPATH.'database/MY_DB_active_rec' . EXT);

    if ( ! class_exists('CI_DB'))
    {
        eval('class CI_DB extends MY_DB_active_record { }');
    }
}
...

2)在应用程序/核心中创建MY_Loader.php:


class MY_Loader extends CI_Loader
{
  function __construct()
  {
    parent::__construct();
    log_message('debug', 'MY Loader Class Initialized');
  }

  public function database($params = '', $return = FALSE, $active_record = NULL) {
    // Grab the super object
    $CI = & get_instance();

    // Do we even need to load the database class?
    if (class_exists('CI_DB') AND $return == FALSE AND $active_record == NULL AND isset($CI->db) AND is_object($CI->db)) {
      return FALSE;
    }

    //require_once(BASEPATH . 'database/DB.php');
    require_once(APPPATH . 'database/DB' . EXT);

    if ($return === TRUE) {
      return DB($params, $active_record);
    }

    // Initialize the db variable.  Needed to prevent
    // reference errors with some configurations
    $CI->db = '';

    // Load the DB class
    $CI->db = & DB($params, $active_record);
  }

}

3)创建应用程序/数据库/MY_DB_active_rec.php:


class MY_DB_active_record extends CI_DB_active_record {

  public function __construct($params)
  {
    parent::__construct($params);
    log_message('debug', 'MY Active Record Database Driver Class Initialized');
  }

  private function _array_escape(&$str)
  {
    $str = "'" . $this->escape_str($str) . "'";
  }

  function escape($str)
  {
    if (is_array($str))
    {
      array_walk($str, array($this, '_array_escape'));
      return implode(',', $str);
    }
    elseif (is_string($str))
    {
      $this->_array_escape($str);
    }
    elseif (is_bool($str))
    {
      $str = ($str === FALSE) ? 0 : 1;
    }
    elseif (is_null($str))
    {
      $str = 'NULL';
    }

    return $str;
  }

}

然后你只需传入一个值数组:

$in_data = array(1, 2, 3);
$this->db->query('SELECT * FROM table WHERE id IN(?)', array($in_data));

它不漂亮,但它似乎可以解决问题!

你可以尝试这样的事情:

$sql = 'select * from toys t where t.toy_id in ('.
  join(',',array_map(function($i) {
    return $this->db->escape($i);
  }, $id)).');';

*免责声明:我现在无法访问我的 PHP/MySQL 服务器,所以我没有对此进行验证。 可能需要进行一些修改和/或调整。

要绑定它们,您可以执行以下操作:

$queryParams = [];

// to add the appropriate amount of bindings ?
$idBindings = str_replace(' ', ',', trim(str_repeat("(?) ", count($ids))));

// add each id with int validation
foreach ($ids as $id) {
    if(is_int(intVal($id)) == TRUE){
        array_push($queryParams, intVal($id));
    }
}

// the other option commented out below is to merge without checking - 
// note: sometimes values look like numeric values but are actually strings
//queryParams = array_merge($queryParams, $ids);


$sql = "select * from toys t where t.toy_id in ('. $idBindings .')";
$query = $this->db->query($sql, $queryParams );

Code Igniter v3 现在自动转义数组值:

http://www.codeigniter.com/userguide3/database/queries.html

查询绑定

绑定使您能够通过让系统为您将查询放在一起来简化查询语法。 考虑以下示例:

$sql = "SELECT * FROM some_table WHERE id =? AND status =? AND author =?"; $this->db->query($sql, array(3, 'live', 'Rick'));

查询中的问号会自动替换为查询 function 的第二个参数中的数组中的 > 值。

绑定也适用于 arrays,它将转换为 IN 集:

$sql = "SELECT * FROM some_table WHERE id IN? AND status =? AND author =?"; $this->db->query($sql, array(array(3, 6), 'live', 'Rick'));

结果查询将是:

SELECT * FROM some_table WHERE id IN (3,6) AND status = 'live' AND author = 'Rick'

使用绑定的第二个好处是值会自动转义,从而产生更安全的查询。 您不必记住手动转义数据; 引擎会自动为您完成。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM