谢谢你的好问题。
事实上,您可以同时使用这两种方法。
大多数人确实将准备好的语句的概念与主要 DBMS 提供的 [非常有限的] 实现混淆了。虽然后者可能会受到质疑,但前者确实是唯一的方法。
看看这个例子。让我们使用safeMysql运行您的查询:
$sql = "UPDATE SET column1 = ?i, column2 = ?s WHERE column3 = ?s AND column4 = ?s";
$db->query($sql, $string, $blob, $int, $double);
它像您的代码一样执行字符串格式化,但在内部执行。为什么?因为它是如何在内部实现的(通过本机准备好的语句或手动格式化)并不重要,但是使用准备好的语句来组装您的查询是必不可少的。
大多数人都忽略了关于准备好的陈述的一些要点:
它使格式化始终完整(尽管在您的示例中您正在做正确的事情并进行了完整的格式化,但仍然很容易陷入不完整的格式化,如下所示:
$colname = "`$colname`";
您的格式始终是正确的。它不会让你做类似的事情
$colname = "`" .mysql_real_escape_string($colname) ."`";
这将是无用的并导致您注射
它将强制格式化。通过以您当前的方式组装查询,很容易忽略一两个变量。
- 它将尽可能接近查询执行进行正确的格式化。这是非常重要的一点,因为
- 它不会破坏您的源变量(如果查询失败并且您想回显它怎么办?)
- 它不会让您将格式化代码从查询中移开,这可能会导致致命的后果。
- 毕竟,它会让您的代码大大缩短,而无需所有无聊的手动格式化!
这就是准备好的语句的真正好处,它保证了安全性,从而使它们变得如此受欢迎。虽然服务器端准备的东西虽然很聪明,但只是一个特定的实现。
此外,以准备好的语句为指导,可以为可能添加到查询中的所有内容(例如标识符或数组)创建一个占位符,使其真正安全和方便使用。
牢记所有事情,必须在他们的数据库访问库中实现准备好的语句的想法,以使代码安全且简短。
只是来自 safeMysql 的几个例子:
$name = $db->getOne('SELECT name FROM table WHERE id = ?i',$_GET['id']);
$data = $db->getInd('id','SELECT * FROM ?n WHERE id IN ?a','table', array(1,2));
$data = $db->getAll("SELECT * FROM ?n WHERE mod=?s LIMIT ?i",$table,$mod,$limit);
$ids = $db->getCol("SELECT id FROM tags WHERE tagname = ?s",$tag);
$data = $db->getAll("SELECT * FROM table WHERE category IN (?a)",$ids);
$data = array('offers_in' => $in, 'offers_out' => $out);
$sql = "INSERT INTO stats SET pid=?i,dt=CURDATE(),?u ON DUPLICATE KEY UPDATE ?u";
$db->query($sql,$pid,$data,$data);
只需对传统的 mysql(i) 进行相同的尝试,然后查看它需要的代码量。
您可能会注意到,对于可用的准备好的语句,您必须用类型标记它们,因为类型不仅仅是简单的字符串,而且它是告诉驱动程序如何格式化变量的唯一可靠方法。