为什么PDO比mysql_real_escape_string更好地转义MySQL查询/查询string?

我被告知,我会更好地使用PDO进行MySQL转义,而不是mysql_real_escape_string

也许我正在度过一个大脑死亡的日子(或者事实上,我不是一个天生的程序员,我仍然在PHP的新手阶段),但有检查了PHP手册并阅读了PDO中的条目 ,但是我还没有更清楚PDO究竟是什么,为什么比使用mysql_real_escape_string更好。 这可能是因为我还没有真正掌握OOP的复杂性(我认为这与OOP有关),但除了variables和数组值似乎在它们之前有一个冒号,我还不确定它到底是什么以及如何使用它(为什么它比mysql_real_escape_string更好(这也可能与我没有清楚地了解“类”是什么有关) ,所以当我读“PDO类”时,我真的不聪明)。

在MySQL网站的“开发者区”位阅读了一两篇文章后 ,我仍然没有更清楚。 因为我现在还不知道这是什么东西,所以我认为现在使用它可能有点超出我的想法,但我仍然有兴趣扩大我的教育范围,并找出如何改进的地方。

任何人都可以用简单的英语向我解释PDO是什么(或者用简单的英语来指向我的主题),以及如何去使用它?

由于目前的答案详细,而你的问题是更全面的概述,我会试试看:

PDO类旨在封装与数据库交互所需的所有function。 他们通过定义“方法”(OO会议室的function)和“属性”(OO会议厅的variables)来实现这一点。 您将使用它们来完全替代您正在使用的所有“标准”function与数据库交谈。

因此,不要调用一系列'mysql_doSomething()'函数,将结果存储在自己的variables中,而是从PDO类实例化一个对象('class'= abstract definition,'object'=具体的,可用的实例的类),并调用该对象的方法来做同样的事情。

作为一个例子,没有PDO,你会做这样的事情:

 // Get a db connection $connection = mysql_connect('someHost/someDB', 'userName', 'password'); // Prepare a query $query = "SELECT * FROM someTable WHERE something = " . mysql_real_escape_string($comparison) . "'"; // Issue a query $db_result = mysql_query($query); // Fetch the results $results = array(); while ($row = mysql_fetch_array($db_result)) { $results[] = $row; } 

而这将是相当于使用PDO:

 // Instantiate new PDO object (will create connection on the fly) $db = new PDO('mysql:dbname=someDB;host=someHost'); // Prepare a query (will escape on the fly) $statement = $db->prepare('SELECT * FROM someTable WHERE something = :comparison'); // $statement is now a PDOStatement object, with its own methods to use it, eg // execute the query, passing in the parameters to replace $statement->execute(array(':comparison' => $comparison)); // fetch results as array $results = $statement->fetchAll(); 

所以乍一看,没有太大的区别,除了语法。 但是PDO版本有一些优点,最大的是数据库独立性:

如果您需要与PostgreSQL数据库交谈,则只需在实例化调用new PDO()mysql:更改为pgsql: 。 用旧的方法,你必须通过你所有的代码,用他们的'pg_doSomthing()'对象replace所有'mysql_doSomething()'函数(总是检查参数处理中的潜在差异)。 许多其他支持的数据库引擎也是如此。

因此,回到你的问题,PDO基本上只是给你一个不同的方式来实现相同的事情,同时提供一些捷径/改进/优势。 例如,转义会自动以您正在使用的数据库引擎所需的正确方式发生。 另外参数replace(防止SQL注入,在示例中未显示)要容易得多,使其不易出错。

您应该阅读一些OOP基础知识来了解其他优点。

我对PDO并不是很熟悉,但是“准备好的语句”和逃脱的string之间是有区别的。 转义是关于从查询中删除不允许的string ,但是预处理语句是关于告诉数据库需要什么types的查询

查询有多个部分

可以这样想:当你给数据库查询时,你会告诉它几个单独的事情。 有一件事可能是,例如,“我希望你做一个select”。 另一个可能是“将其限制为行,其中用户名是以下值”。

如果你build立一个查询作为一个string,并把它交给数据库,它不知道任何一部分,直到它获得完整的string。 你可能会这样做:

 'SELECT * FROM transactions WHERE username=$username' 

当它得到的string,它必须parsing它,并决定“这是一个SELECT与一个地方”。

把零件弄混了

