【问题标题】:PDO: Passing extra parameters to a prepared statment than neededPDO:将额外的参数传递给准备好的语句而不是需要
【发布时间】:2012-11-21 11:00:30
【问题描述】:

您能否向使用 PDO 的预准备语句发送比需要更多的参数而不会产生不良副作用?

这似乎是一个奇怪的问题,但我问是因为我连续有 4 个查询,它们都使用相似和不同的参数。查询的相关部分:

第一个(选择,与其他人不同的表):
WHERE threadID = :tid

第二(选择):
WHERE user_ID = :u_ID AND thread_ID = :tid

第 3 次(如果第 2 次成功则更新):
SET time = :current_time WHERE user_ID = :u_ID AND thread_ID = :tid

第 4 次(如果第 2 次失败则插入):
VALUES (:u_ID, :tid, :current_time)

我可以在开头声明一个包含三个参数的数组并将其用于所有 4 个查询吗?

为了解决任何混淆,查询将分别执行。它是参数变量被重用,因此这意味着某些查询将接收他们不需要的参数。所以像:

$parameters = array(':tid' => $tid, ':u_ID' => $u_ID, ':current_time' => $time);

$1st = $db->prepare($query1);
$1st->execute($parameters);

$2nd = $db->prepare($query2);
$2nd->execute($parameters);

$3rd = $db->prepare($query3);
$3rd->execute($parameters);

$4th = $db->prepare($query4);
$4th->execute($parameters);

如果可以,我应该吗?这会减慢或导致我的数据库或脚本出现安全漏洞吗?

如果我可以让这个问题更清楚一点,请提问。

谢谢!

【问题讨论】:

标签: pdo prepared-statement


【解决方案1】:

也许documentation 自从第一次提出这个问题以来已经更新,但现在很清楚地表明“

您不能绑定比指定更多的值;如果 input_parameters 中存在的键多于 PDO::prepare() 中指定的 SQL 中的键,则语句将失败并发出错误。

这些answers 应该有助于过滤掉额外的参数。

