Php 有人能清楚地解释为什么mysqli_prepare()/bind_param()比real_escape_string()更好吗?
好吧,我还是不太明白。我一直在读到,为了正确地避开MySQL查询,您需要使用Php 有人能清楚地解释为什么mysqli_prepare()/bind_param()比real_escape_string()更好吗?,php,mysql,mysqli,prepared-statement,mysql-real-escape-string,Php,Mysql,Mysqli,Prepared Statement,Mysql Real Escape String,好吧,我还是不太明白。我一直在读到,为了正确地避开MySQL查询,您需要使用mysqli_prepare()和mysqli_bind_param() 我试着使用这个设置,坦率地说,它有点笨重。当我不需要再次引用变量时,我被困在通过引用传递变量的过程中,而完成同样的任务需要更多的代码行 我想我只是不明白这两者之间的区别: <?php $sql = new \MySQLi(...); $result = $sql->query(' UPDATE `table` SET
mysqli_prepare()
和mysqli_bind_param()
我试着使用这个设置,坦率地说,它有点笨重。当我不需要再次引用变量时,我被困在通过引用传递变量的过程中,而完成同样的任务需要更多的代码行
我想我只是不明白这两者之间的区别:
<?php
$sql = new \MySQLi(...);
$result = $sql->query('
UPDATE `table`
SET
`field` = "'.$sql->real_escape_string($_REQUEST[$field]).'";
');
?>
我认为,与其说后一种方法本身更安全,不如说它鼓励逻辑分离。对于准备好的语句,SQL查询独立于我们使用的值。这意味着,例如,当我们返回并更改查询时,我们不必将一组不同的值连接到一个字符串,并且可能会忘记转义输入。使代码更易于维护 我发现有两个主要好处写得很好:
因此会产生编译和优化语句的开销
只执行一次,尽管语句执行多次。不
所有优化都可以在准备好的语句时执行
它的编制有两个原因:最佳计划可能取决于
参数的具体值,最佳方案可能会随着
表和索引会随着时间的推移而变化
准备好的语句能够抵抗SQL注入,因为
参数值,稍后使用不同的
协议,不需要正确转义。如果原始声明
模板不是从外部输入派生的,SQL注入无法
发生
另一方面,如果查询只执行一次,则服务器端准备的语句可能会因为到服务器的额外往返而变慢。实现限制也可能导致性能下降:某些版本的MySQL没有缓存准备好的查询的结果,某些DBMS(如PostgreSQL)在执行过程中没有执行额外的查询优化
我想从PHP5.4.0开始添加它。您应该使用您正在阅读的内容,您需要使用mysqli_prepare()
和mysqli_bind_param()
函数来“正确转义您的MySQL查询”是错误的
确实,如果使用mysqli\u prepare()
和mysqli\u bind\u param()
,则不需要(也不应该)“转义”作为绑定参数提供的值。所以,从这个意义上说,你所读的东西是有道理的
只有当SQL文本(查询的实际文本)中包含不安全变量时,您才需要“正确地转义”变量,通常是通过将变量包装在mysqli\u real\u escape\u string()函数调用中
(我们注意到,可以使用准备好的语句,并且仍然在SQL文本中包含未转义的变量,而不是将变量值作为bind_参数传递。这在某种程度上违背了使用准备好的语句的目的,但问题是,无论哪种方式,您都可以编写易受攻击的代码
MySQL现在支持“服务器端”准备语句(如果在连接中启用了该选项),这是重复执行相同SQL文本的性能优化(在某些情况下)。(这在其他数据库中得到了长期的支持,比如Oracle,在Oracle中,使用准备好的语句是一种常见的模式,从永远以来都是如此。)
Q:他们是否实现了[prepared statements],以便人们在发送查询之前不会忘记转义值
A:基于不使用预处理语句时易受SQL注入攻击的代码示例的数量,尽管有关于mysql\u real\u escape\u string()
函数的文档,但您认为这肯定是充分的理由
我认为一个很大的好处是,当我们阅读代码时,我们可以将SQL语句视为单个字符串文字,而不是一堆变量的串联,带有引号、点和对mysql_real_escape_string的调用,这对于一个简单的查询来说并不太糟糕,但是对于一个更复杂的查询来说,这太麻烦了de>?
占位符使SQL语句更易于理解,…没错,我需要查看其他代码行,以找出填充在那里的值。(我认为Oracle样式命名的parameters:fee,:fi,:fo,:fum
比位置符号?,,,,,,,,,,,,
更可取。)但拥有静态SQL文本才是真正的好处
Q:还是速度更快
正如我前面提到的,使用服务器端准备的语句在性能方面可能是一种优势。它并不总是更快,但对于重复执行同一语句,唯一的区别是文字值(如重复插入),它可以提供性能提升
Q:或者当我打算重复使用同一个查询时(因为mysqli\u stmt可以重用),我应该使用此方法,而在其他情况下使用传统方法吗
这取决于您。我更喜欢使用静态SQL文本。但这实际上来自于使用Oracle的悠久历史,并且使用MySQL的相同模式自然适合(尽管来自使用DBI接口的Perl,以及使用JDBC和MyBATIS的Java,或其他ORM(Hibernate、Glassfish JPA等)
遵循相同的模式在PHP中感觉很自然;mysqli_uu和PDO的引入是对神秘(和滥用)mysql_uu接口的一种令人欢迎的缓解
好的代码可以按照这两种模式编写。但我要求您提前考虑更复杂的SQL语句,以及是否选择使用mysqli\u real\u escape\u string()
<?php
$sql = new \MySQLi(...);
$stmt = $sql->prepare('
UPDATE `table`
SET
`field` = ?;
');
$value = $_REQUEST[$field];
$stmt->bind_param('s', $value);
$stmt->execute();
$result = $stmt->get_result();
unset($value);
?>