唯一可靠防sql注入的方法是使用mysqli::prepare()或pdo::prepare()预处理语句,因其将sql结构与数据彻底分离;切勿手拼sql或依赖addslashes()、mysql_real_escape_string()等已废弃且不安全的函数。

用 mysqli::prepare() 或 PDO::prepare() 是唯一靠谱路径
手拼 SQL 字符串,哪怕加了 mysqli_real_escape_string(),也挡不住绕过型注入(比如宽字节、编码歧义)。预处理语句把 SQL 结构和数据彻底分离,数据库引擎在解析阶段就固定了执行逻辑,变量只当纯数据传入,连“被当 SQL 执行”这个环节都不存在了。
实操建议:
- 优先选
PDO,它跨数据库兼容性好,错误模式统一(设PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION) -
mysqli也行,但注意:必须用面向对象写法的prepare(),别用过程式mysqli_prepare()后忘了绑定——容易漏掉bind_param() - 所有用户输入,只要进 SQL,无论 WHERE、ORDER BY 还是 LIMIT 后的数字,全得走参数占位符;
ORDER BY ?是非法的,得用白名单校验后硬编码字段名
别信 addslashes() 和 mysql_real_escape_string()
这两个函数根本不是为防注入设计的:addslashes() 只处理单引号、反斜杠等几个字符,对十六进制绕过、Unicode 编码混淆完全无效;mysql_real_escape_string() 已废弃且依赖连接字符集,一旦客户端和服务端编码不一致(比如 UTF8MB4 连接却传 GBK 数据),照样被绕过。
常见错误现象:
- 代码里混用
addslashes()和预处理——多此一举还可能破坏二进制数据(比如上传的图片内容) - 用
mysql_*函数(如mysql_query())+mysql_real_escape_string()组合,PHP 7.0+ 已彻底移除,运行直接报错Fatal error: Uncaught Error: Call to undefined function mysql_query() - 以为 magic_quotes_gpc 开启就能高枕无忧——该配置 PHP 5.4 就已废弃,现代环境默认关,且它只作用于 $_GET/$_POST/$_COOKIE,漏掉 $_SERVER、文件名、JSON 解析结果等大量入口
参数类型要对得上,否则绑定失效
预处理不是挂了占位符就万事大吉。bind_param() 的类型标识符(i/s/d/b)必须和实际数据匹配,否则 MySQL 可能静默转成字符串,导致索引失效或比较逻辑出错。
使用场景与参数差异:
- 整数 ID 查询:
bind_param('i', $id)—— 用i,别用s,否则WHERE id = '123'可能无法走索引 - 浮点金额:
bind_param('d', $price)——d确保按 double 解析,避免科学计数法字符串被截断 - 二进制内容(如加密盐值):
bind_param('b', $blob)——b传PDO::PARAM_LOB对象,防止编码污染 - 字符串搜索:
bind_param('s', $keyword)—— 注意s不代表“安全”,只是告诉驱动按字符串传,防注入靠的是预处理机制本身
ORM 框架也不能自动免疫 SQL 注入
像 Laravel Eloquent、ThinkPHP QueryBuilder 这类 ORM,底层仍是调用 PDO::prepare()。但开发者一写原生查询(DB::select("SELECT * FROM users WHERE name = '$name'"))或拼接 whereRaw(whereRaw("status = $_GET['status']")),防线立刻崩塌。
容易踩的坑:
- 在
orderBy()、groupBy()里直接插变量:orderBy($_GET['sort'])—— 必须白名单过滤:in_array($sort, ['created_at', 'updated_at'], true) ? $sort : 'id' - 用
find()或first()时传入数组,误以为安全,其实如果数组键名来自用户输入(如[$request->input('field') => $value]),可能触发非预期字段查询 - 迁移文件里写
DB::statement("CREATE TABLE {$table} ...")—— 表名不能由用户控制,必须硬编码或严格校验正则/^[a-zA-Z_][a-zA-Z0-9_]*$/
防注入没银弹,核心就一条:任何用户可控的数据,进 SQL 前必须经过预处理参数绑定。别的都是补丁,而且补丁还常有漏洞。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











