本文目录导读:

在PHP项目中处理敏感词过滤,常见的方法有以下几种,从简单到高效:
简单字符串替换(适用于少量敏感词)
function simpleFilter($text, $sensitiveWords) {
foreach ($sensitiveWords as $word) {
$text = str_replace($word, '***', $text);
}
return $text;
}
// 使用示例
$words = ['敏感词1', '敏感词2'];
$text = '这是一段包含敏感词1的文本';
echo simpleFilter($text, $words);
正则表达式过滤(更灵活)
function regexFilter($text, $sensitiveWords) {
$pattern = '/(' . implode('|', array_map('preg_quote', $sensitiveWords)) . ')/u';
return preg_replace($pattern, '***', $text);
}
// 使用示例
$text = '包含敏感词1和敏感词2的文本';
echo regexFilter($text, $words);
高效方案:Trie树(字典树)
这是处理大量敏感词时的最佳方案,适合生产环境:
class SensitiveFilter {
private $trie = [];
// 构建Trie树
public function addWords($words) {
foreach ($words as $word) {
$node = &$this->trie;
$len = mb_strlen($word);
for ($i = 0; $i < $len; $i++) {
$char = mb_substr($word, $i, 1);
if (!isset($node[$char])) {
$node[$char] = [];
}
$node = &$node[$char];
}
$node['end'] = true; // 标记结束
}
}
// 过滤敏感词
public function filter($text, $replaceChar = '*') {
$result = '';
$textLen = mb_strlen($text);
$i = 0;
while ($i < $textLen) {
$match = $this->findMatch($text, $i);
if ($match !== false) {
$result .= str_repeat($replaceChar, mb_strlen($match));
$i += mb_strlen($match);
} else {
$result .= mb_substr($text, $i, 1);
$i++;
}
}
return $result;
}
private function findMatch($text, $start) {
$node = $this->trie;
$match = '';
for ($i = $start; $i < mb_strlen($text); $i++) {
$char = mb_substr($text, $i, 1);
if (!isset($node[$char])) {
return $match ? $match : false;
}
$match .= $char;
$node = $node[$char];
if (isset($node['end'])) {
return $match;
}
}
return false;
}
}
// 使用示例
$filter = new SensitiveFilter();
$filter->addWords(['敏感词1', '敏感词2', '敏感词']);
$text = '这是一段包含敏感词1和敏感词2的文本';
echo $filter->filter($text);
使用扩展库(推荐生产环境)
使用 swoole 扩展(性能最好)
// 安装:pecl install swoole
$filter = new \Swoole\Filter();
$filter->setDict(['敏感词1', '敏感词2']);
$result = $filter->exec('包含敏感词的文本');
使用 trie_filter 扩展
// 安装:pecl install trie_filter
$tree = trie_filter_new();
foreach ($words as $word) {
trie_filter_store($tree, $word);
}
trie_filter_save($tree, 'sensitive.dic');
// 使用时加载
$tree = trie_filter_load('sensitive.dic');
$result = trie_filter_search($tree, '文本内容');
完整的生产环境方案
class SensitiveWordFilter {
private $trie = [];
private $filePath;
public function __construct($filePath = null) {
$this->filePath = $filePath ?: __DIR__ . '/sensitive_words.txt';
$this->loadFromFile();
}
// 从文件加载敏感词
private function loadFromFile() {
if (file_exists($this->filePath)) {
$words = file($this->filePath, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
$this->addWords($words);
}
}
// 添加单个词
public function addWord($word) {
$word = trim($word);
if (empty($word)) return;
$node = &$this->trie;
$len = mb_strlen($word);
for ($i = 0; $i < $len; $i++) {
$char = mb_substr($word, $i, 1);
if (!isset($node[$char])) {
$node[$char] = [];
}
$node = &$node[$char];
}
$node['end'] = true;
}
// 批量添加
public function addWords($words) {
foreach ($words as $word) {
$this->addWord($word);
}
}
// 检查是否包含敏感词
public function containsSensitive($text) {
$textLen = mb_strlen($text);
for ($i = 0; $i < $textLen; $i++) {
$match = $this->findMatch($text, $i);
if ($match !== false) {
return true;
}
}
return false;
}
// MySQL 版本(适合大量数据)
public function saveToDatabase($pdo) {
$words = json_encode($this->trie);
$sql = "INSERT INTO sensitive_config (`type`, `content`) VALUES ('trie', ?)
ON DUPLICATE KEY UPDATE `content` = ?";
$stmt = $pdo->prepare($sql);
$stmt->execute([$words, $words]);
}
// 从数据库加载
public function loadFromDatabase($pdo) {
$sql = "SELECT content FROM sensitive_config WHERE type = 'trie' LIMIT 1";
$stmt = $pdo->query($sql);
$row = $stmt->fetch(PDO::FETCH_ASSOC);
if ($row) {
$this->trie = json_decode($row['content'], true);
}
}
}
// 生产环境使用示例
$filter = new SensitiveWordFilter('/path/to/sensitive_words.txt');
$text = $_POST['content'];
if ($filter->containsSensitive($text)) {
echo json_encode(['code' => 1, 'msg' => '包含敏感词']);
} else {
echo json_encode(['code' => 0, 'msg' => $filter->filter($text)]);
}
最佳实践建议
存储方式
- 小项目:保存在文本文件或数据库配置表中
- 大项目:使用Redis等缓存,减少IO开销
- 分布式:使用配置中心统一管理
性能优化
- 缓存Trie树:序列化后缓存到Redis
- 分片处理:大文本分段过滤
- 异步处理:使用消息队列异步过滤
- 静态化:生成过滤结果,减少实时计算
注意事项
- Unicode处理:使用
mb_*函数处理字符串 - 性能监控:记录过滤耗时,监控异常
- 更新机制:支持热更新敏感词列表
- 多语言支持:处理中英文混合情况
更复杂的场景处理
// 处理变体(如使用特殊字符绕过)
function antiEvasion($text) {
// 替换常见变体
$replacements = [
'/[1lI]/' => 'l', // 1和l的替换
'/[0oO]/' => 'o', // 0和o的替换
'/[@]/' => 'a', // @替换a
'/[\\x{3000}]/u' => '', // 全角空格
];
return preg_replace(array_keys($replacements), array_values($replacements), $text);
}
根据项目规模和性能要求选择合适的方案,建议在开发环境测试后再部署到生产环境。