2013-05-17 70 views
1

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

您的SQL语法错误;检查coresponds 你的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,它只是输出(“更新用户设置的角色=:角色其中USER_ID IN(100)”),剧本的作品。

+0

这是一个MySQL错误,在绑定之前。 'echo $ SQL'来查看构造语句的样子。它会有一些奇怪的东西导致这个模棱两可的错误信息。 –

+0

您是否试过回应您的查询?它是什么样子的? – andrewsi

+0

回显的查询是有效的SQL(在构建之后),如果我将查询复制到Workbench /手动执行它,它将起作用。它看起来像这样:“更新用户SET角色=:角色WHERE user_id IN(100)” – syl

回答

3

反馈:

  • 使用"string" . $var变得非常不可读迅速。 PHP可以直接在字符串中嵌入变量:"string $var",如果您需要执行数组表达式,则可以使用大括号"string {$arr['key']}"

  • 我建议划定与后台蜱列名。

  • 搓背最后一个逗号落定名单是笨拙的。最好使用逗号将数组设置为数组并使用implode。

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

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

  • 这不是从你的例子清楚,如果$ passed_columns从用户输入取东西,或者在您的应用程序,如果是硬编码。注意以这种方式引入SQL注入。我假设$ passed_columns只包含您控制的值。

  • prepare()返回false出错,所以您应该始终检查其返回值并适当地响应错误。

  • print_r()实际打印输出,而不是返回一个字符串,除非你通过可选的第二个参数真。

  • 这是一个惊喜,大多数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:刚开始使用模具(),如果你得到一个错误,未必是最好的事情。专业的网络界面会为开发人员记录错误,然后向用户展示更好的屏幕。

+0

这有效,比我写的方式更好。我只是希望我知道我为什么不行。 – syl

+0

是的,这是一个谜。您可以启用[通用查询日志](http://dev.mysql.com/doc/refman/5.6/en/query-log.html),它记录失败的查询,并查看实际到达MySQL服务器的SQL当它认为有错误时。但是有时我会遇到神秘失败的代码,当我重写它时,过程中会有某些东西被修复。很高兴知道原来的问题是什么,但除此之外取胜并继续前进。 :-) –