內容審核系統核心需求:**敏感詞替換**、**敏感詞檢測**、**白名單保護**(如「曹操」不應被「操」過濾)。本文提供生產級 `StrFilter` 類,支持自定義替換字符、白名單/黑名單數組、大小寫不敏感擴展。
<?php
/**
* 敏感詞過濾器
* 支持:黑名單替換、白名單保護、敏感詞檢測
*/
class StrFilter {
private $_whiteList = []; // 白名單 [關鍵詞 => 替換佔位符]
private $_blackList = []; // 黑名單關鍵詞數組
private $_replacement = '*'; // 替換字符
private $_lTag = '[[##'; // 白名單保護左標記
private $_rTag = '##]]'; // 白名單保護右標記
public function __construct(array $whiteList = [], array $blackList = [], string $replacement = '*') {
$this->_whiteList = $whiteList;
$this->_blackList = $blackList;
$this->_replacement = $replacement;
}
/**
* 替換敏感詞
* @param string $content 待處理內容
* @return string 處理後內容
*/
public function replace(string $content): string {
if (empty($content)) return '';
// 1. 保護白名單:將白名單詞替換為唯一標記
$content = $this->_protectWhiteList($content);
// 2. 替換黑名單
if ($this->_blackList) {
foreach ($this->_blackList as $word) {
$content = str_ireplace($word, $this->_replacement, $content); // 不區分大小寫
}
}
// 3. 還原白名單
$content = $this->_restoreWhiteList($content);
return $content;
}
/**
* 檢測是否包含敏感詞
* @param string $content
* @return bool true=無敏感詞/通過, false=包含敏感詞
*/
public function check(string $content): bool {
if (empty($content)) return true;
$content = $this->_protectWhiteList($content);
if ($this->_blackList) {
foreach ($this->_blackList as $word) {
if (stripos($content, $word) !== false) { // 不區分大小寫檢測
return false;
}
}
}
return true;
}
// 白名單保護:替換為唯一標記
private function _protectWhiteList(string $content): string {
if ($this->_whiteList) {
foreach ($this->_whiteList as $key => $word) {
$content = str_ireplace($word, $this->_lTag . $key . $this->_rTag, $content);
}
}
return $content;
}
// 白名單還原:將標記替換回原詞
private function _restoreWhiteList(string $content): string {
if ($this->_whiteList) {
$content = preg_replace_callback(
'/' . preg_quote($this->_lTag, '/') . '(.*?)' . preg_quote($this->_rTag, '/') . '/s',
function ($matches) {
$key = $matches[1];
return isset($this->_whiteList[$key]) ? $this->_whiteList[$key] : '';
},
$content
);
}
return $content;
}
}
?>
<?php
require_once 'StrFilter.php';
// 白名單:受保護詞 (key 為內部標識,value 為實際詞)
$whiteList = [
'caocao' => '曹操',
'diao_si' => '屌絲', // 自定義 key 避免衝突
];
// 黑名單:敏感詞
$blackList = ['屌', '操', '傻逼', '垃圾'];
$content = "我操,曹操你是屌絲,我屌你啊,傻逼垃圾";
$filter = new StrFilter($whiteList, $blackList, '**');
// 替換測試
echo "原文: $content\n";
echo "替換後: " . $filter->replace($content) . "\n";
// 輸出: 我**,曹操你是屌絲,我**你啊,******
// 檢測測試
$clean = "今天天氣不錯";
$dirty = "這是垃圾內容";
echo "正常內容檢測: " . ($filter->check($clean) ? '通過' : '不通過') . "\n"; // 通過
echo "敏感內容檢測: " . ($filter->check($dirty) ? '通過' : '不通過') . "\n"; // 不通過
?>
原文: "我操,曹操你是屌絲"
↓
1. 白名單保護: "我操,[[##caocao##]]你是[[##diao_si##]]"
↓
2. 黑名單替換: "我**,[[##caocao##]]你是[[##diao_si##]]"
↓
3. 白名單還原: "我**,曹操你是屌絲"
↓
結果: "我**,曹操你是屌絲" ✓ 白名單詞未被破壞
| 優化方向 | 方案 | 適用場景 |
|---|---|---|
| 超大黑名單 (10萬+) | 構建 Trie 字典樹 (前綴樹) / Aho-Corasick 自動機 | 高頻內容審核、實時過濾 |
| 多語言/繁簡體 | 引入 opencc 繁簡轉換,統一編碼後過濾 | 港台/海外業務 |
| 變體詞 (如 "傻*逼", "S B") | 正則預處理 + 字符標準化 (全角轉半角、去特殊符號) | 對抗式內容審核 |
| 分布式服務化 | 封裝為 gRPC/HTTP 微服務,支持熱更新詞庫 | 多業務線複用 |
| 性能極致 | C/C++ 擴展 (php-extension) 或 Swoole 協程異步處理 | 億級日請求 |
composer require wujunze/badwords`StrFilter` 類通過**白名單標記保護 → 黑名單替換/檢測 → 白名單還原**三步驟,優雅解決了「誤傷合法詞」的經典問題。代碼結構清晰、易擴展,適合中小項目直接集成。大規模、高併發、對抗性強的場景,建議遷移至 Trie 樹 / Aho-Corasick 算法實現或成熟開源庫/微服務。