【问题标题】:PDO PHP bindValue doesn't workPDO PHP bindValue 不起作用
【发布时间】:2013-01-03 04:57:53
【问题描述】:

我知道这个问题已经被问了 1000 次了,但出于某种原因,我继续用头撞墙..

这行得通:

$sql = 'SELECT a.eventCode, a.eventTime, a.teamCode, a.playerCode, b.lastName, b.firstName, b.number, a.xCoord, a.yCoord, a.id ';
$sql = $sql . 'FROM events a, players b ';
$sql = $sql . 'WHERE a.regGUID in ( ' . $regGUID . ' ) and ';
$sql = $sql . 'a.playerCode=b.playerCode and a.gameCode = "' . $game . '" order by a.eventTime desc, a.actionCode asc'; 
$stmt = $db->prepare($sql);
$results = $stmt->execute();

这不是:

$sql = 'SELECT a.eventCode, a.eventTime, a.teamCode, a.playerCode, b.lastName, b.firstName, b.number, a.xCoord, a.yCoord, a.id ';
$sql = $sql . 'FROM events a, players b ';
$sql = $sql . 'WHERE a.regGUID in ( :regGUID ) and ';
$sql = $sql . 'a.playerCode=b.playerCode and a.gameCode = :game order by a.eventTime desc, a.actionCode asc'; 
$stmt = $db->prepare($sql);
$stmt->bindValue(':regGUID', $regGUID, PDO::PARAM_STR);
$stmt->bindValue(':game', $game, PDO::PARAM_STR);
$results = $stmt->execute();

我错过了什么?谢谢

【问题讨论】:

  • regGUID 真的是字符串吗?
  • 通过更改默认的静默错误模式,确保您可以查看 PDO 错误:$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING)
  • 将 PDO 设置为throw exceptions on errors,看看它是否抛出任何东西。 $regGUID 是单个 GUID,还是逗号分隔的 GUID 列表?如果是后者,则必须将每个 GUID 绑定为单独的变量。
  • 检查查询错误的建议很好,但在这种情况下,此查询不会引发错误——它只会无法匹配任何行,因为数据库中没有单独的 GUID 字符串是相等的到一个以逗号分隔的 GUID 列表的字符串。

标签: php mysql pdo bindvalue


【解决方案1】:

这确实被问了 1000 次。

准备好的语句只能接受标量值,不能接受 SQL 查询的任意部分。

您必须使用尽可能多的占位符形成 IN() 语句,您必须放入尽可能多的项目,然后将它们一一绑定。

为了简化这项任务,可以使用一些辅助功能。

比如说,使用SafeMysql library,这段代码可以写成

$sql  = 'SELECT * FROM events a, players b WHERE regGUID in (?a) and';
$sql .= ' a.playerCode=b.playerCode and a.gameCode = ?s';
$sql .= ' order by a.eventTime desc, a.actionCode asc'; 
$results = $db->getAll($sql,$regGUID,$game);

注意$regGUID 应该是一个数组,而不是字符串,$results 已经包含了所有请求的数据,无需进一步处理。

