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


How do you bind parameters to a query that isn't prepared?

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

但是,我

发现了这个问题,并且由于我的应用程序(至少据我所知)不会在每个页面请求中执行多个查询,因此似乎我真正需要的只是将值绑定到查询中的参数。

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

语句

是否"准备"是由数据库的支持决定的,并且准备语句将始终在代码中?或者有没有办法将参数直接绑定到$dbh->query(...)中?

为了解释为什么我正在寻找是否可以不使用 prepare,是由于我在帖子前面链接的 SO 问题的以下陈述:

何时不使用预准备语句?当您只要在数据库连接消失之前运行一次语句时。

何时不使用绑定查询参数(这实际上是大多数人使用预准备语句来获取的)?

而这个

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

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

你没有。首先需要解析(即准备)带有参数(即特定位置的问号)的 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();

优点是:

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

你没有。原因如下:

如果使用$dbh->query(...)您可以使用插入到 SQL 字符串中的参数来调用 SQL。通过使用类似

$dbh->query("INS INTO MY_TABLE_OF_NAMES ('$name');"); 

大约 10 年前,大多数 SQL 都是这样完成的。这是使用 RDMS 已经实现的 SQL 接口调用数据库的最直接方法,无需特殊的低级接口。但是人们发现这是危险的,因为一种叫做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 插入您的数据库,删除您的所有名称,并在您的网站运行时为尾随);抛出错误。

因此,发明了准备好的陈述。它不是将字符串直接插入到 SQL 中,而是使用?字符来表示动态值,并使用 bind 函数安全地插入字符串。这样,恶意输入永远不会被数据库引擎解释为 SQL 代码,并且您的网站不会被诱骗做它不想做的事情。prepare 命令采用 SQL 字符串,需要一点 SQL,并将其半编译为较低级别的数据库语言,在使用 ? 的地方留出动态字符串的空间。然后,Bind 用一段数据填充其中一个开放空间,这些数据编码为转义的 ASCII,这样它就不会被误解为 SQL 代码。一旦所有这些?都填满了,SQL就可以发送到RDMS运行了。

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

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

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