在 Web 开发中,用户通过表单、评论区或接口提交的文本经常带有单引号、双引号等字符。如果把这些内容直接拼进 SQL 插入语句,MySQL 会把这些引号当成 SQL 语法的一部分,导致语句报错甚至被恶意利用。因此,我们必须用安全的方式把用户文本写入数据库。

为什么直接拼接 SQL 有风险
假设用户昵称叫 O'Brien,若使用下面这种拼接方式:
$name = "O'Brien";
$sql = "INSERT INTO user(name) VALUES('$name')";
// 实际 SQL: INSERT INTO user(name) VALUES('O'Brien')
// 单引号提前闭合,语法错误
更严重的是,攻击者可以输入 ' OR '1'='1 这类内容来篡改逻辑,造成 SQL 注入。
使用预处理语句避免引号问题
预处理语句把 SQL 结构和数据分开发送,数据库会自动转义特殊字符。下面分别展示 PDO 和 mysqli 的写法。
PDO 方式
try {
$pdo = new PDO('mysql:host=127.0.0.1;dbname=test', 'root', 'pass');
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$stmt = $pdo->prepare('INSERT INTO user(name, bio) VALUES(?, ?)');
$name = "O'Brien";
$bio = '他说:"你好"';
$stmt->execute([$name, $bio]);
echo '插入成功';
} catch (PDOException $e) {
echo '错误:' . $e->getMessage();
}
mysqli 方式
$mysqli = new mysqli('127.0.0.1', 'root', 'pass', 'test');
if ($mysqli->connect_error) {
die('连接失败: ' . $mysqli->connect_error);
}
$stmt = $mysqli->prepare('INSERT INTO user(name, bio) VALUES(?, ?)');
$name = "O'Brien";
$bio = '他说:"你好"';
$stmt->bind_param('ss', $name, $bio);
$stmt->execute();
echo '插入成功';
$stmt->close();
$mysqli->close();
不推荐的转义函数用法
早期常用 addslashes() 或 mysql_real_escape_string() 手动转义,但容易因字符集不一致而失效。对比见下表:
| 方式 | 安全性 | 维护成本 |
|---|---|---|
| 字符串拼接 | 低 | 高 |
| 手动转义 | 中 | 中 |
| 预处理语句 | 高 | 低 |
总结
面对含单双引号的用户文本,最安全的做法是使用 PDO 或 mysqli 的预处理语句。它不仅能正确处理引号,还能从根本上防止 SQL 注入。请在项目中统一使用参数化查询,不要手动拼接 SQL 字符串。