【讨论】:

    【解决方案2】:

    $regGUID的内容是什么?由于您使用的是 in 子句,我怀疑是逗号分隔的列表。

    将变量绑定到参数与将字符串替换到查询中不同;这就像告诉 MySQL 如何使用您的实际 PHP 变量。因此,如果将'1,2,3' 之类的字符串绑定到查询参数,它会保留为一个字符串,并且不会被重新解释为数字列表。

    因此,如果 $regGUID 类似于 "'AAA1', 'BBB2'",您的第一个查询变为

    ... WHERE a.regGUID in ( 'AAA1', 'BBB2' ) ...
    

    但您的第二个查询更像

    ... WHERE a.regGUID in ( '\'AAA1\', \'BBB2\'' ) ...
    

    和说的一样

    ... WHERE a.regGUID = '\'AAA1\', \'BBB2\'' ...
    

    【讨论】:

      【解决方案3】:

      由于其他人有状态,您只能将单个标量值绑定到占位符。因此,这意味着您实际上需要为 IN 语句中的每个值添加一个占位符。我通常会执行以下操作。应该注意的是,虽然我从不使用bindValue,所以如果它有关于必须像 Mysqli 那样引用的东西的规则,那么可能需要修改以下内容:

      $regGUIDPlaceholders = array();
      
      // prepare the placeholders
      // assume regGUID is an array - if its a string then explode on whatever to make it an array
      foreach($regGUID as $k => $v) {
         $placeholder = ':regGUID' . $k;
         $regGUIDPlaceholders[$key] = $value;
      }
      
      // prepare the IN statememnt
      $in = sprintf('IN (%s)', implode(',', array_keys($regGUIDPlaceholders)));
      
      $sql = 'SELECT a.eventCode, a.eventTime, a.teamCode, a.playerCode, b.lastName, b.firstName, b.number, a.xCoord, a.yCoord, a.id ';
      $sql = $sql . 'FROM events a, players b ';
      
      // USE the IN statement dynamically prepared above
      $sql = $sql . 'WHERE a.regGUID '. $in . ' and ';
      
      $sql = $sql . 'a.playerCode=b.playerCode and a.gameCode = :game order by a.eventTime desc, a.actionCode asc'; 
      
      $stmt = $db->prepare($sql);
      
      // bind each GUID to its placeholder
      foreach($regGUIDPlaceholders as $placeholder => $value) {
         $stmt->bindValue($placeholder, $value, PDO::PARAM_STR);
      }
      
      $stmt->bindValue(':game', $game, PDO::PARAM_STR);
      $results = $stmt->execute();
      

      【讨论】:

        【解决方案4】:

        问题出在这里:

        $sql = $sql . 'WHERE a.regGUID in ( :regGUID ) and ';
        $stmt->bindValue(':regGUID', $regGUID, PDO::PARAM_STR);
        

        我假设 $regGUID 是逗号分隔的引号字符串列表。

        每个查询参数只接受一个标量值。不是列表值。

        所以你有两个选择:

        1. 继续插入 $regGUID 字符串,即使您将参数用于其他标量值。但是您仍然要小心避免 SQL 注入,因此您必须正确形成 $regGUID 字符串。您不能只对整个字符串调用 PDO::quote() ,这会使它成为包含 UUID 和逗号的单引号字符串。您必须确保每个 UUID 字符串都被单独转义和引用,然后将列表内爆在一起并将其插入到 IN 子句中。

          $regGUIDs = explode(',', $regGUID);
          $regGUIDs = array_map(function ($g) { return $db->quote($g); }, $regGUIDs);
          $regGUID = implode(',', $regGUIDs);
          $sql = $sql . 'WHERE a.regGUID in (' . $regGUID . ') and ';
          
        2. explode()将$regGUID放入一个数组中,并为数组中的每个元素添加一个查询参数。插入查询参数占位符的动态列表。

          $regGUIDs = explode(',', $regGUID);
          $params = array_fill(1, count($regGUIDs), '?');
          $sql = $sql . ' WHERE a.regGUID in ( ' . implode(',', $params) . ' ) and ';
          

        您可以在数组的循环中使用 bindValue(),但请记住,其他参数也应按位置绑定,而不是按名称绑定。当您尝试在同一个查询中混合两种不同样式的参数时,PDO 存在一些错误,导致它不满意。

        我只是将一组参数值传递给 PDOStatement::execute(),而不是使用 bindValue(),这要容易得多。

        $paramValues = $regGUIDs;
        $paramValues[] = $game;
        $results = $stmt->execute($paramValues);
        

        【讨论】:

        • 谢谢你.. 像魅力一样工作!内爆函数中的小错字更正,花了几分钟才意识到应该有一个,而不是一个。撞到墙上我的头疼得更轻了!
        • 谢谢,我在上面的回答中更正了,。很高兴为您提供帮助!
        猜你喜欢
        • 2011-02-11
        • 2016-01-28
        • 1970-01-01
        • 2015-06-10
        • 2014-01-26
        • 1970-01-01
        • 1970-01-01
        • 2017-01-18
        相关资源
        最近更新 更多