8

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

但是,我发现了这个 SO question,并且由于我的应用程序(至少据我所知)不会对每个页面请求进行一个以上的查询,看来我真正需要的只是将值绑定到参数查询。

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

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

为了解释为什么我想看看它是否可以不使用准备,是由于我在帖子前面链接的 SO question 中的这个声明:

什么时候不使用准备好的语句?当您在数据库连接消失之前只运行一次语句时。

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

和这个

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

4

3 回答 3

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();

优点是:

  • 您可以将新值绑定到参数并再次执行查询,而无需重复所有操作(在循环中很有用)。
  • SQL 注入是不可能的,无论$_POST["username"]包含什么值。
于 2012-08-14T19:03:20.643 回答
4

You Don't. Here's why:

If using $dbh->query(...) you can just call sql with the parameters interpolated into the sql string. By using a query like

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

10 or so years ago, this is how most sql was done. This is the most straight forward way of invoking the database, using the SQL interface alreaady implemented by the RDMS, without the need for a special lower level interface. But people discovered that this was dangerous because of something called sql injection.

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

The simplest and most common example goes something like this. Suppose you had a sql call in your web page that would run:

 INS INTO MY_TABLE_OF_NAMES VALUE ('$name');

But then someone would come to your site and enter there name as bob'); DROP TABLE MY_TABLE_OF_NAMES;

suddenly your interpolated sql statement becomes

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

which would subsequently insert bob into your database, delete all of your names, and throw an error for the trailing ); when your website ran it.

So, prepared statements were invented. Instead of interpolating string directly into your strings it will use ? chars to denote dynamic values, and a bind function is used to insert the string safely. This way manevolent input will never be interpreted as SQL code by your database engine and you site cant be tricked into doing things it doesnt want to do. The prepare command takes a sql string takes a bit of sql and semi compiles into a lower level database langauge leaving spaces open of dynamic strings wherever a ? is used. Bind then takes one of those open spaces and fills it with a piece of data, encoded to escaped ascii, so that it cannot be misinterpreted as SQL code. Once all of those ?s are filled, the sql is ready to be sent to the RDMS to be run.

So to answer your question, you will never bind a parameter to a simple query. If you want dynamic varables in a simple query you will just interpolate them into the SQL string. But this is dangerous. Prepared statements allow you to precompile a sql statement then safely bind dynamic parameters to it to create safe dynamic SQL. Binding to sql is purely a construct of prepared statements.

于 2012-08-14T19:33:03.050 回答
0

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

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

于 2012-08-14T20:13:23.350 回答