mysqli_real_escape_string在PHP 8.3+中仍存在但不推荐单独用于防SQL注入,因其仅转义字符串特殊字符,无法防护数字型注入、LIKE通配符、字符集错配等问题;应改用预处理语句实现代码与数据隔离。
PHP 8.0 没删这个函数,但它现在要求第一个参数必须是有效的 mysqli 连接对象——如果连接失败、未初始化或被提前 mysqli_close(),调用就会直接报 Fatal error: Uncaught ValueError: mysqli_real_escape_string(): Argument #1 ($mysql) must be of type mysqli, null given。
常见失效场景:
null 进去mysqli_connect() 但没检查返回值,连接失败时得到 false,后续当对象传给 mysqli_real_escape_string()
实操建议:
mysqli_real_escape_string($conn, $str) 前加 if (!$conn instanceof mysqli) { throw new RuntimeException('DB connection lost'); }
function safe_escape($conn, $str) { return $conn instanceof mysqli ? mysqli_real_escape_string($conn, $str) : addslashes($str);}
mysqli_prepare() + mysqli_stmt_bind_param()),它从根源上绕过字符串转义逻辑PHP 8.0 已物理删除整个 mysql_* 函数族,包括 mysql_real_escape_string()。只要代码里还存在任何 mysql_* 调用,不管是否执行到,只要被 PHP 解析器读到(比如在条件分支里),就会立即报 Fatal error: Uncaught Error: Call to undefined function mysql_real_escape_string()。
立即学习“PHP免费学习笔记(深入)”;
容易漏掉的地方:
.php 后缀的 HTML 混写文件)里藏着 mysql_real_escape_string()
db_helper.php 或 functions.php 中封装了兼容层,内部仍调用 mysql_*
// mysql_real_escape_string() is deprecated —— 这类注释不会报错,但说明项目曾重度依赖它,得顺藤摸瓜查实际调用实操建议:
grep -r "mysql_real_escape_string|mysql_escape_string" . --include="*.php"
./plugins/、./includes/、./themes/*/template.php 等非主框架目录mysqli_real_escape_string($conn, $str) 或(更优)改用预处理PHP 8.0 把很多“隐式兜底”行为变成了硬性拦截,导致旧防御链断裂。典型例子:用 intval() 或 (int) 强转用户输入后拼进 SQL,看似安全,但若原始输入是 null 或布尔值,PHP 8 会直接报错,而不是返回 0。
例如这段旧代码在 PHP 7.4 可跑,在 8.0 会崩:
$id = $_GET['id'] ?? null;$sql = "SELECT * FROM users WHERE id = " . (int)$id;
因为 (int) null 在 PHP 8.0 触发 TypeError,根本走不到 SQL 拼接那步。
实操建议:
$id = filter_input(INPUT_GET, 'id', FILTER_VALIDATE_INT) ?: 0;
(int) 或 intval() 处理可能为 null 的输入;用 filter_var() 显式声明意图WHERE id = ? 类型的查询,确认占位符绑定前已做过有效性判断,而不是靠类型转换“碰运气”PDO::quote() 本身没被移除,但它的底层依赖 PDO MySQL 驱动。PHP 8.0 的 ABI 不兼容 PHP 7.4,若你从旧环境复制了 pdo_mysql.so 或宝塔没重装扩展,该方法可能返回空字符串、false,甚至不报错直接放行恶意字符。
验证方式:
php --ri pdo_mysql,确认输出里有 PDO Driver for MySQL => enabled,且版本号 ≥ 8.0$pdo = new PDO("mysql:host=127.0.0.1;dbname=test", "root", "");var_dump($pdo->quote("'; DROP TABLE users; --")); // 应返回带引号的转义字符串,不是空或 false
/www/server/php/80/lib/php/extensions/no-debug-non-zts-20200930/pdo_mysql.so 是否存在(路径中的 20200930 是 PHP 8.0 ABI ID)关键点:扩展名存在 ≠ 功能可用。哪怕 php -m 显示 pdo_mysql,若 ABI 不匹配,quote() 就可能返回异常结果,且无明确报错。