如何将参数绑定到未准备的查询?

时间:2012-08-14 18:59:20

标签: php pdo mysqli

我正在制作一个小型的Web应用程序,它将定期接收用户输入的数据。在研究如何确保数据输入首先被清理时,为此它似乎是准备好的语句是要走的路。

我发现this SO question然而,因为我的应用程序(至少据我所知)每页请求不会执行多个查询,所以我真正需要的只是绑定值对查询中的参数。

我一直在浏览PDO和mysqli上的PHP手册,但我找不到任何值与普通查询绑定的示例。我发现的所有示例在绑定之前的某处都有$stmt->prepare

该语句是否“准备好”由数据库支持决定的内容,而prepare语句将始终在代码中?或者有没有办法将参数直接绑定到$dbh->query(...)

解释为什么我要查看是否有可能不使用prepare,是由于我之前在帖子中链接的SO问题的声明:

  

何时不使用准备好的陈述?当你只是在数据库连接消失之前运行语句一次。

     

何时不使用绑定查询参数(这实际上是大多数人使用预处理语句获得的)?

和这个

  

就个人而言,我不会打扰。伪准备语句可能对他们可能提供的安全变量引用有用。

3 个答案:

答案 0 :(得分:5)

  

如何将参数绑定到未准备好的查询?

你没有。在将这些问号视为参数值的插入点之前,需要先解析带有参数的SQL字符串(即特定位置的问号)(即准备好)。

因此,您需要先拨打prepare(),然后才能拨打bind()


参数化语句是一个包含SQL和占位符标记的字符串(例如问号,但不同的数据库使用不同的占位符):

$sql = "SELECT user_id FROM user WHERE user_name = ?"

现在假设您要在此位置插入

$_POST["username"]
广泛地说,

准备声明会给问号带来特殊含义“可以插入值”。换句话说,它会从占位符创建参数

$stmt->prepare($sql)

将值绑定到参数会将参数设置为特定值。

$stmt->bind_param("s", $_POST["username"])

现在可以在没有SQL字符串的情况下执行查询,并且用户提供的值实际上彼此接触。 这是重要的一点: SQL和参数值分别发送到服务器。他们从不相互接触。

$stmt->execute();

优点是:

  • 您可以将新值绑定到参数并再次执行查询,而无需重复所有操作(在循环中很有用)。
  • 无论$_POST["username"]包含什么值,都不可能进行SQL注入。

答案 1 :(得分:4)

你没有。原因如下:

如果使用$dbh->query(...) 你可以使用插入sql字符串的参数调用sql。通过使用像

这样的查询
$dbh->query("INS INTO MY_TABLE_OF_NAMES ('$name');"); 
大约10年前,这就是大多数sql的完成方式。这是使用RDMS实现的SQL接口alreaady调用数据库的最直接方式,无需特殊的低级接口。但人们发现这很危险,因为有一种叫做sql注入的东西。

http://en.wikipedia.org/wiki/Sql_injection

最简单,最常见的例子是这样的。假设您的网页中有一个sql调用将运行:

 INS INTO MY_TABLE_OF_NAMES VALUE ('$name');

但是有人会来到您的网站并输入名称bob'); DROP TABLE MY_TABLE_OF_NAMES;

突然你的插值sql语句变成了

INS INTO MY_TABLE_OF_NAMES VALUE ('bob'); DROP TABLE MY_TABLE_OF_NAMES; );

随后会将bob插入您的数据库,删除所有名称,并在网站运行时为跟踪);抛出错误。

因此,发明了准备好的陈述。它不是直接将字符串插入字符串,而是使用?字符表示动态值,而bind函数用于安全地插入字符串。这样,仁慈的输入永远不会被数据库引擎解释为SQL代码,并且您的网站不能被欺骗去做它不想做的事情。 prepare命令需要一个sql字符串,需要一些sql并半编译成一个较低级别的数据库langauge,只要使用?,就会在动态字符串中打开空格。然后绑定其中一个开放空间并用一段数据填充它,编码为转义为ascii,这样它就不会被误解为SQL代码。一旦填充了所有这些?,就可以将sql发送到要运行的RDMS。

因此,要回答您的问题,您永远不会将参数绑定到简单查询。如果您想在简单查询中使用动态变量,您只需将它们插入到SQL字符串中即可。但这很危险。 Prepared语句允许您预编译一个sql语句,然后安全地将动态参数绑定到它,以创建安全的动态SQL。绑定到sql纯粹是预准备语句的构造。

答案 2 :(得分:0)

要使用绑定参数,必须使用预准备语句。这就是目前在pdo和mysqli中实现的方式。我不确定某些数据库产品是否支持某种类型的通信协议,其中参数化sql(使用占位符的sql文本)与参数值一起发送,而不必先进行显式的prepare调用,但是pdo和mysqli不会暴露此功能如果可用。它肯定是网络应用程序的一个受欢迎的功能。

使用pdo,是的,在调用$dbh->prepare($sql)时sql语句是否真正准备好取决于数据库支持。当数据库不支持时,pdo将模拟预准备语句,或者如果配置为这样做,它总是可以模拟它们。事实上,默认情况下,pdo模拟mysql驱动程序的预处理语句,并且默认情况下已经很长时间。它通过创建动态sql来模拟它们,引用值,就像你一样。在这种情况下,当您调用$stmt->execute()时,sql(最终值嵌入到文本中)将被发送到数据库。是的,在某些情况下可以使用sql注入。