內容審核系統的核心需求是敏感詞過濾。本文提供兩種 PHP 實作方案:方案一:逐詞 strpos 遍歷(簡單、適合中小詞庫)、方案二:合併正則單次匹配(高效、適合大詞庫),並解析編碼陷阱、效能優化與擴展建議。
關鍵字儲存於 keyWords.txt,每行一詞,UTF-8 編碼。
function keyWordCheck(string $content): string|false {
$content = trim($content);
$file = __DIR__ . '/keyWords.txt';
if (!is_readable($file)) return false;
$words = file($file, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
foreach ($words as $word) {
$word = trim($word);
if ($word === '') continue;
// stripos 大小寫不敏感;mb_strpos 支援多位元組
if (mb_strpos($content, $word) !== false) {
return $word; // 返回首個命中的敏感詞
}
}
return false;
}
// 使用
$text = '這裡是要發布的文本內容。。。';
if ($bad = keyWordCheck($text)) {
echo "內容包含敏感詞:$bad";
} else {
echo "通過檢測,可入庫";
}
將所有敏感詞以 | 連接成一個巨大正則,**一次掃描**即可檢測所有詞彙,效能遠優於逐詞循環。
function banwordCheck(string $string, string $fileName): bool {
$pattern = @file_get_contents($fileName);
if ($pattern === false) die('敏感詞檔案讀取失敗');
// 檔案內容已為 "詞1|詞2|詞3" 格式,或每行一詞需自行 implode('|', $arr)
// 加上邊界修飾詞防止部分匹配誤傷(視需求)
$regex = '/' . $pattern . '/iu'; // i=不分大小寫, u=UTF-8
return (bool)preg_match($regex, $string);
}
// 敏感詞檔 banwords.txt 內容範例:
// 賭博|色情|暴力|敏感詞4|敏感詞5
// 使用
$content = '測試關鍵字';
if (banwordCheck($content, __DIR__ . '/banwords.txt')) {
echo "命中敏感詞";
} else {
echo "未命中";
}
| 指標 | strpos 遍歷 | 合併正則 |
|---|---|---|
| 詞庫規模 | < 5,000 詞 | > 5,000 詞(可達 10 萬+) |
| 單次檢測時間 | O(N × L) 線性增長 | O(L) 單次掃描,N 為詞數,L 為文本長度 |
| 記憶體佔用 | 低 | 中(正則編譯緩存) |
| 維護難度 | 低(純文字檔) | 中(需處理正則元字元轉義) |
| 支援邊界/詞性 | 困難 | 可透過 \b, (?<!\w) 等實現 |
. * + ? [ ] ( ) { } | ^ $ \ 等,合併正則前**必須** preg_quote($word, '/') 轉義,否則導致正則語法錯誤或匹配異常。/u 修飾符強制 PCRE 以 UTF-8 模式運作,避免多位元組字元被拆分匹配。/\b(?:詞1|詞2)\b/u(中文詞邊界較複雜,建議引入分詞庫)(a+)+)。敏感詞正則純交替 A|B|C 安全,但若詞庫極大(>5 萬),PCRE 編譯/匹配可能超時,需分塊或改用 Aho-Corasick 自動機(PHP 擴展 php-aho-corasick 或純 PHP 實現)。preg_replace_callback 可將命中詞替換為 ***、<mark>$0</mark> 或記錄位置。class ContentFilter {
public function filter(string $text): array {
$result = ['clean' => $text, 'hits' => [], 'level' => 'pass'];
// 1. 快速正則檢測(高危詞)
if ($this->regexHighRisk->match($text)) {
$result['level'] = 'reject';
return $result;
}
// 2. Aho-Corasick 多模式匹配(通用詞庫)
$hits = $this->acAutomaton->search($text);
if ($hits) {
$result['hits'] = $hits;
$result['level'] = 'review';
$result['clean'] = $this->mask($text, $hits);
}
return $result;
}
}
中小專案用 strpos 遍歷足夠;大流量、大詞庫**必須**用合併正則或 Aho-Corasick 自動機。核心鐵律:**UTF-8 全鏈路、元字元轉義、短詞誤傷防範、效能基準測試**。建議引入成熟庫(如 phpsensitive, htmlpurifier 內建過濾)而非重造輪子。