用 preg_replace 实现关键词高亮需先转义用户输入(preg_quote($keyword, ‘/’)),加 i 修饰符不区分大小写,用 ‘$0’ 替换;须先 htmlspecialchars 原文防 xss,再替换 mark 标签;中文注意全角/半角空格统一处理。

用 preg_replace 实现关键词高亮最直接
核心思路是把搜索词当作正则模式,用 preg_replace 替换为带 HTML 标签的高亮内容。注意必须转义用户输入,否则特殊字符(如 .、+、[)会破坏正则匹配甚至引发错误。
实操建议:
- 用
preg_quote($keyword, '/')转义关键词,斜杠/是正则分隔符,必须传入第二个参数 - 加
i修饰符实现不区分大小写匹配:/'.preg_quote($keyword, '/').'/'.'i' - 替换时用
'$0',$0表示完整匹配项,比捕获组更安全 - 若需高亮多个词,逐个循环调用
preg_replace,不要拼成一个正则——容易冲突且难以调试
为什么不用 str_replace 直接替换
str_replace 看似简单,但对大小写敏感、不支持模糊匹配、无法处理重叠关键词(比如搜索 php 和 phpstorm 同时存在时),而且容易误替换 HTML 标签里的内容(如
php)。 更关键的是:如果用户搜的是 a+b,str_replace 会原样去字符串里找 a+b,而实际想匹配的是字面量 a+b,不是正则含义的“a 后跟一个或多个 b”。这时候不转义就出错,转义又得自己模拟正则逻辑——不如直接上 preg_replace。
立即学习“PHP免费学习笔记(深入)”;
防止 XSS 的关键一步:输出前必须过滤
高亮后的内容含 标签,如果原始文本来自用户输入(比如数据库读出的评论),直接 echo 会有 XSS 风险。不能只依赖高亮函数做防护。
正确做法:
- 先用
htmlspecialchars($text, ENT_QUOTES, 'UTF-8')对原文转义 - 再对转义后的字符串执行高亮(此时
变成zuojiankuohaophpcn,不会被解析为标签) - 最后用
str_replace把zuojiankuohaophpcnmarkyoujiankuohaophpcn和zuojiankuohaophpcn/markyoujiankuohaophpcn换回真实标签——仅限这组标签,其他仍保持转义
漏掉这步,攻击者在搜索框输入 就可能触发脚本执行。
中文搜索高亮要注意全角/半角和空格
中文用户常混用全角空格( )、半角空格( )、甚至不间断空格( )。如果关键词含空格,而原文用的是全角空格,preg_replace 默认不匹配。
解决方法:
- 预处理关键词和原文:用
str_replace([' ', "xc2xa0"], ' ', $str)统一为空格(xc2xa0是 UTF-8 下 的字节) - 或改用
mb_ereg_replace(需开启 mbstring)配合u修饰符,但性能略低,且 PHP 8.2+ 已废弃mb_ereg_*系列 - 更稳妥的是前端限制输入:用 js 过滤掉全角符号,或提示“请使用英文标点与空格”
真正难处理的是拼音缩写、同音词、繁简混输——那已超出高亮范畴,得上分词或 nlp 库了。