1

对于给定的代码,我收到以下 SQL 错误。

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

编码:

$set_query = "";

foreach ($passed_columns as $c)
{
    $set_query .= $c . " = " . ':' . $c . ',';
}

$p = strlen($set_query);
$set_query[$p-1] = "";

$SQL = 'UPDATE users SET ' . $set_query . ' WHERE user_id IN (' . implode(",", $_POST['user_id']) . ')';

$stmt = $dbh->prepare($SQL);

foreach($_POST['cols'] as $key => $val)
{
    $stmt->bindValue(':' . $key, $val);
}

if (!$stmt->execute()) {
    die(print_r($stmt->errorInfo()));
}

$_POST['cols'] 包含一个键值数组(column_name => 新列值)。$passed_columns 仅包含与 $_POST['cols'] 中的键匹配的列名数组

我认为这个问题与价值观的绑定方式有关。如果我回显 $SQL 变量,则输出是有效的 SQL(带有我正在测试的值)。

但奇怪的是,如果我手动将 $SQL 设置为它只是输出的有效 SQL(“UPDATE users SET role = :role WHERE user_id IN (100)”),脚本就可以工作。

4

1 回答 1

3

反馈:

  • 使用"string" . $var变得非常难以理解。PHP 可以直接在字符串中嵌入变量:"string $var"如果你需要做数组表达式,你可以使用像"string {$arr['key']}".

  • 我建议用反引号分隔列名。

  • 从设置列表中删除最后一个逗号很笨拙。最好将集合列表构建为数组并使用逗号内爆。

  • 您的 IN 列表容易受到 SQL 注入的攻击。使用 (int) 映射 user_id 值以删除可能的恶意内容。如果 user_id 值不是整数,则使用查询参数(但不要?在单个语句中将位置参数与命名参数混合——它会混淆 PDO)。

  • bind_param() 是不必要的。只需将参数值传递给execute()。在现代版本的 PHP 中,键值中的前导冒号是不必要的,这使得直接从键/值数组传递参数变得更简单。

  • 从您的示例中不清楚 $passed_columns 是从用户输入中获取的,还是在您的应用程序中硬编码的。小心以这种方式引入 SQL 注入。我假设 $passed_columns 仅包含您控制的值。

  • prepare()false在错误时返回,因此您应该始终检查它的返回值并适当地响应错误。

  • print_r()实际上打印到输出,而不是返回字符串,除非您传递可选的第二个参数 true。

  • 大多数 PHP 开发人员对此感到惊讶,但双引号字符串实际上比单引号字符串要快一些。无论如何差异都非常小,但是双引号字符串允许您将变量直接放入字符串中,为什么不呢?

这是我编写代码的方式:

$set_terms = array();
foreach ($passed_columns as $c)
{
    $set_terms[] = "`$c` = :$c";
}
$set_clause = implode(",", $set_terms);

$user_id_list = implode(",", array_map(function($id) { return (int) $id; },
  $_POST["user_id"]);

$SQL = "UPDATE users SET {$set_clause} WHERE user_id IN ({$user_id_list})";

if (!($stmt = $dbh->prepare($SQL)) {
    die(print_r($dbh->errorInfo(), true));
}

if (!$stmt->execute($_POST["cols"])) {
    die(print_r($stmt->errorInfo(), true));
}

PS:如果遇到错误,仅使用 die() 可能不是最好的做法。专业的 Web 界面会为开发人员记录错误,然后向用户呈现更好的屏幕。

于 2013-05-17T20:16:40.517 回答