【讨论】:

    【解决方案2】:

    我知道这已经得到解答,它只是询问是否您可以发送额外的参数,但我认为人们可能会遇到这个问题,并想知道如何绕过这个限制。这是我使用的解决方案:

    $parameters = array('tid' => $tid, 'u_ID' => $u_ID, 'current_time' => $time);
    
    $1st = $db->prepare($query1);
    $1st->execute(array_intersect_key($parameters, array_flip(array('tid'))));
    
    $2nd = $db->prepare($query2);
    $2nd->execute(array_intersect_key($parameters, array_flip(array('u_ID', 'tid'))));
    
    $3rd = $db->prepare($query3);
    $3rd->execute(array_intersect_key($parameters, array_flip(array('u_ID', 'tid', 'current_time'))));
    
    $4th = $db->prepare($query4);
    $4th->execute(array_intersect_key($parameters, array_flip(array('u_ID', 'tid', 'current_time'))));
    

    array_interset_key 和 array_flip 操作可以提取到它自己的函数中,比如:

    function filter_fields($params,$field_names) {
        return array_intersect_key($params, array_flip($field_names))
    }
    

    我只是还没开始。

    该函数翻转您的键名数组,因此您有一个没有值但有正确键的数组。然后 intersect 过滤第一个数组,这样您就只有两个数组中的键(在这种情况下,只有 array_flipped 数组中的键)。但是你得到了原始数组的值(不是空的)。因此,您创建一组参数,但指定实际发送到 PDO 的参数。

    因此,使用该功能,您可以:

    $parameters = array('tid' => $tid, 'u_ID' => $u_ID, 'current_time' => $time);
    
    $1st = $db->prepare($query1);
    $1st->execute(filter_fields($parameters, array('tid')));
    
    $2nd = $db->prepare($query2);
    $2nd->execute(filter_fields($parameters, array('u_ID', 'tid')));
    
    $3rd = $db->prepare($query3);
    $3rd->execute(filter_fields($parameters, array('u_ID', 'tid', 'current_time')));
    
    $4th = $db->prepare($query4);
    $4th->execute(filter_fields($parameters, array('u_ID', 'tid', 'current_time')));
    

    如果你有 PHP 5.4,你可以使用方括号数组语法,让它更酷:

    $parameters = array('tid' => $tid, 'u_ID' => $u_ID, 'current_time' => $time);
    
    $1st = $db->prepare($query1);
    $1st->execute(filter_fields($parameters, ['tid']));
    
    $2nd = $db->prepare($query2);
    $2nd->execute(filter_fields($parameters, ['u_ID', 'tid']));
    
    $3rd = $db->prepare($query3);
    $3rd->execute(filter_fields($parameters, ['u_ID', 'tid', 'current_time']));
    
    $4th = $db->prepare($query4);
    $4th->execute(filter_fields($parameters, ['u_ID', 'tid', 'current_time']));
    

    【讨论】:

      【解决方案3】:

      我有机会测试我的问题,答案是您不能发送比查询使用更多的参数。您收到以下错误:

      PDOException Object
      (
          [message:protected] => SQLSTATE[HY093]: Invalid parameter number: parameter was not defined
          [string:Exception:private] => 
          [code:protected] => HY093
          [file:protected] => C:\Destination\to\file.php
          [line:protected] => line number
          [trace:Exception:private] => Array
              (
                  [0] => Array
                      (
                          [file] => C:\Destination\to\file.php
                          [line] => line number
                          [function] => execute
                          [class] => PDOStatement
                          [type] => ->
                          [args] => Array
                              (
                                  [0] => Array
                                      (
                                          [:u_ID] => 1
                                          [:tid] => 1
                                          [:current_time] => 1353524522
                                      )
      
                              )
      
                      )
      
                  [1] => Array
                      (
                          [file] => C:\Destination\to\file.php
                          [line] => line number
                          [function] => function name
                          [class] => class name
                          [type] => ->
                          [args] => Array
                              (
                                  [0] => SELECT
                                                      column
                                                  FROM
                                                      table
                                                  WHERE
                                                      user_ID  = :u_ID AND
                                                      thread_ID = :tid
                                  [1] => Array
                                      (
                                          [:u_ID] => 1
                                          [:tid] => 1
                                          [:current_time] => 1353524522
                                      )
      
                              )
      
                      )
      
              )
      
          [previous:Exception:private] => 
          [errorInfo] => Array
              (
                  [0] => HY093
                  [1] => 0
              )
      
      )
      

      我不太了解 PDO,因此我的问题是,但我认为因为 :current_time 已发送但未使用,并且错误消息是“无效参数编号:未定义参数”,所以您无法发送额外参数没有使用。

      另外会生成错误代码 HY093。现在我似乎在任何地方都找不到任何解释 PDO 代码的文档,但是我遇到了以下两个专门关于 HY093 的链接:
      What is PDO Error HY093
      SQLSTATE[HY093]

      似乎是你错误绑定参数时产生了HY093。这一定是这里发生的,因为我绑定了太多参数。

      【讨论】:

      • 这是一篇很老的帖子,但我会评论我自己对 PDO 的发现,尤其是参数。您不能重复使用相同的参数名称两次。在上面的:current_time 将被使用两次(一次在数组[0] 中,再次在数组[1] 中)。它们中的每一个都必须有一个唯一的名称,例如。 :current_time 在数组 [0] 中,例如 :current_time2 在数组 [1] 中。 :u_ID:tid 也是如此。
      • 在这里恢复一个旧线程,只是想注意如果 EMULATE_PREPARES 关闭,如果参数与参数计数不匹配,execute() 将返回 false 而不会引发异常(截至 PHP 5.2+)
      【解决方案4】:

      一次执行不同类型的多个查询会导致问题。您可以通过一次执行运行多个选择或多个更新。对于这种情况,创建不同的准备好的语句对象并相应地传递参数。

      // for WHERE threadID = :tid
      $st1 = $db->prepare($sql);
      $st1->bindParam(':tid', $tid);
      $st1->execute();
      or
      $st1->execute(array(':tid'=>$tid);
      
      // for WHERE user_ID = :u_ID AND thread_ID = :tid
      $st2 = $db->prepare($sql);
      $st2->bindParam(':u_ID', $u_ID);
      $st2->bindParam(':tid', $tid);
      $st2->execute();
      or
      $st2->execute(array(':tid'=>$tid, ':u_ID' => $u_ID);
      
      // for SET time = :current_time WHERE user_ID = :u_ID AND thread_ID = :tid
      $st3 = $db->prepare($sql);
      $st3->bindParam(':u_ID', $u_ID);
      $st3->bindParam(':tid', $tid);
      $st3->bindParam(':current_time', $current_time);
      $st3->execute();
      or
      $st3->execute(array(':tid'=>$tid, ':u_ID' => $u_ID, ':current_time' => $current_time);
      
      // for VALUES (:u_ID, :tid, :current_time)
      $st4 = $db->prepare($sql);
      $st4->bindParam(':u_ID', $u_ID);
      $st4->bindParam(':tid', $tid);
      $st4->bindParam(':current_time', $current_time);
      $st4->execute();
      or
      $st4->execute(array(':tid'=>$tid, ':u_ID' => $u_ID, ':current_time' => $current_time);
      

      【讨论】:

      • 我并不是要使用相同的执行。我已经修改了我的问题,希望能更好地解释它。我的意思是单独执行,但每次都使用相同的参数变量。因此,一些查询会收到比他们需要的更多的参数。
      猜你喜欢
      • 2020-09-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-07-20
      • 2014-11-16
      • 2011-08-02
      • 2011-05-14
      相关资源
      最近更新 更多