为什么PHP中的mysql_*函数是祸害:完整解析与示例

面向初学者的在线Python训练器

轻松学习Python,无需理论负担。在浏览器中直接解决带自动检查的实践任务,无需安装任何东西。

开始课程

引言:从历史到问题

\n\n

如果您曾经用PHP编写过代码并与MySQL数据库打过交道,那么您很可能见过像mysql_connect()或mysql_query()这样的代码。大约10到15年前,这曾是事实上的标准。但时代在变,如今使用mysql_*函数,就像试图在新款MacBook上运行Windows 95一样。虽然可以,但何必呢?

\n\n

在Stack Overflow上,“为什么我不应该在PHP中使用mysql_*函数?”这个问题获得了数千次浏览和数百次投票。这并非偶然:安全性和现代数据库处理方法对于任何开发者来说都至关重要。在本文中,我们将剖析为什么mysql_*不仅仅是“过时”,而是明显危险,并展示应该用什么来替代它们。

\n\n

问题一:mysql_*已从PHP 7中完全移除

\n\n

最明显的原因是:从PHP 5.5.0开始,mysql_*函数被标记为deprecated(已弃用),而在PHP 7.0中则被完全移除。如果您的服务器升级到PHP 7+,所有使用mysql_connect()、mysql_query()等函数的代码将直接停止工作。您将收到致命错误:

\n\n
Fatal error: Call to undefined function mysql_connect()
\n\n

这不是“可能无法工作”,而是网站必然崩溃。因此,第一个也是最重要的原因是:兼容性。任何主机商迟早都会升级PHP,届时您的项目将陷入死区。

\n\n

问题二:缺乏对SQL注入的防护

\n\n

让我们看看一个典型的mysql_*代码:

\n\n
<?php\n$connection = mysql_connect('localhost', 'user', 'password');\nmysql_select_db('my_database', $connection);\n\n$username = $_POST['username'];\n$password = $_POST['password'];\n\n$query = "SELECT * FROM users WHERE username = '$username' AND password = '$password'";\n$result = mysql_query($query, $connection);\n\nif (mysql_num_rows($result) > 0) {\n    echo "欢迎!";\n} else {\n    echo "用户名或密码错误";\n}\n?>
\n\n

看起来无害?现在想象一下,攻击者在username字段中输入以下字符串:

\n\n
admin' OR '1'='1
\n\n

查询变成了:

\n\n
SELECT * FROM users WHERE username = 'admin' OR '1'='1' AND password = '...'
\n\n

瞧——'1'='1'始终为真,因此查询将返回表中的第一条记录。攻击者无需密码即可登录系统。这是一个经典的SQL注入。mysql_*函数不提供任何内置的数据转义机制——您必须手动使用mysql_real_escape_string(),而该函数本身也已过时。

\n\n

与将防护内置于架构中的现代方法相比(稍后详述)。

\n\n

问题三:过时的架构与缺乏支持

\n\n

mysql_*是一个过程式接口,不支持:

\n\n
    \n
  • 预处理语句(prepared statements)——防御注入的主要工具。
  • \n
  • 面向对象风格——现代PHP中通常使用对象进行开发。
  • \n
  • 多语句查询——无法在一次调用中执行多条SQL命令。
  • \n
  • 事务——虽然可以模拟,但没有内置支持。
  • \n
  • 存储过程——与之配合使用极其不便。
  • \n
\n\n

此外,mysql_*扩展自2014年以来就未再更新。PHP开发者已停止对其维护。这意味着任何新的数据库功能、安全改进或优化——所有这些都与您无缘。

\n\n

应该用什么替代mysql_*?

\n\n

PHP有两个现代且受支持的

博客

书籍推荐