您是否可以使用PDO向预先准备好的语句发送超出需要的参数而没有不良副作用?
这可能看起来像一个奇怪的问题,但我问,因为我连续有4个查询,它们都使用相似和不同的参数。查询的相关部分:
1st(选择,与其他人不同):
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);
如果可以的话,我应该吗?这会减慢或导致我的数据库或脚本出现安全漏洞吗?
如果我能让这个问题更清楚一点,请问。
谢谢!
答案 0 :(得分:3)
我知道这已经得到了解答,它只是询问是否你可以发送额外的参数,但我认为人们可能会提出这个问题,并想知道如何解决这个限制。这是我使用的解决方案:
$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))
}
我还没有解决它。
该函数会翻转您的键名数组,因此您有一个没有值的数组,但是右键。然后交叉过滤第一个数组,这样你只有两个数组中的键(在这种情况下,只有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']));
答案 1 :(得分:3)
自从这个问题首次提出以来,documentation可能已经更新了,但现在已经非常明确地说明了这一点#34; 否"
您无法绑定超过指定值的值;如果input_parameters中存在的键多于PDO :: prepare()中指定的SQL,则语句将失败并发出错误。
这些answers在过滤掉额外参数时非常有用。
答案 2 :(得分:2)
我有机会测试我的问题,答案是您不能发送比查询使用的更多参数。您收到以下错误:
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。这必须在这里发生,因为我绑定了太多参数。
答案 3 :(得分:0)
使用一次执行执行不同类型的多个查询会导致问题。您可以使用一个执行运行多个选择或多个更新。对于这种情况,要创建不同的预准备语句对象并相应地传递参数。
// 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);