Why shouldn't I use mysql_* functions in PHP?
为什么不应该使用
即使他们在我的网站上工作,我为什么还要用别的东西?
如果他们不在我的网站上工作,为什么我会遇到这样的错误
Warning: mysql_connect(): No such file or directory
MySQL扩展:
- 不在积极发展中
- 从php 5.5(2013年6月发布)起正式被否决。
- 已从php 7.0完全删除(2015年12月发布)
- 这意味着截至2018年12月31日,它将不存在于任何支持的PHP版本中。目前,它只获取安全更新。
- 缺少OO接口
- 不支持:
- 非阻塞、异步查询
- 准备好的语句或参数化查询
- 存储过程
- 多个语句
- 交易
- "新"密码验证方法(在MySQL5.6中默认为打开;在5.7中是必需的)
- MySQL5.1中的所有功能
因为它被否决了,所以使用它可以减少代码的未来证明。
缺少对准备好的语句的支持尤其重要,因为它们提供了一种更清晰、更不容易出错的方法来转义和引用外部数据,而不是用单独的函数调用手动转义外部数据。
请参阅SQL扩展的比较。
PHP提供了三种不同的API来连接到MySQL。这些是
后来的PHP开发团队决定在用户连接到MySQL时生成
从php 5.5起,
看到红盒子了吗?好的。
当您进入任何
离开
- 存储过程(无法处理多个结果集)
- 准备的报表
- 加密(SSL)
- 压缩
- 完全字符集支持
不使用
- 不在积极发展中
- 从php 7起删除
- 缺少OO接口
- 不支持非阻塞异步查询
- 不支持准备好的语句或参数化查询
- 不支持存储过程
- 不支持多个语句
- 不支持事务处理
- 不支持MySQL5.1中的所有功能
以上点引自昆廷的回答好的。
缺少对准备好的语句的支持尤其重要,因为它们提供了一种更清晰、更不容易出错的方法来转义和引用外部数据,而不是通过单独的函数调用手动转义外部数据。好的。
请参阅SQL扩展的比较。好的。
抑制折旧警告好的。
当代码转换为
1 |
请注意,这也会隐藏其他的拒绝警告,不过,这些警告可能是针对MySQL以外的东西的。(来自PHP手册)好的。
文章PDO与mysqli:你应该使用哪一个?由dejan marjanovic将帮助您选择。好的。
还有一个更好的方法是
a."pdo–php数据对象–是一个数据库访问层,提供对多个数据库的统一访问方法。"好的。
Ok.
连接到MySQL
使用
1 2 3 | $link = mysql_connect('localhost', 'user', 'pass'); mysql_select_db('testdb', $link); mysql_set_charset('UTF-8', $link); |
使用
在这里,我想你对除
1 | $db = new PDO('mysql:host=localhost;dbname=testdb;charset=utf8', 'username', 'password'); |
注:您也可以使用
如果有连接错误,它将抛出一个可以捕获的
阅读良好:连接和连接管理?好的。
还可以将多个驱动程序选项作为数组传递给第四个参数。我建议传递将
另一种是关闭默认情况下在
稍后我将解释为什么应关闭准备仿真。如需了解原因,请查看本帖。好的。
只有当您使用的是我不推荐的旧版本的
下面是一个如何做到这一点的示例:好的。
1 2 3 4 5 | $db = new PDO('mysql:host=localhost;dbname=testdb;charset=UTF-8', 'username', 'password', array(PDO::ATTR_EMULATE_PREPARES => false, PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION)); |
我们可以在pdo构造之后设置属性吗?好的。
是的,我们还可以在PDO构造后使用
1 2 3 4 5 | $db = new PDO('mysql:host=localhost;dbname=testdb;charset=UTF-8', 'username', 'password'); $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $db->setAttribute(PDO::ATTR_EMULATE_PREPARES, false); |
错误处理
在
使用
1 2 | //Connected to MySQL $result = mysql_query("SELECT * FROM table", $link) or die(mysql_error($link)); |
PDO::ERRMODE_SILENT 。它只是设置错误代码,其行为与mysql_* 几乎相同,您必须检查每个结果,然后查看$db->errorInfo(); 以获取错误详细信息。PDO::ERRMODE_WARNING 升高E_WARNING 。(运行时警告(非致命错误)。脚本的执行不会停止。)PDO::ERRMODE_EXCEPTION :抛出异常。它表示PDO引发的错误。您不应该从自己的代码中抛出一个PDOException 。有关PHP中异常的详细信息,请参阅异常。当它没有被抓到的时候,它的行为非常类似于or die(mysql_error()); 。但与OR die() 不同,如果你选择这样做,PDOException 可以被捕获并被优雅地处理。
良好阅读:好的。
- 错误和错误处理?
- pdoException类?
- 例外情况?
像:好的。
1 2 3 | $stmt->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_SILENT ); $stmt->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING ); $stmt->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION ); |
你可以用
1 2 3 4 5 6 7 8 | try { //Connect as appropriate as above $db->query('hi'); //Invalid query! } catch (PDOException $ex) { echo"An Error occured!"; //User friendly message/message you want to show to user some_logging_function($ex->getMessage()); } |
您现在不必处理
1 2 3 4 5 6 7 8 9 10 11 12 | function data_fun($db) { $stmt = $db->query("SELECT * FROM table"); return $stmt->fetchAll(PDO::FETCH_ASSOC); } //Then later try { data_fun($db); } catch(PDOException $ex) { //Here you can handle error and show message/perform action you want. } |
另外,你也可以用
现在,在阅读了以上所有内容之后,你可能会想:当我只想开始学习简单的
好的。
所以你在
1 2 3 4 5 6 7 8 | <?php $result = mysql_query('SELECT * from table') or die(mysql_error()); $num_rows = mysql_num_rows($result); while($row = mysql_fetch_assoc($result)) { echo $row['field1']; } |
现在在
1 2 3 4 5 6 | <?php $stmt = $db->query('SELECT * FROM table'); while($row = $stmt->fetch(PDO::FETCH_ASSOC)) { echo $row['field1']; } |
或好的。
1 2 3 4 5 | <?php $stmt = $db->query('SELECT * FROM table'); $results = $stmt->fetchAll(PDO::FETCH_ASSOC); //Use $results |
注意:如果您使用的方法如下(
1 2 3 4 | <?php foreach($db->query('SELECT * FROM table') as $row) { echo $row['field1']; } |
在PDO数据中,它是通过
注意上面的
首先,我解释了如何选择获取模式:好的。
1 | $stmt->fetch(PDO::FETCH_ASSOC) |
在上面,我一直在使用
PDOStatement::fetchAll() —返回一个包含所有结果集行的数组PDOStatement::fetchColumn() —从结果集的下一行返回一列PDOStatement::fetchObject() —获取下一行并将其作为对象返回。PDOStatement::setFetchMode() —设置此语句的默认提取模式
现在我来取模式:好的。
PDO::FETCH_ASSOC :返回结果集中返回的按列名索引的数组。PDO::FETCH_BOTH (默认值):返回结果集中返回的按列名和0索引列号索引的数组。
还有更多的选择!在
获取行计数:好的。
不使用
1 2 3 4 | <?php $stmt = $db->query('SELECT * FROM table'); $row_count = $stmt->rowCount(); echo $row_count.' rows selected'; |
获取最后插入的ID好的。
1 2 3 | <?php $result = $db->exec("INSERT INTO table(firstname, lastname) VAULES('John', 'Doe')"); $insertId = $db->lastInsertId(); |
插入、更新或删除语句
好的。
我们在
1 2 3 | <?php $results = mysql_query("UPDATE table SET field='value'") or die(mysql_error()); echo mysql_affected_rows($result); |
在PDO中,同样的事情可以通过:好的。
1 2 3 |
在上面的查询中,
insert and delete稍后将介绍。好的。 只有在查询中不使用变量时,上述方法才有用。但是,当您需要在查询中使用变量时,永远不要像上面那样尝试,因为准备好的语句或参数化的语句是存在的。好的。准备的报表 问:准备好的声明是什么?为什么我需要它们?a.准备好的语句是预先编译好的SQL语句,可以通过只向服务器发送数据来多次执行。好的。 使用准备好的语句的典型工作流程如下(引自维基百科3点):好的。 准备:语句模板由应用程序创建并发送到数据库管理系统(DBMS)。某些值未指定,称为参数、占位符或绑定变量(下面标记为 DBMS对语句模板进行分析、编译和执行查询优化,并在不执行的情况下存储结果。好的。 通过在SQL中包含占位符,可以使用准备好的语句。基本上有三个不带占位符(不要用上面的变量来尝试这个方法),一个带未命名的占位符,一个带命名的占位符。好的。 那么,现在,什么是命名的占位符,我如何使用它们呢?a.指定的占位符。使用带冒号的描述性名称,而不是问号。我们不关心名下持仓人的地位/价值顺序:好的。 也可以使用执行数组进行绑定:好的。 问:那么现在,什么是未命名的占位符,如何使用它们?A.让我们举个例子:好的。 和好的。 在上面,您可以看到那些 注意:在未命名的占位符中,我们必须注意数组中要传递给 注: 然而, 好啊。
2
3
4
$stmt = $db->prepare("SELECT * FROM table WHERE id=:id AND name=:name");
$stmt->execute(array(':name' => $name, ':id' => $id));
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
2
3
4
5
6
7
8
9
10
11
12
public $name;
public $add;
function __construct($a,$b) {
$this->name = $a;
$this->add = $b;
}
}
$demo = new person('john','29 bla district');
$stmt = $db->prepare("INSERT INTO table (name, add) value (:name, :add)");
$stmt->execute((array)$demo);
2
3
4
5
$stmt = $db->prepare("INSERT INTO folks (name, add) values (?, ?)");
$stmt->bindValue(1, $name, PDO::PARAM_STR);
$stmt->bindValue(2, $add, PDO::PARAM_STR);
$stmt->execute();
2
$stmt->execute(array('john', '29 bla district'));
2
3
$stmt->execute(array(':name' => $name, ':id' => $id));
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
2
3
$stmt->execute(array(':field1' => $field1, ':field2' => $field2));
$affected_rows = $stmt->rowCount();
2
3
4
$stmt->bindValue(':id', $id, PDO::PARAM_STR);
$stmt->execute();
$affected_rows = $stmt->rowCount();
2
3
$stmt->execute(array($name, $id));
$affected_rows = $stmt->rowCount();
2
3
4
首先,让我们从我们给每个人的标准评论开始:
Please, don't use
mysql_* functions in new code. They are no longer maintained and are officially deprecated. See the red box? Learn about prepared statements instead, and use PDO or MySQLi - this article will help you decide which. If you choose PDO, here is a good tutorial.
让我们一句一句地来看看这个,并解释一下:
它们不再被维护,并被正式否决
这意味着PHP社区正在逐渐放弃对这些非常老的函数的支持。它们很可能不存在于未来(最新)版本的PHP中!继续使用这些函数可能会在将来(而不是现在)破坏代码。
新!-从php 5.5开始,ext/mysql现在正式被否决了!
更新!ext/mysql已在php 7中删除。相反,你应该学习准备好的陈述
mysql_* 扩展不支持准备好的语句,这是(除其他外)对抗SQL注入的非常有效的对策。它修复了MySQL相关应用程序中的一个非常严重的漏洞,允许攻击者访问您的脚本并对您的数据库执行任何可能的查询。有关详细信息,请参阅如何在PHP中防止SQL注入?
看到红盒子了吗?
当您进入任何
mysql 功能手册页面时,您会看到一个红色的框,说明不应再使用它。使用PDO或mysqli
有更好、更健壮和构建良好的替代方案,pdo-php database object,它提供了一个完整的OOP数据库交互方法,mysqli,它是一个mysql特有的改进。
易用性
已经提到了分析和综合原因。对于新来者来说,停止使用过时的mysql_u函数有更大的动机。好的。
现代的数据库API更易于使用。好的。
主要是绑定参数可以简化代码。有了优秀的教程(如上图所示),向PDO的过渡不会过于困难。好的。
然而,一次重写一个更大的代码库需要时间。中间方案的理由:好的。等效的pdo_*functions代替mysql_*s>
使用
只需在每个必须与数据库交互的调用脚本中使用
删除所有地方的
您的代码将工作得很相似,并且大部分看起来仍然相同:好的。
1 2 3 4 5 6 7 8 9 10 | include_once("pdo_mysql.php"); pdo_connect("localhost","usrABC","pw1234567"); pdo_select_db("test"); $result = pdo_query("SELECT title, html FROM pages"); while ($row = pdo_fetch_assoc($result)) { print"$row[title] - $row[html]"; } |
ET Voice。您的代码正在使用PDO。现在是时候实际利用它了。好的。绑定参数易于使用
好的。
你只需要一个不那么笨拙的API。好的。
好的。
将变量移出SQL字符串。好的。
- 将它们作为逗号分隔的函数参数添加到
pdo_query() 中。 - 将问号
? 放在变量之前的位置。 - 去掉以前包含字符串值/变量的单引号。
对于长度更大的代码来说,优势变得更加明显。好的。
通常,字符串变量不只是被插入到SQL中,而是与中间的转义调用相连接。好的。
1 2 3 4 | pdo_query("SELECT id, links, html, title, user, date FROM articles WHERE title='" . pdo_real_escape_string($title) ."' OR id='". pdo_real_escape_string($title) ."' AND user <> '" . pdo_real_escape_string($root) ."' ORDER BY date") |
使用
1 2 | pdo_query("SELECT id, links, html, title, user, date FROM articles WHERE title=? OR id=? AND user<>? ORDER BY date", $title, $id, $root) |
记住,PDO仍然允许或。不要转义变量并将其绑定到同一查询中。好的。
- 占位符功能由它后面的真正PDO提供。
- 因此也允许稍后使用
:named 占位符列表。
更重要的是,您可以在任何查询后面安全地传递$u request[]变量。提交时,