简体   繁体   English

PDO绑定问题

[英]PDO Binding Issue

I'm getting the following SQL error for the given code. 我给出了给定代码的以下SQL错误。

You have an error in your SQL syntax; 您的SQL语法有错误; check the manual that coresponds to your MySQL server version for the right syntax to use near '' at line 1 查看与您的MySQL服务器版本相对应的手册,以便在第1行的''附近使用正确的语法

The code: 编码:

$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'] contains a key value array of (column_name => new column value). $ _POST ['cols']包含一个键值数组(column_name => new column value)。 $passed_columns just contains an array of column names that match the keys in $_POST['cols'] $ passed_columns只包含一个与$ _POST ['cols']中的键匹配的列名数组

I believe the issue has to do with the way the values are bound. 我认为这个问题与价值观的约束方式有关。 If I echo the $SQL variable, the output is valid SQL(with the values I'm testing). 如果我回显$ SQL变量,则输出是有效的SQL(带有我正在测试的值)。

But oddly enough, if I manually set $SQL to the valid SQL it just output ("UPDATE users SET role = :role WHERE user_id IN (100)"), the script works. 但奇怪的是,如果我手动将$ SQL设置为有效的SQL,它只输出(“UPDATE users SET role =:role WHERE user_id IN(100)”),脚本可以工作。

Feedback: 反馈:

  • Using "string" . $var 使用"string" . $var "string" . $var gets really unreadable quickly. "string" . $var很快就变得难以理解了。 PHP can embed variables directly in strings: "string $var" and if you need to do array expressions you can use curly braces like "string {$arr['key']}" . PHP可以直接在字符串中嵌入变量: "string $var"如果你需要做数组表达式,你可以使用大括号,如"string {$arr['key']}"

  • I recommend to delimit the column names with back-ticks. 我建议使用反向标记来分隔列名称。

  • Chopping the last comma off the set-list is clumsy. 从列表中删除最后一个逗号是笨拙的。 Better to build the set-list as an array and implode using comma. 最好将set-list构建为数组并使用逗号进行内爆。

  • Your IN list is vulnerable to SQL injection. 您的IN列表容易受到SQL注入攻击。 Map the user_id values with (int) to remove possible malicious content. 使用(int)映射user_id值以删除可能的恶意内容。 If the user_id values aren't integers, then use query parameters (but don't mix ? positional parameters with named parameters in a single statement -- it confuses PDO). 如果USER_ID值不是整数,然后使用查询参数(但不要混用?使用命名参数的位置参数在单个语句-它混淆了PDO)。

  • bind_param() is unnecessary. bind_param()是不必要的。 Just pass the parameter values to execute(). 只需将参数值传递给execute()即可。 In modern versions of PHP, the leading colon in key values is unnecessary, which makes it simpler to pass the parameters directly from a key/value array. 在现代版本的PHP中,键值中的前导冒号是不必要的,这使得直接从键/值数组传递参数变得更加简单。

  • It's not clear from your example if $passed_columns is something taken from user input, or if it's hard-coded in your app. 从您的示例中不清楚$ passed_columns是从用户输入中获取的内容,还是在应用程序中硬编码的内容。 Be careful of introducing SQL injection this way. 小心以这种方式引入SQL注入。 I'll assume $passed_columns contains only values you control. 我假设$ passed_columns只包含你控制的值。

  • prepare() returns false on error, so you should always check its return value and respond to the error appropriately. prepare()在出错时返回false ,因此您应该始终检查其返回值并适当地响应错误。

  • print_r() actually prints to output, instead of returning a string, unless you pass the optional second argument true. print_r()实际打印到输出,而不是返回一个字符串,除非你传递可选的第二个参数为true。

  • It's a surprise to most PHP developers, but double-quoted strings are actually slightly faster than single-quoted strings. 这对大多数PHP开发人员来说都是一个惊喜,但双引号字符串实际上比单引号字符串略快。 The difference is very small regardless, but double-quoted strings allow you to put variables directly in the string, so why not? 不管是差异都很小,但是双引号字符串允许你将变量直接放在字符串中,为什么不呢?

Here's how I would write the code: 以下是我编写代码的方法:

$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: Just using die() if you get an error might not be the best thing to do. PS:如果你收到错误,只使用die()可能不是最好的事情。 A professional web interface would log the error for developers, and then present a nicer screen to the user. 专业的Web界面会为开发人员记录错误,然后为用户提供更好的屏幕。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM