如何在使用 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 数字型变量的注入