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