假设恶意用户input他们的用户名为billysmith OR 1=1 。 如果你不小心,你可能会把它放到你的string中,导致:

 'SELECT * FROM transactions WHERE username=billysmith OR 1=1' 

…将返回所有用户的交易 ,因为1总是等于1.哎呀,你已经被黑了!

看看发生了什么? 数据库不知道在你的查询中需要什么部分 ,所以它只是parsingstring。 这并不令人惊讶,在WHERE有一个OR ,有两个条件,可以满足它。

保持部件平直

如果只知道预期的是什么 ,即WHERE只有一个条件的SELECT ,恶意用户就不会欺骗它。

有了准备好的陈述,你可以给它正确的期望。 你可以告诉数据库“我准备给你发一个SELECT ,它将被限制在行WHERE username =一个我将要给你的string。这就是全部 – 查询中没有其他部分你准备好了吗?好的,这里是用来比较用户名的string。“

有了这个期望,数据库不会被愚弄:它只会返回username名列中包含实际string'billysmith OR 1 = 1'的行。 如果没有人拥有该用户名,则不会返回任何内容。

准备好的陈述的其他好处

准备好的声明除了安全性好处之外,还具有一些速度优势:

  • 他们可以重复使用不同的参数,这应该比从头构build一个新的查询更快,因为数据库已经基本知道你要问什么了。 它已经build立了“查询计划”。
  • 有些数据库(Postgres就是我认为的那个)会在获得准备好的语句之后立即开始制定查询计划 – 在实际发送参数之前使用它。 所以即使在第一个查询中,您也可能会看到加速。

有关另一种解释,请参阅Theo的答案。

与mysql_real_escape_string不同,PDO允许您执行数据types。

 <?php /* Execute a prepared statement by binding PHP variables */ $calories = 150; $colour = 'red'; $sth = $dbh->prepare('SELECT name, colour, calories FROM fruit WHERE calories < :calories AND colour = :colour'); $sth->bindParam(':calories', $calories, PDO::PARAM_INT); $sth->bindParam(':colour', $colour, PDO::PARAM_STR, 12); $sth->execute(); ?> 

请注意,在上面的示例中,第一个参数卡路里必须是整数(PDO :: PARAM_INT)。

其次,对我来说,PDO参数化查询更易于阅读。 我宁愿读:

 SELECT name FROM user WHERE id = ? AND admin = ? 

 SELECT name FROM user WHERE id = mysql_real_escape_string($id) AND admin = mysql_real_escape_string($admin); 

第三,你不必确保你正确地引用参数。 PDO照顾这一点。 例如,mysql_real_query_string:

 SELECT * FROM user WHERE name = 'mysql_real_escape_string($name)' //note quotes around param 

VS

 SELECT * FROM user WHERE name = ? 

最后,PDO允许您将应用程序移植到不同的数据库,而无需更改您的PHP数据调用。

想象你写下如下的话:

 $query = 'SELECT * FROM table WHERE id = ' . mysql_real_escape_string($id); 

这不会节省注射,因为$ id可能是1 OR 1=1 ,您将从表中获取所有logging。 你必须将$ id转换为正确的数据types(在这种情况下是int)

pdo还有另一个优点,那就是数据库后端的可互换性。

除了防止SQL注入,PDO允许您准备一次查询并多次执行。 如果你的查询被多次执行(例如在一个循环中),这个方法应该更有效率(我说“应该是”,因为在老版本的MySQL中看起来并不总是这种情况)。 准备/绑定方法也更符合我曾与其他语言。

为什么PDO比mysql_real_escape_string更好地转义MySQL查询/查询string?

只是因为“逃避”是没有意义的。
而且,这是不同的事情。

逃跑的唯一问题是每个人都认为它是错误的,假设它是某种“保护”。
大家都说“我逃过我的变数”,意思是“我保护了我的查询”。
单独逃避与保护无关。

保护可以大致实现的情况下, 我逃避和引用我的数据 ,但它并不适用于任何地方,例如标识符(顺便说一下,以及PDO)。

所以答案是:

  • PDO在为绑定值进行转义时,不仅适用于转义,而且也适用于引用 – 这就是为什么它更好。
  • “逃避”不是“保护”的代名词。 “逃避+引用”大致是。
  • 但是对于一些查询部分这两种方法都不适用。