【问题标题】:Trouble binding an imploded array into a mysql prepared statement无法将内爆数组绑定到 mysql 准备好的语句中
【发布时间】:2013-11-21 01:43:04
【问题描述】:

我对以下语法错误感到头疼。我正在尝试将内爆数组绑定到准备好的语句中,但出现以下语法错误:

您的 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')

【问题讨论】:

  • 对不起,我没有答案。我只是想说我认为这是一个巧妙的把戏。我自己可以多次使用这种技术进行动态绑定。
  • @LeeLoftiss 看到我的回答为什么这不起作用
  • 我的意思是我经常想要动态绑定,但我从来没有想过会有办法。我经常忘记 P​​HP 的通用性。下次我需要这个时,我会为你的答案添加书签。谢谢。

标签: php mysql mysqli prepared-statement


【解决方案1】:

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

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

  1. 动态生成您的类型字符串
  2. 使用call_user_func_array() 绑定参数

你可以像这样生成类型字符串:

$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()期望参数二通过引用传递的错误:

警告:mysqli_stmt::bind_param() 的参数 2 应为参考,已给出值

这有点烦人,但很容易解决。要解决这个问题,您可以使用以下函数:

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);

【讨论】:

  • 很好的答案,非常感谢您的解释。我不再收到任何 MySQL 错误,但由于某种原因没有从数据库中删除 email_addresses。我想知道,它们是字符串,是否需要用引号括起来?
  • 不。引号仅用于解释语句。对于不需要的准备好的语句。如果您有权访问您的查询日志,您可以查看您的 SQL 查询并验证它看起来是否正确并将其用于测试。我希望 mysqli 提供一种让查询运行的方法,但显然没有其他人认为它会是一个有用的功能。
  • 不幸的是我没有。我正在开发由 GoDaddy 托管的客户网站。我相信我会弄明白的,只是多久的问题!
  • 希望这能让你更接近。祝你好运!如果您发现此代码中有一些需要改进的地方,请告诉我,以便我可以将其发布给以后偶然发现的其他人。
  • 很好解释的答案,约翰。谢谢。你能解释更多关于 $types 变量的信息吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-11-12
  • 1970-01-01
  • 2014-09-27
  • 2015-07-13
  • 1970-01-01
相关资源
最近更新 更多