根本原因是特殊字符破坏SQL语法结构,应使用参数化查询(MySQLi的prepare/bind_param或PDO的prepare/execute);addslashes()因不兼容字符集和SQL方言而不可靠;PDO需设utf8mb4、显式传null类型、LIKE通配符须手动转义。

PHP中SQL查询里的单引号、反斜杠怎么不出错
直接拼接字符串进SQL语句,遇到用户输入的 '、\、" 就会报错或被注入。根本原因不是“字符特殊”,而是这些字符破坏了SQL语法结构——比如 O'Reilly 会让MySQL把 O' 当成字符串开头,后面没闭合就报错。
最稳妥的做法是不手动转义,改用参数化查询:
- MySQLi:用
prepare()+bind_param() - PDO:用
prepare()+execute()(传数组) - 绝对不要用已废弃的
mysql_real_escape_string()
如果非得用字符串拼接(比如动态表名/字段名不能参数化),才考虑 mysqli_real_escape_string(),且必须在建立连接后调用,否则返回 false。
为什么addslashes()不能用于SQL安全防护
addslashes() 只加反斜杠,不考虑当前连接的字符集和SQL方言,对多字节编码(如GBK)存在绕过风险。它设计初衷是处理PHP字符串输出到HTML或文件,不是防SQL注入。
立即学习“PHP免费学习笔记(深入)”;
典型失败场景:
- 数据库连接用
SET NAMES gbk,而addslashes()不识别该上下文 - 输入为
%A1%AA(GBK编码的′),可能被MySQL误解析为单引号 - PostgreSQL、SQLite 等不认
\'这种转义形式
换句话说:addslashes() 和 SQL 安全之间没有可靠映射关系。
PDO预处理时中文、emoji、null值怎么传
PDO默认把所有绑定参数当字符串处理,但实际类型会影响结果。比如时间字段传字符串可能触发隐式转换,null 值需显式声明类型,emoji需要utf8mb4支持。
关键点:
- 连接DSN里加上
;charset=utf8mb4,建表也用CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci - 绑定
null用PDO::PARAM_NULL,例如$stmt->bindValue(':name', null, PDO::PARAM_NULL) - 日期类字段优先传
PDO::PARAM_STR并确保格式为'Y-m-d H:i:s',避免依赖MySQL自动转换 - 二进制数据(如图片)用
PDO::PARAM_LOB,配合PDO::ATTR_EMULATE_PREPARES => false
WHERE条件里LIKE匹配带%和_怎么办
% 和 _ 是LIKE的通配符,不是SQL语法字符,所以参数化查询不会自动转义它们——你得自己控制。
两种常用方式:
- 用ESCAPE指定转义符,例如
WHERE name LIKE ? ESCAPE '\',然后绑定值前用str_replace(['\\', '%', '_'], ['\\\\', '\%', '\_'], $input) - 改用正则(MySQL 8.0+)或全文索引,避开LIKE的语义歧义
注意:PDO的 quote() 方法不处理LIKE转义,它只做SQL字符串包裹,别混用。
真正难的不是转义字符,而是分清哪些要由SQL引擎解析(如引号)、哪些由查询逻辑解析(如LIKE通配符)、哪些根本不能进SQL(如表名)。一锅炖就容易漏。











