唯一可靠方式是用pdo::prepare或mysqli_prepare预处理语句,其他如字符串拼接、addslashes()、mysql_real_escape_string()均不安全;php 8.0+已移除mysql_*函数;pdo连接必须显式指定charset=utf8mb4并禁用模拟预处理(pdo::attr_emulate_prepares=>false),占位符仅适用于值,表名、字段名等须白名单校验。

唯一可靠的方式是用 PDO::prepare 或 mysqli_prepare,其他任何字符串拼接、addslashes()、mysql_real_escape_string() 都不安全,PHP 8.0+ 已彻底移除 mysql_* 函数。
PDO连接必须显式指定字符集和禁用模拟预处理
很多新手以为只要用了 prepare() 就万事大吉,结果在宽字节场景下仍被绕过。根本原因是默认开启的 PDO::ATTR_EMULATE_PREPARES 让 PHP 自己“模拟”预处理,没走数据库真实预编译流程。
- 连接时必须在 DSN 中声明
charset=utf8mb4,不能靠SET NAMES补救 - 必须调用
$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false)强制走真实预处理 - 同时启用异常模式:
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION),否则错误静默失败
错误示例:$pdo = new PDO("mysql:host=localhost;dbname=test", $u, $p) —— 缺少字符集和属性设置,等于裸奔。
占位符只能用于值,不能用于字段名、表名、排序方向
预处理语句只保护“数据值”,对 SQL 结构部分(如列名、表名、ORDER BY 子句)完全无效。这类动态片段必须白名单校验,不能靠绑定参数糊弄过去。
-
ORDER BY字段:用in_array($_GET['sort'], ['id', 'name', 'created_at'])判断,再硬编码进 SQL - 表名/列名:禁止从用户输入直接拼接,哪怕加了
mysqli_real_escape_string也没用 -
LIKE查询中的通配符必须在 PHP 层加,不能写成WHERE name LIKE :keyword%—— 这种写法会报错或逻辑失效
正确做法:$search = '%' . $_POST['q'] . '%'; $stmt->execute([$search]);,SQL 里保持 name LIKE ?。
数字参数别拼字符串,更别信“转义就够了”
这是新手最常踩的坑:"WHERE id = " . (int)$_GET['id'] 看似安全,但一旦漏掉强制转换,或者用在非数字上下文(比如 IN (1,2,?)),立刻崩盘。而 mysqli_real_escape_string 对数字字段根本不起作用 —— 因为它不加引号,压根不触发转义逻辑。
- 所有外部输入,无论类型,统一走占位符:
WHERE status = ?,然后execute([$_POST['status']]) - 如果要确保类型,用
bindValue(1, $_POST['id'], PDO::PARAM_INT),避免字符串被当作文本解析 - 别用
exec()执行含占位符的 SQL —— 它不支持参数绑定,只会把问号当字面量
典型翻车现场:$sql = "SELECT * FROM user WHERE id = " . $_GET['id']; mysqli_query($conn, $sql),哪怕后面加了 mysqli_real_escape_string,传入 id=1 OR 1=1 依然全表返回。
mysqli_bind_param 的类型字符串必须严丝合缝
mysqli 的 bind_param() 看似简单,但类型字符串(如 "is")和变量顺序稍有差池,就会报 Number of variables doesn't match number of parameters in prepared statement,而且错误信息不提示具体哪一环错了。
- 类型字符必须一一对应:
i(整型)、s(字符串)、d(浮点)、b(blob) - 变量必须是引用传递,
bind_param("s", $_POST['name'])会警告 —— 得先赋值给变量再传:$name = $_POST['name']; bind_param("s", $name) - 不建议混用命名占位符和问号占位符,
mysqli只支持问号,PDO 支持两种,但别在同一个项目里来回切
真正容易被忽略的是:预处理不是“写了就安全”,而是“每一步都得对”。字符集、模拟开关、占位符位置、类型绑定、白名单校验——缺一不可。漏掉任意一环,都可能让整个防护形同虚设。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











