假设我要执行这样的预备声明:
$qry->prepare('UPDATE table_name SET column1 = ? string_column = ? WHERE column3 = ? AND column4 = ?');
$qry->bind_param('sbid', $string, $blob, $int, $double);
$int = 'non int value'; /* gives 0 in the database */
$blob = 'some string';
$string = 'another string';
$double = $double;
$qry->execute();
$qry->close();
我们只想说我只想执行一次查询,我只是在安全名称中使用了预处理语句。从我一直在阅读的内容来看,只使用一次准备好的查询会产生更多的开销,这相当于降低了安全性方面的性能。话虽这么说 - 像这样一次做同样的查询会有什么性能/安全性差异。
$int = (int) $int;
$blob = "'" .mysql_real_escape_string($blob) ."'";
$string = "'" .mysql_real_escape_string($blob) ."'";
$double = (double) $double;
$db->query("UPDATE SET column1 = $int, column2 = $blob WHERE column3 = $string AND column4 = $double ");
PS。我对Prepared语句如何改进性能以及单个查询的安全性和速度差异感兴趣。
答案 0 :(得分:3)
这有很多。一些随机点
或:
IN ( )
构造没有准备好的查询支持)经常被忽视:
我的最爱:
因此,风格的选择通常必须根据具体情况进行。我们采用了在标准化库中封装所有数据库访问包括参数管理的方式,简单地require()
编辑,因此您可以直接替换准备好的查询,转义或其他任何内容想要和你的RDBMS支持。
答案 1 :(得分:3)
谢谢你提出这个好问题。
事实上,您可以一次使用两种方法。
大多数人确实将准备好的声明的想法与主要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),然后查看它带来的代码量。
你可能会注意到,使用可用的预处理语句,你必须用类型标记它们,因为有更多的类型而不仅仅是简单的字符串,这是告诉驱动程序如何格式化你的唯一可靠方式变量
答案 2 :(得分:1)
我认为从安全角度来看它们同样安全,但使用prepare
不仅可以使您的SQL安全,还可以使您感到安全。您不能相信自己手动转义并始终转换为正确的类型。如果您编写10,000个不同的SQL查询,您将倾向于忘记逃避一两个。
总而言之,prepare
是一种更好的反对SQL注入的习惯。将PHP变量直接放到SQL查询中会让我在晚上睡觉时感到不安。