Php 将内爆数组绑定到mysql准备语句时出现问题

Php 将内爆数组绑定到mysql准备语句时出现问题,php,mysql,mysqli,prepared-statement,Php,Mysql,Mysqli,Prepared Statement,我正在为下面的语法错误绞尽脑汁。我试图将一个内爆数组绑定到一个准备好的语句中,但出现以下语法错误: 您的SQL语法有错误;检查与MySQL服务器版本对应的手册,以了解第1行“?”附近使用的正确语法 这是我的密码。谁能看出我错在哪里 <?php include('config.php'); $selected = $_POST['selected']; if ($stmt = $mysqli->prepare("DELETE FROM email_addresses WHERE

我正在为下面的语法错误绞尽脑汁。我试图将一个内爆数组绑定到一个准备好的语句中,但出现以下语法错误:

您的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();

?>
这给了我正确的答案

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

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

要克服这一问题,您需要:

  • 动态生成您的类型字符串
  • 用于绑定参数
  • 您可以生成如下类型的字符串:

    $types = str_repeat('s', count($selected));
    
    所做的一切就是创建一个
    s
    字符串,其字符数与数组中的元素数相同

    然后,您可以像这样使用
    call\u user\u func\u array()
    绑定参数(注意,我为
    in()
    函数放回了括号):

    但是,如果您尝试此操作,您将得到一个关于
    mysqli_stmt::bind_param()
    期望通过引用传递参数2的错误:

    警告:mysqli_stmt::bind_param()的参数2应为引用,给定值

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

    if ($stmt = $mysqli->prepare("DELETE FROM email_addresses WHERE email_addresses IN (?)")) {
        call_user_func_array(array($stmt, "bind_param"), array_merge($types, $selected));
    
    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)));
    
    编辑

    从PHP 5.6开始,您现在可以使用
    操作符使其更简单:

    $stmt->bind_param($types, ...$selected);
    

    对不起,我没有答案。我只是想说,我认为这是一个巧妙的伎俩。我自己也可以在动态绑定中使用这种技术好几次。@LeeLoftiss请看我的答案,为什么这样做不起作用我的意思是我经常想要动态绑定,但我从来没有想到会有一种方法。我经常忘记PHP的多功能性。下次我需要这个时,我会把你的答案加入书签。谢谢。回答得很好,非常感谢你的解释。我不再收到任何MySQL错误,但由于某种原因,电子邮件地址不会从数据库中删除。我想知道,它们是否需要被引语包围,因为它们是字符串?不需要。引号仅用于解释语句。用于准备不需要的报表。如果您有权访问查询日志,则可以查看SQL查询并验证它是否正确,并将其用于测试。我希望mysqli提供了一种运行查询的方法,但显然没有人认为这是一种有用的功能。不幸的是,我没有。我在一个由GoDaddy托管的客户网站上工作。我相信我会弄明白的,这只是一个多久的问题!希望这能让你更亲近。祝你好运如果您注意到这段代码中有一些需要改进的地方,请告诉我,这样我就可以为以后偶然发现这段代码的其他人发布。答案解释得很好,John。谢谢你能解释一下$types变量吗。
    $stmt->bind_param($types, ...$selected);