无法将内爆数组绑定到mysql预处理语句中

时间:2013-11-21 01:43:04

标签: php mysql mysqli prepared-statement

我正在打破以下语法错误。我试图将一个内爆数组绑定到一个预准备语句,但我得到以下语法错误:

您的SQL语法出错;检查与您的MySQL服务器版本对应的手册,以便在'?'附近使用正确的语法第1行

这是我的代码。谁能看到我错在哪里?

<?php 
include('config.php');

$selected = $_POST['selected'];

if ($stmt = $mysqli->prepare("DELETE FROM email_addresses WHERE email_addresses IN ?")) {

    $stmt->bind_param("s", "('" . implode("', '", $selected) . "')" );

    $stmt->execute();

    $stmt->close();

    print "ok";

} else {
    print $mysqli->error;
}

$mysqli->close();

?>

作为测试,我尝试过:

print "('" . implode("', '", $selected) . "')";

哪个正确地给了我

('me@me.com', 'you@you.com')

1 个答案:

答案 0 :(得分:2)

让我省去一些麻烦,并告诉你,你想要做的事情无论如何都行不通。您只将一个参数绑定到IN()函数调用。您认为您正在传递以逗号分隔的列表,但实际上您只传递一个逗号分隔的字符串,该字符串被视为一个值。这意味着您将搜索一条记录,其值为“'me@me.com”,“you @ you.com”,而不是与“me@me.com”匹配的记录或“you@you.com”。

要解决这个问题,您需要:

  1. 动态生成您的类型字符串
  2. 使用call_user_func_array()绑定参数
  3. 您可以像这样生成类型字符串:

    $types = str_repeat('s', count($selected));
    

    所有这一切都是创建一个s的字符串,其字符数与数组中的元素数一样多。

    然后你会使用call_user_func_array()这样绑定你的参数(注意我把括号放回IN()函数中):

    if ($stmt = $mysqli->prepare("DELETE FROM email_addresses WHERE email_addresses IN (?)")) {
        call_user_func_array(array($stmt, "bind_param"), array_merge($types, $selected));
    

    但是如果你试试这个,你会得到一个错误,mysqli_stmt::bind_param()期望参数2通过引用传递:

      

    警告:参数2到mysqli_stmt :: bind_param()应该是一个参考,给定值

    这有点烦人但很容易解决。要解决此问题,您可以使用以下功能:

    function refValues($arr){ 
        $refs = array(); 
        foreach($arr as $key => $value) 
            $refs[$key] = &$arr[$key]; 
        return $refs; 
    } 
    

    它只是创建一个值数组,这些值是$selected数组中值的引用。这足以使mysqli_stmt::bind_param()满意:

    if ($stmt = $mysqli->prepare("DELETE FROM email_addresses WHERE email_addresses IN (?)")) {
        call_user_func_array(array($stmt, "bind_param"), array_merge($types, refValues($selected)));