分页与关键词高亮必须分离:分页由数据库层paginate()完成,高亮须在视图层或模型获取器中处理;sql层无法安全实现高亮,因replace()不识别词边界、易污染html标签、不支持大小写不敏感匹配,且破坏count(*)统计与分页上下文。

搜索结果页的分页与关键词高亮必须拆开做:分页由 paginate() 在数据库层完成,高亮必须在视图层或模型获取器中处理,两者不能混进 SQL 里。
为什么不能在 SQL 层做高亮
MySQL 的 REPLACE() 或字符串拼接无法识别词边界、无法避开 HTML 标签、不防属性值污染,更没法做大小写不敏感匹配。一旦字段含 <div class="title">PHP</div>,str_replace('PHP', '<em>PHP</em>', ...) 会变成 <div class="<em>PHP</em>"><em>PHP</em></div>,页面直接解析失败。
还有两个硬伤:
-
COUNT(*)和高亮后字段长度/结构无关,但若你在 SQL 里做了替换再 COUNT,总数统计就失真 - 分页对象
$list->render()依赖原始查询上下文,SQL 层掺入 HTML 字符串会让分页链接生成异常甚至报错
正确做法:用获取器(accessor)封装高亮逻辑
在模型中定义只读获取器,比如 getHighlightTitleAttr(),它只负责渲染,不修改原始字段,也不影响持久化。
关键点:
- 先用
preg_quote($keyword, '/')转义关键词中的正则元字符(如+、.、[) - 用
preg_replace()匹配「纯文本区域」,正则建议写成/([^>]*?)(' . $escapedKeyword . ')(?=[^,避免跨标签匹配 - 多关键词时,不要循环调用
preg_replace,改用数组批量:preg_replace('/(' . implode('|', $escapedKeywords) . ')/i', '<em>$1</em>', $text) - 务必检查原始字段是否为空或为 null,避免
Warning: preg_replace(): Parameter mismatch
示例(模型内):
public function getHighlightTitleAttr($value, $data)
{
$keyword = request()->param('keyword', '');
if (empty($keyword) || empty($data['title'])) {
return $data['title'];
}
$escaped = preg_quote($keyword, '/');
return preg_replace('/(' . $escaped . ')/i', '<em>$1</em>', $data['title']);
}
分页参数必须显式透传,否则翻页丢失搜索条件
paginate() 默认只读 $_GET['page'],不会自动带 keyword 这类搜索参数。点击第2页时 URL 变成 ?page=2,关键词没了。
必须用 'query' 参数手动塞进去:
- 控制器里调用要写全:
->paginate(10, false, ['query' => ['keyword' => $keyword]]) - 漏掉
false会导致 page 被重复解析,翻页跳转错乱(比如点第3页却跳到第1页) - 如果还支持每页条数切换(如
size=20),也要一并加进 query:['query' => ['keyword' => $keyword, 'size' => $size]]
视图中渲染分页链接时,直接用 $list->render() 即可,它会自动拼上 query 参数。
高亮后的 <em></em> 标签需要基础样式和 XSS 防御
<em></em> 语义正确、零样式侵入,但默认无颜色/背景,用户看不到高亮效果。
至少加一行 CSS:
em { background-color: #fff9c4; font-style: normal; }
更重要的是 XSS 风险:
- 关键词来自用户输入,必须过
htmlspecialchars()再进正则替换(或确保前端已过滤) - 字段内容本身如果是富文本,且未过滤就入库,高亮时可能把
<script></script>一起包进<em></em>—— 渲染即执行 - 稳妥做法:高亮前对字段内容也做一次
htmlspecialchars($content, ENT_QUOTES, 'UTF-8'),再替换关键词
复杂业务里,高亮不是“加个 <em></em>”就完事;它是视图层职责,得防标签、防脚本、防嵌套、防空值,一步不到位,轻则样式错乱,重则页面崩溃或安全漏洞。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











