
本文详解如何通过 sql `like` 操作符配合通配符(`%`)实现关键词“包含式”模糊搜索,并强调使用预处理语句防范 sql 注入,确保从 products 表中准确查出如输入 "shirt" 时返回 "shirt"、"t-shirt"、"short shirt" 等所有相关记录。
在实际开发中,用户搜索“shirt”时,期望结果不仅限于完全匹配的记录,而应涵盖所有产品名称中包含该字符串的条目(如 "T-shirt"、"cotton shirt"、"dress shirt")。但原始代码中:
$thin = $_POST['stxt']; $thing = strtoupper($thin); $sql = "SELECT * FROM products WHERE UPPER(productName) LIKE '$thing'";
存在两个关键问题:
- 缺少通配符:LIKE 'SHIRT' 等价于精确匹配,等同于 = 'SHIRT',无法实现“包含”语义;
- 严重安全风险:直接拼接用户输入($thing)到 SQL 字符串中,极易引发 SQL 注入攻击(例如提交 shirt' OR '1'='1 可导致全表泄露)。
✅ 正确做法是:
- 在 LIKE 模式中使用 % 通配符包裹关键词,表示“任意前缀 + 关键词 + 任意后缀”;
- 统一转换大小写(推荐在数据库层用 UPPER() 或 LOWER()),并确保通配符参与比较;
- 必须使用预处理语句(Prepared Statements) 替代字符串拼接,从根本上阻断注入。
以下是安全、可运行的改进示例(基于 PDO):
<?php
$thin = $_POST['stxt'] ?? '';
if (empty($thin)) {
die("搜索关键词不能为空");
}
// 使用 PDO 预处理(推荐)
try {
$pdo = new PDO("mysql:host=localhost;dbname=your_db", $user, $pass);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
// 构建带通配符的模式:'%SHIRT%',并在 SQL 中统一转大写
$pattern = '%' . strtoupper($thin) . '%';
$stmt = $pdo->prepare("SELECT * FROM products WHERE UPPER(productName) LIKE ?");
$stmt->execute([$pattern]);
$results = $stmt->fetchAll(PDO::FETCH_ASSOC);
foreach ($results as $row) {
echo htmlspecialchars($row['productName']) . "<br>";
}
} catch (PDOException $e) {
error_log("SQL Error: " . $e->getMessage());
echo "搜索失败,请稍后重试。";
}
?>? 关键要点说明:
- LIKE ? 中的问号由 execute([$pattern]) 安全绑定,数据库引擎会将 $pattern 视为纯值而非可执行 SQL;
- 通配符 % 必须在 PHP 层添加(如 '%'.$keyword.'%'),不可写在 SQL 字符串里(如 "LIKE '%?%'" 是错误的,会导致语法错误或逻辑失效);
- 若需“左匹配”(以关键词开头),用 '%$keyword';“右匹配”(以关键词结尾),用 '$keyword%';
- 避免使用 mysql_* 函数(已废弃),优先选用 PDO 或 MySQLi 的预处理接口。
⚠️ 额外建议:
- 对用户输入做基础过滤(如 trim()、htmlspecialchars() 用于输出,但不用于 SQL 过滤——预处理已足够);
- 考虑添加 LIMIT 防止海量结果拖慢响应;
- 如搜索量大,建议为 UPPER(productName) 建函数索引(MySQL 8.0+ 支持)或添加生成列索引提升性能。
掌握 LIKE 与预处理的组合应用,既能满足灵活的模糊检索需求,又能筑牢 Web 应用的数据安全防线。










