我被告知我最好使用PDO
进行MySQL转义,而不是mysql_real_escape_string
。
也许我有一个脑死亡的日子(或者可能是因为我没有想象力的自然程序员,而且在PHP方面我还处于新手阶段)但是,在查看了PHP手册并阅读the entry on PDO后,我仍然不清楚PDO实际上是什么以及为什么它比使用mysql_real_escape_string
更好。这可能是因为我还没有真正掌握OOP的复杂性(我假设它与OOP有关),但除了变量和数组值似乎在其前面有冒号之外,我仍然不确定它实际上是什么以及你如何使用它(以及为什么它比mysql_real_escape_string
更好。(这也可能与我真的没有清楚地了解什么有关“课程”是,所以当我读“PDO课程”时,我真的不是更聪明的。)
在MySQL网站的'Developer Zone'位上读了an article或两个,我仍然不清楚。由于我现在甚至无法弄清楚它到底是什么,我认为现在可能使用它有点超出我的范围,但我仍然有兴趣扩大我的教育并找出如何改进的方法。
有人能用“简单的英语”向我解释PDO是什么(或指向我用简单英语写的主题的方向),以及你如何使用它?
答案 0 :(得分:57)
由于当前的答案会详细介绍,而您的问题更多是针对概述,我会试一试:
PDO类旨在封装与数据库交互所需的所有功能。他们通过定义'方法'(功能的OO客厅)和'属性'(变量的OO客厅)来做到这一点。您可以将它们用作完全替换,用于您现在用于与数据库通信的所有“标准”功能。
因此,不是调用一系列'mysql_doSomething()'函数,将结果存储在自己的变量中,而是从PDO类中“实例化”一个对象('class'= abstract definition,'object'= concrete ,可用的类实例)并在该对象上调用方法来执行相同的操作。
例如,如果没有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, e.g.
// execute the query, passing in the parameters to replace
$statement->execute(array(':comparison' => $comparison));
// fetch results as array
$results = $statement->fetchAll();
所以乍一看,除了语法之外没有太大区别。但PDO版本有一些优点,最大的一个是数据库独立性:
如果您需要与PostgreSQL数据库交谈,则只需在实例化调用mysql:
中将pgsql:
更改为new PDO()
。使用旧方法,您必须完成所有代码,用'pg_doSomthing()'对应替换所有'mysql_doSomething()'函数(始终检查参数处理中的潜在差异)。许多其他受支持的数据库引擎也是如此。
所以回到你的问题,PDO基本上只是给你一个不同的方法来实现相同的东西,同时提供一些捷径/改进/优势。例如,转义将以您正在使用的数据库引擎所需的正确方式自动发生。参数替换(防止SQL注入,未在示例中显示)也更容易,使其更不容易出错。
您应该阅读some OOP basics以了解其他优势。
答案 1 :(得分:40)
我对PDO并不是很熟悉,但“预准备语句”和转义字符串之间存在区别。转义是关于从查询中删除不允许的字符串,但是准备好的语句是关于告诉数据库期望什么类型的查询。
以这种方式思考:当您向数据库提出查询时,您会告诉它几个不同的事情。有一件事可能是,例如,“我希望你做一个选择。”另一个可能是“将其限制为行,其中用户名是以下值。”
如果您将查询构建为字符串并将其交给数据库,则在获取完成的字符串之前,它不知道任何一个部分。你可以这样做:
'SELECT * FROM transactions WHERE username=$username'
当它获得该字符串时,它必须解析它并决定“这是SELECT
WHERE
”。
假设恶意用户将其用户名输入为billysmith OR 1=1
。如果你不小心,可以把它放到你的字符串中,结果是:
'SELECT * FROM transactions WHERE username=billysmith OR 1=1'
...会返回所有用户的所有交易,因为1总是等于1.哎呀,你被黑了!
看看发生了什么? 数据库不知道您的查询中需要哪些部分,所以它只是解析了字符串。 WHERE
有一个OR
,有两个条件可以满足它,这并不奇怪。
如果只知道期待的内容,即SELECT
WHERE
只有一个条件,那么恶意用户就不会欺骗它。
通过准备好的陈述,您可以给予正确的期望。您可以告诉数据库“我即将向您发送SELECT
,它将仅限于行WHERE username =
我将要给您的字符串。这就是全部 - 有没有查询的其他部分。你准备好了吗?好的,这里有与用户名比较的字符串。“
有了这个期望,数据库不会被愚弄:它只会返回username
列包含实际字符串'billysmith OR 1 = 1'的行。如果没有人拥有该用户名,则不返回任何内容。
除了安全性方面的好处之外,准备好的语句还有几个速度优势:
有关其他说明,请参阅Theo的回答here。
答案 2 :(得分:16)
与mysql_real_escape_string不同,PDO允许您强制执行数据类型。
<?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();
?>
请注意,在上面的示例中,第一个参数calories必须是一个整数(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数据调用。
答案 3 :(得分:14)
想象一下你写的东西:
$query = 'SELECT * FROM table WHERE id = ' . mysql_real_escape_string($id);
这不会使您免于注射,因为$ id可能是1 OR 1=1
,您将从表中获得所有记录。你必须将$ id强制转换为正确的数据类型(在这种情况下为int)
pdo还有另一个优势,那就是数据库后端的可互换性。
答案 4 :(得分:3)
除了防止SQL注入外,PDO还允许您准备一次查询并多次执行。如果你的查询被多次执行(例如在一个循环中),这个方法应该更有效(我说“应该是”,因为在旧版本的MySQL上看起来并非总是如此)。准备/绑定方法也更符合我使用过的其他语言。
答案 5 :(得分:3)
为什么PDO比mysql_real_escape_string更好地逃避MySQL查询/查询字符串?
仅仅因为“逃避”是没有意义的 而且,它是不同的无与伦比的事项。
逃避的唯一问题是每个人都错了,假设它是某种“保护”。
每个人都说“我逃脱了我的变量”,意思是“我保护了我的查询”
虽然单独逃避与保护毫无关系。
在我转义并引用我的数据的情况下,可以大致实现保护,但它并不适用于所有地方,例如标识符(以及PDO,顺便说一句)。
所以答案是: