PHPAPI敏感词过滤怎么实现

wen PHP项目 15

本文目录导读:

PHPAPI敏感词过滤怎么实现

  1. 基于数组的简单匹配(适合少量敏感词)
  2. 基于Trie树的高效方案(推荐)
  3. 基于正则表达式(适合模式匹配)
  4. API集成方案
  5. 优化建议
  6. 使用建议

在PHP中实现API敏感词过滤,常见的方法包括基于数组的匹配基于Trie树的匹配等,以下是几种常见的实现方式,从简单到高效:

基于数组的简单匹配(适合少量敏感词)

class SensitiveFilter {
    private $sensitiveWords = ['敏感词1', '敏感词2', '敏感词3'];
    public function filter($text, $replaceChar = '*') {
        foreach ($this->sensitiveWords as $word) {
            $text = str_replace($word, str_repeat($replaceChar, mb_strlen($word)), $text);
        }
        return $text;
    }
    public function contains($text) {
        foreach ($this->sensitiveWords as $word) {
            if (mb_strpos($text, $word) !== false) {
                return true;
            }
        }
        return false;
    }
}
// 使用示例
$filter = new SensitiveFilter();
$text = "这是一个包含敏感词1的文本";
$filtered = $filter->filter($text);

基于Trie树的高效方案(推荐)

class TrieNode {
    public $children = [];
    public $isEnd = false;
}
class SensitiveFilterTrie {
    private $root;
    private $sensitiveWords = [];
    public function __construct() {
        $this->root = new TrieNode();
    }
    /**
     * 加载敏感词列表
     */
    public function loadWords(array $words) {
        $this->sensitiveWords = $words;
        foreach ($words as $word) {
            $this->addWord($word);
        }
    }
    /**
     * 添加单个敏感词到Trie树
     */
    private function addWord($word) {
        $node = $this->root;
        $len = mb_strlen($word);
        for ($i = 0; $i < $len; $i++) {
            $char = mb_substr($word, $i, 1);
            if (!isset($node->children[$char])) {
                $node->children[$char] = new TrieNode();
            }
            $node = $node->children[$char];
        }
        $node->isEnd = true;
    }
    /**
     * 检测文本是否包含敏感词
     */
    public function contains($text) {
        $len = mb_strlen($text);
        for ($i = 0; $i < $len; $i++) {
            $node = $this->root;
            for ($j = $i; $j < $len; $j++) {
                $char = mb_substr($text, $j, 1);
                if (!isset($node->children[$char])) {
                    break;
                }
                $node = $node->children[$char];
                if ($node->isEnd) {
                    return true;
                }
            }
        }
        return false;
    }
    /**
     * 过滤敏感词
     */
    public function filter($text, $replaceChar = '*') {
        $len = mb_strlen($text);
        $result = [];
        $foundWords = [];
        for ($i = 0; $i < $len; $i++) {
            $node = $this->root;
            $wordStart = $i;
            for ($j = $i; $j < $len; $j++) {
                $char = mb_substr($text, $j, 1);
                if (!isset($node->children[$char])) {
                    break;
                }
                $node = $node->children[$char];
                if ($node->isEnd) {
                    $wordLen = $j - $i + 1;
                    $result[] = str_repeat($replaceChar, $wordLen);
                    $i = $j;
                    $foundWords[] = mb_substr($text, $wordStart, $wordLen);
                    continue 2;
                }
            }
            $result[] = mb_substr($text, $i, 1);
        }
        return implode('', $result);
    }
    /**
     * 获取所有匹配的敏感词
     */
    public function getFoundWords($text) {
        $foundWords = [];
        $len = mb_strlen($text);
        for ($i = 0; $i < $len; $i++) {
            $node = $this->root;
            for ($j = $i; $j < $len; $j++) {
                $char = mb_substr($text, $j, 1);
                if (!isset($node->children[$char])) {
                    break;
                }
                $node = $node->children[$char];
                if ($node->isEnd) {
                    $foundWords[] = mb_substr($text, $i, $j - $i + 1);
                    $i = $j;
                    break;
                }
            }
        }
        return array_unique($foundWords);
    }
}
// 使用示例
$filter = new SensitiveFilterTrie();
$filter->loadWords(['敏感词1', '敏感词2', '敏感词3', '测试']);
$text = "这是一个包含敏感词1和测试的文本";
echo "是否包含敏感词: " . ($filter->contains($text) ? '是' : '否') . "\n";
echo "过滤后: " . $filter->filter($text) . "\n";
echo "发现的敏感词: " . implode(', ', $filter->getFoundWords($text));

基于正则表达式(适合模式匹配)

class SensitiveFilterRegex {
    private $pattern;
    public function __construct(array $words) {
        // 对敏感词进行转义并构建正则
        $escaped = array_map('preg_quote', $words);
        $this->pattern = '/(' . implode('|', $escaped) . ')/u';
    }
    public function filter($text, $replaceChar = '*') {
        return preg_replace_callback($this->pattern, function($matches) use ($replaceChar) {
            return str_repeat($replaceChar, mb_strlen($matches[0]));
        }, $text);
    }
    public function contains($text) {
        return (bool) preg_match($this->pattern, $text);
    }
}
// 使用示例
$filter = new SensitiveFilterRegex(['敏感词1', '敏感词2']);
echo $filter->filter("包含敏感词1的文本");

API集成方案

<?php
header('Content-Type: application/json; charset=utf-8');
require_once 'SensitiveFilterTrie.php'; // 包含上面的类
class SensitiveAPI {
    private $filter;
    public function __construct() {
        $this->filter = new SensitiveFilterTrie();
        // 从文件或数据库加载敏感词
        $this->loadSensitiveWords();
    }
    private function loadSensitiveWords() {
        // 方式1: 从文件加载
        $words = file('sensitive_words.txt', FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
        // 方式2: 从数据库加载
        // $words = $this->getFromDatabase();
        $this->filter->loadWords($words);
    }
    public function handleRequest() {
        $method = $_SERVER['REQUEST_METHOD'];
        $input = json_decode(file_get_contents('php://input'), true);
        switch ($method) {
            case 'POST':
                if (isset($input['text'])) {
                    $text = $input['text'];
                    $action = isset($input['action']) ? $input['action'] : 'filter';
                    switch ($action) {
                        case 'check':
                            $result = [
                                'contains' => $this->filter->contains($text),
                                'found_words' => $this->filter->getFoundWords($text)
                            ];
                            break;
                        case 'filter':
                        default:
                            $result = [
                                'original' => $text,
                                'filtered' => $this->filter->filter($text, 
                                    isset($input['replace_char']) ? $input['replace_char'] : '*'),
                                'found_words' => $this->filter->getFoundWords($text)
                            ];
                            break;
                    }
                    $this->response(200, $result);
                } else {
                    $this->response(400, ['error' => 'Missing text parameter']);
                }
                break;
            default:
                $this->response(405, ['error' => 'Method not allowed']);
        }
    }
    private function response($code, $data) {
        http_response_code($code);
        echo json_encode($data, JSON_UNESCAPED_UNICODE);
        exit;
    }
}
// 使用
$api = new SensitiveAPI();
$api->handleRequest();

优化建议

// 1. 缓存敏感词树到文件
class CachedSensitiveFilter extends SensitiveFilterTrie {
    private $cacheFile = 'sensitive_tree.cache';
    public function loadWords(array $words) {
        // 检查缓存
        if (file_exists($this->cacheFile) && 
            filemtime($this->cacheFile) > $this->getLastModifyTime()) {
            $this->root = unserialize(file_get_contents($this->cacheFile));
        } else {
            parent::loadWords($words);
            // 保存缓存
            file_put_contents($this->cacheFile, serialize($this->root));
        }
    }
    private function getLastModifyTime() {
        // 返回敏感词列表的最后修改时间
    }
}
// 2. 使用Redis缓存
class RedisSensitiveFilter extends SensitiveFilterTrie {
    private $redis;
    private $cacheKey = 'sensitive_filter_tree';
    public function loadWords(array $words) {
        $cached = $this->redis->get($this->cacheKey);
        if ($cached) {
            $this->root = unserialize($cached);
        } else {
            parent::loadWords($words);
            $this->redis->set($this->cacheKey, serialize($this->root));
        }
    }
}

使用建议

  1. 性能优先:使用Trie树实现,时间复杂度O(n*m),n为文本长度,m为敏感词平均长度
  2. 更新便利:敏感词从数据库或文件加载,支持热更新
  3. 批量处理:支持批量API请求
  4. 错误处理:添加适当的异常处理
  5. 编码处理:注意UTF-8编码的多字节字符处理

选择哪种方案取决于你的具体需求:简单场景用数组匹配,高性能场景用Trie树,模式匹配复杂用正则。

抱歉,评论功能暂时关闭!