如何在使用 SQLi 的 SQL IN 运算符的准备语句中使用 php 数组? [复制]

Posted

技术标签:

【中文标题】如何在使用 SQLi 的 SQL IN 运算符的准备语句中使用 php 数组? [复制]【英文标题】:How to use php array in a Prepared Statement for SQL IN Operator using SQLi? [duplicate] 【发布时间】:2014-01-23 03:46:09 【问题描述】:

这是我的代码:

if(isset($_POST['abc'])) 
   
    $things['abc'] =  mysqli_real_escape_string($connect, implode("','", $_POST['abc']));

    $result = mysqli_query($connect, "SELECT * FROM this_list WHERE abc_column IN ('$things['abc']')");

    if (!$result)  
           
        echo "Error fetching results: " . mysqli_error(); 

    
    else
    
        while ($row = mysqli_fetch_array($result))  
        
           $abc[] = $row['description'];  
        
    

上面的代码使用了 mysqli_real_escape_string(),$things 是一个带有复选框值的数组,通过 POST 接收。此数组包含我在查询中使用的以逗号分隔的字符串列表。

当我在网上搜索时,我注意到有人说mysqli_real_escape_string() 可能会阻止 sql 注入,我在想也许为复选框值准备的语句可能更安全地防止 sql 注入。

我使用了带有单独参数的预处理语句来防止 sql 注入。但是我被困在这个问题上,我不知道如何将上面的代码更改为 prepare() 语句,因为它使用数组$things['abc']。我尝试搜索,每次我在准备好的语句中搜索数组时,我都会获得有关 Java 等的信息。有人可以告诉我如何使用 php 做到这一点吗?

编辑:

在下面的 onetrickpony 代码的帮助下,这就是我现在所拥有的:

if(isset($_POST['abc'])) 
       
        $ph = rtrim(str_repeat('?,', count($_POST['abc'])), ',');
        $query = sprintf("SELECT col1 FROM abc_table WHERE col2 IN (%s)", $ph); 

        $stmt = mysqli_prepare($connect, $query);

        // bind variables 
        $params = array();
        foreach($_POST['abc'] as $v)
          $params[] = &$v;

        array_unshift($params, $stmt, str_repeat('s', count($_POST['abc'])));  // s = string type
        call_user_func_array('mysqli_stmt_bind_param', $params);

        mysqli_stmt_execute($stmt);

        // Get the data result from the query. 
        mysqli_stmt_bind_result($stmt, $col1);

        /* fetch values and store them to each variables */
        while (mysqli_stmt_fetch($stmt)) 
           $name[] = $col1;
           echo $name;         
        

        //loop to echo and see whats stored in the array above
        foreach($name as $v)   
               echo $v;
        


        // Close the prepared statement.
        $stmt->close();

    

在上面的代码中,prepare 语句的 sqli 方法似乎很有效。但是,当我使用 mysqli_stmt_bind_result() 时,while 循环中的 $name[] 数组似乎只打印最后一行。

更新:

onetrickpony 的代码使用 mysqli 方法在 Prepared Statement 中使用 php 数组运行良好,这是他建议的一个非常好的方法。但是,我一直在做噩梦,代码的后半部分试图让获取的数组结果正常工作。在尝试了一天多之后,我已经放弃了,我已经切换到 PDO。再次,onetrickpony 下面的建议是完全值得的。切换到 PDO 使代码变得如此简单和简单,简直不敢相信。

【问题讨论】:

PHP PDO: Can I bind an array to an IN() condition 感谢您的链接。有没有 SQLi 方法呢?我没有使用 PDO,我所有的脚本 atm 都使用 sqli 方法。 【参考方案1】:

试试这个:

// build placeholder string (?,?...)
$ph = rtrim(str_repeat('?,', count($_POST['abc'])), ',');
$query = sprintf("SELECT * FROM this_list WHERE abc_column IN (%s)", $ph);

$stm = mysqli_prepare($connect, $query);

// bind variables (see my notes below)
$params = array();
foreach($_POST['abc'] as $v)
  $params[] = &$v;

                                      // s = string type
array_unshift($params, $stm, str_repeat('s', count($_POST['abc'])));  
call_user_func_array('mysqli_stmt_bind_param', $params);

mysqli_stmt_execute($stm);

看来mysqli_stmt_bind_param不能多次调用绑定多个变量。更糟糕的是,它需要引用变量。我建议您切换到 PDO,只是因为这些限制迫使您编写丑陋的代码:)

【讨论】:

我喜欢你的方法。但是当我尝试这个时,我得到了错误mysqli_stmt_bind_param() [function.mysqli-stmt-bind-param]: Number of variables doesn't match number of parameters in prepared statement 它现在应该可以工作了。我高估了mysqli_stmt_bind_param :) 对不起..尝试了更新的代码,但它显示此错误mysqli_stmt_bind_param() expects parameter 1 to be mysqli_stmt, string given。这个错误指的是这一行:call_user_func_array('mysqli_stmt_bind_param', $params); 我认为它现在有效。使用str_repeat() 进行的最后一次编辑做到了。执行上述准备好的语句后,当我像这样绑定结果时:$stm->bind_result($col1, $col2); while ($stm->fetch()) $id = $col1; $name = $col2; $stmt->close();,它只打印第一行 id 和 name,而不是完整列表。 mysqli_stmt_execute 后面的 bind_result 语句是否遗漏了什么? 试试程序版本:mysqli_stmt_bind_result($stm, $col1, $col2)

以上是关于如何在使用 SQLi 的 SQL IN 运算符的准备语句中使用 php 数组? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

如何在 SQL (JPA) 中使用带有 IN 运算符的嵌套 SELECT 语句?

ThinkPHP 3.1,3.2中对IN和BETWEEN正则匹配不当导致的一个SQLi

SQL注入:sqli-labs Lesson-2 数字型变量的注入

如何在 Tedious 中运行 sql 查询,为 sql in 运算符提供多个值?

如何在使用变量的动态查询中指定 IN 子句?

如何创建 SQL 运算符组合,如 ALL IN,NOT ALL IN