codeigniter需自行实现敏感词过滤,推荐辅助函数+正则/dfa双方案:strtr()适合小词库但无边界控制,生产环境应结合词边界正则或dfa算法,并在中间件与模型层双重校验。

CodeIgniter 本身不内置敏感词过滤系统,但可以通过轻量级辅助函数快速实现基础替换,或结合会话、过滤器、模型层构建更可控的检测流程。直接用 strtr() 做关键词映射最简单,但生产环境必须注意匹配粒度、大小写、边界控制和性能开销。
怎么用辅助函数实现基础敏感词替换
把过滤逻辑封装成辅助函数(如 filter_helper.php),放在 app/Helpers/(CI4)或 application/helpers/(CI3)下,再通过 $this->load->helper('filter') 加载即可调用 clean()。
- 关键词数组必须是「完整字符串 → 替换结果」的键值对,
strtr()是逐字符替换,不识别词边界 —— 比如'ass'会把'passion'错替成'p**ion' - 大小写需显式列出:
'Ass'、'ASS'、'ass'都要单独定义,否则漏过滤 - 敏感词数量超过 200 个后,
strtr()性能下降明显,建议改用正则 +preg_replace_callback()或 DFA 算法(需额外引入类) - 示例中
clean($string)不做 trim、不处理 HTML 实体,若输入含<script></script>,得先过$this->security->xss_clean()(CI3)或esc()(CI4)
为什么不能只靠控制器里调 $this->input->post() 的 TRUE 参数
$this->input->post('content', TRUE) 中的 TRUE 只触发 XSS 过滤,跟敏感词无关 —— 它防的是 HTML/JS 注入,不是语义违规词。
- CI3 的
TRUE参数等价于调用$this->security->xss_clean(),仅处理标签、事件属性、JavaScript 协议等 - CI4 已移除
xss_clean(),TRUE改为启用全局输出转义(esc()),仍不碰词汇表 - 若把敏感词过滤塞进 POST 处理环节,容易遗漏 AJAX 提交、API 接口、后台导入等非表单路径
- 真正需要统一拦截的场景(如所有用户评论),应抽离为独立服务类,而非耦合在输入方法里
如何让敏感词检测支持上下文与最小匹配
纯字符串替换无法满足「仅匹配独立词汇」或「跳过已脱敏内容」的需求,此时需切换为正则方案,并控制匹配方式。
- 用
\b匹配词边界:preg_replace('/\b(shit)\b/i', 's**t', $text),避免污染单词内部 - 区分最小/最大匹配:DFA 算法中最小匹配(minMatchType=1)优先命中短词,最大匹配(maxMatchType=2)优先长词 —— 如同时有
'中国'和'中国人',后者应优先生效 - CI4 中可将 DFA 类放入
app/Libraries/,构造时传入词库文件路径,避免每次请求都读取words.txt - 注意:正则在大文本中多次执行会变慢,建议对长度 > 500 字符的输入加缓存或异步队列处理
敏感词过滤该放在哪一层才不容易被绕过
过滤位置决定安全水位:仅在视图层显示前处理,等于没防;只在模型保存前校验,可能被 API 直接绕过;最佳实践是「入口处拦截 + 存储前加固」双保险。
- CI4 推荐在中间件(Filter)中调用检测逻辑,比如自定义
ContentFilter,对/api/comment路由强制执行WordFilter::replaceWords() - 数据库写入前,模型层再跑一次(防止绕过前端/Filter),并记录原始内容与过滤日志,便于审计
- 绝对不要依赖前端 JS 过滤 —— 用户禁用 JS 或抓包重放就能跳过
- 若使用 CI4 的 Validation,可扩展自定义规则:
'content' => 'required|no_sensitive_words',并在app/Validation/Rules.php中实现no_sensitive_words()
真正难的不是写一个 clean() 函数,而是确定哪些词算敏感、是否区分场景(客服对话 vs 公告栏)、是否需要人工复核、以及被过滤后要不要通知运营 —— 这些业务逻辑一旦硬编码进辅助函数,后期就很难解耦。建议把词库、替换策略、审核流拆成配置驱动,而不是堆在 PHP 数组里。











