Why shouldn't I use mysql_* functions in PHP?

Why shouldn’t I use mysql_* functions in PHP?

技术背景

在PHP开发中,mysql_* 函数曾经是开发者与MySQL数据库交互的主要方式。然而,随着PHP和MySQL的发展,这些函数逐渐暴露出诸多问题,因此不再被推荐使用。

不使用 mysql_* 函数的原因

功能特性缺失

  • 缺乏面向对象接口mysql_* 函数仅提供了面向过程的接口,不利于代码的组织和维护,而现代开发更倾向于使用面向对象的编程方式。
  • 不支持新特性:它不支持非阻塞异步查询、预编译语句、存储过程、多语句、事务处理、新的密码认证方法以及MySQL 5.1及以后版本的新功能。例如,预编译语句可以有效防止SQL注入攻击,而 mysql_* 函数需要手动转义数据,容易出错。

安全风险

  • 易导致SQL注入:由于不支持预编译语句,开发者需要手动使用 mysql_real_escape_string() 函数对用户输入进行转义。如果在任何一处忘记转义或只转义了部分输入,数据库就可能遭受攻击。例如,恶意用户可以构造特殊的输入,如 ' OR 1=1 --,来绕过身份验证。

维护与兼容性问题

  • 停止开发mysql_* 函数已经停止维护,从PHP 5.5开始被正式弃用,并在PHP 7.0中被完全移除。这意味着使用这些函数的代码在未来版本的PHP中可能无法正常运行。
  • 兼容性差:不利于向其他数据库后端迁移,代码的可移植性较低。

替代方案及示例代码

PDO(PHP Data Objects)

PDO 是一个数据库访问层,提供了统一的方式来访问多个数据库。以下是使用 PDO 进行数据库操作的示例代码:

连接到 MySQL

1
$db = new PDO('mysql:host=localhost;dbname=testdb;charset=utf8', 'username', 'password');

查询数据

1
2
3
4
$stmt = $db->query('SELECT * FROM table');
while($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
echo $row['field1'];
}

插入数据

1
2
3
$stmt = $db->prepare("INSERT INTO table(field1,field2) VALUES(:field1,:field2)");
$stmt->execute(array(':field1' => $field1, ':field2' => $field2));
$affected_rows = $stmt->rowCount();

MySQLi

MySQLi 是专门为 MySQL 设计的扩展,提供了面向过程和面向对象两种接口。以下是使用 MySQLi 进行数据库操作的示例代码:

连接到 MySQL

1
$mysqli = new mysqli('localhost', 'username', 'password', 'testdb');

查询数据

1
2
3
4
$result = $mysqli->query('SELECT * FROM table');
while($row = $result->fetch_assoc()) {
echo $row['field1'];
}

插入数据

1
2
3
4
$stmt = $mysqli->prepare("INSERT INTO table (field1, field2) VALUES (?, ?)");
$stmt->bind_param("ss", $field1, $field2);
$stmt->execute();
$affected_rows = $stmt->affected_rows;

最佳实践

  • 使用预编译语句:无论是 PDO 还是 MySQLi,都建议使用预编译语句来处理用户输入,避免 SQL 注入。
  • 错误处理:在使用数据库操作时,要进行适当的错误处理,避免将错误信息直接暴露给用户。例如,在 PDO 中可以使用异常处理机制:
1
2
3
4
5
6
try {
$db->query('hi'); // 无效查询
} catch (PDOException $ex) {
echo "An Error occured!";
some_logging_function($ex->getMessage());
}
  • 抽象数据库操作:在应用代码和数据库 API 之间添加抽象层,如使用 ORM 或查询构建器,使代码更易于维护和扩展。

常见问题

能否继续使用 mysql_* 函数?

不建议继续使用。虽然在旧版本的 PHP 中这些函数仍然可用,但由于它们已被弃用且存在安全风险,建议尽快迁移到 PDO 或 MySQLi。

迁移到 PDO 或 MySQLi 困难吗?

对于简单的项目,迁移相对容易。可以先将 mysql_* 函数替换为相应的 PDO 或 MySQLi 函数,然后逐步引入预编译语句和其他新特性。对于复杂的项目,可能需要更多的时间和精力进行重构。

PDO 和 MySQLi 哪个更好?

这取决于具体需求。PDO 提供了统一的接口,可用于访问多种数据库,更适合需要在不同数据库之间切换的项目;MySQLi 是专门为 MySQL 设计的,提供了更多 MySQL 特定的功能,适合只使用 MySQL 数据库的项目。


Why shouldn't I use mysql_* functions in PHP?
https://119291.xyz/posts/2025-04-22.why-not-use-mysql-functions-in-php/
作者
ww
发布于
2025年4月23日
许可协议