Fastadmin中实现敏感词管理

在Fastadmin框架中实现敏感词管理笔记

目录

安装依赖库

创建数据表

设计数据表

插入测试数据

创建模型类

创建公共方法

业务调用

不允许输入敏感词

过滤敏感词

总结


安装依赖库

需要使用overtrue/pinyin依赖库实现中文分词,安装命令:

bash 复制代码
composer require overtrue/pinyin

安装版本如下:

创建数据表

设计数据表
sql 复制代码
CREATE TABLE `fa_sensitive_words` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键 ID',
  `word` varchar(100) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '敏感词内容',
  `category` varchar(50) COLLATE utf8mb4_unicode_ci DEFAULT 'general' COMMENT '敏感词分类:general=通用,politics=政治,porn=色情,violence=暴力,ad=广告',
  `level` tinyint(1) NOT NULL DEFAULT '1' COMMENT '敏感等级:1=低,2=中,3=高',
  `status` tinyint(1) NOT NULL DEFAULT '1' COMMENT '状态:0=禁用,1=启用',
  `replace_char` varchar(10) COLLATE utf8mb4_unicode_ci DEFAULT '*' COMMENT '替换字符,默认*',
  `description` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '备注说明',
  `created_at` datetime NOT NULL COMMENT '创建时间',
  `updated_at` datetime NOT NULL COMMENT '更新时间',
  PRIMARY KEY (`id`) USING BTREE,
  UNIQUE KEY `idx_word_unique` (`word`) USING BTREE,
  KEY `idx_category` (`category`) USING BTREE,
  KEY `idx_status` (`status`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='敏感词库表';
插入测试数据
sql 复制代码
INSERT INTO `fa_sensitive_words` (`id`, `word`, `category`, `level`, `status`, `replace_char`, `description`, `created_at`, `updated_at`) VALUES (1, '敏感词', 'general', 1, 1, '*', '测试敏感词', '2026-04-01 09:00:30', '2026-04-01 09:00:30');
INSERT INTO `fa_sensitive_words` (`id`, `word`, `category`, `level`, `status`, `replace_char`, `description`, `created_at`, `updated_at`) VALUES (2, '广告', 'ad', 2, 1, '*', '广告类敏感词', '2026-04-01 09:00:30', '2026-04-01 09:00:30');
INSERT INTO `fa_sensitive_words` (`id`, `word`, `category`, `level`, `status`, `replace_char`, `description`, `created_at`, `updated_at`) VALUES (3, '暴力', 'violence', 3, 1, '*', '暴力类敏感词', '2026-04-01 09:00:30', '2026-04-01 09:00:30');
INSERT INTO `fa_sensitive_words` (`id`, `word`, `category`, `level`, `status`, `replace_char`, `description`, `created_at`, `updated_at`) VALUES (4, '政治敏感', 'politics', 3, 1, '*', '政治类敏感词', '2026-04-01 09:00:30', '2026-04-01 09:00:30');
INSERT INTO `fa_sensitive_words` (`id`, `word`, `category`, `level`, `status`, `replace_char`, `description`, `created_at`, `updated_at`) VALUES (5, '色情', 'porn', 3, 1, '*', '色情类敏感词', '2026-04-01 09:00:30', '2026-04-01 09:00:30');

创建模型类

在common/model下创建SensitiveWord.php文件,内容如下:

php 复制代码
<?php

namespace app\common\model;

use think\Model;

/**
 * 敏感词模型
 */
class SensitiveWord extends Model
{
    // 设置当前模型对应的完整表名
    protected $name = 'sensitive_words';

    // 定义主键
    protected $pk = 'id';

    // 自动写入时间戳
    protected $autoWriteTimestamp = true;

    // 时间戳字段名
    protected $createTime = 'created_at';
    protected $updateTime = 'updated_at';

    // 字段类型转换
    protected $type = [
        'id'           => 'integer',
        'word'         => 'string',
        'category'     => 'string',
        'level'        => 'integer',
        'status'       => 'integer',
        'replace_char' => 'string',
        'description'  => 'string',
    ];

    // 字段验证规则
    protected $validate = [
        'word'     => 'require|max:100',
        'category' => 'max:50',
        'level'    => 'number|between:1,3',
        'status'   => 'number|in:0,1',
    ];

    // 允许自动填充的字段列表
    protected $insert = ['status' => 1];

    /**
     * 获取所有启用的敏感词列表
     * @return array
     */
    public static function getEnabledWords()
    {
        return self::where('status', 1)
            ->column('word');
    }

    /**
     * 根据分类获取敏感词
     * @param string $category 分类
     * @return array
     */
    public static function getWordsByCategory($category)
    {
        return self::where('status', 1)
            ->where('category', $category)
            ->column('word');
    }

    /**
     * 检查词是否敏感
     * @param string $word 要检查的词
     * @return bool
     */
    public static function isSensitive($word)
    {
        return self::where('status', 1)
            ->where('word', $word)
            ->find() ? true : false;
    }

    /**
     * 添加敏感词
     * @param string $word 敏感词
     * @param string $category 分类
     * @param int $level 等级
     * @param string $description 描述
     * @return bool
     */
    public static function addWord($word, $category = 'general', $level = 1, $description = '')
    {
        $data = [
            'word'        => trim($word),
            'category'    => $category,
            'level'       => $level,
            'description' => $description,
        ];

        $result = self::create($data);
        return $result ? true : false;
    }

    /**
     * 批量添加敏感词
     * @param array $words 敏感词数组
     * @param string $category 分类
     * @return int 成功添加的数量
     */
    public static function addWordsBatch($words, $category = 'general')
    {
        $count = 0;
        foreach ($words as $word) {
            if (self::addWord($word, $category)) {
                $count++;
            }
        }
        return $count;
    }

    /**
     * 删除敏感词
     * @param int $id 敏感词 ID
     * @return bool
     */
    public static function deleteWord($id)
    {
        return self::destroy($id);
    }

    /**
     * 更新敏感词状态
     * @param int $id 敏感词 ID
     * @param int $status 状态
     * @return bool
     */
    public static function updateStatus($id, $status)
    {
        return self::update(['id' => $id, 'status' => $status]);
    }
}

创建公共方法

在application/common.php文件中增加对敏感词的检测、过滤方法,以供全局调用,

内容如下:

php 复制代码
if (!function_exists('filter_sensitive_words')) {

    /**
     * 敏感词过滤函数
     * 对输入内容进行分词,查询敏感词库,若存在则对输入内容进行替换为*处理并返回
     * @param string $content 待过滤的内容
     * @param string $replaceChar 替换字符,默认*
     * @param bool $useCache 是否使用缓存,默认 true
     * @return array 返回过滤后的内容和是否包含敏感词
     */
    function filter_sensitive_words($content, $replaceChar = '*', $useCache = true)
    {
        if (empty($content)) {
            return [
                'content' => $content,
                'has_sensitive' => false,
                'filtered_count' => 0
            ];
        }

        static $sensitiveWordsCache = null;
        
        // 使用缓存获取敏感词列表
        if ($useCache && $sensitiveWordsCache === null) {
            $sensitiveWordsCache = \app\common\model\SensitiveWord::getEnabledWords();
        } elseif (!$useCache) {
            $sensitiveWordsCache = \app\common\model\SensitiveWord::getEnabledWords();
        }

        if (empty($sensitiveWordsCache)) {
            return [
                'content' => $content,
                'has_sensitive' => false,
                'filtered_count' => 0
            ];
        }

        $filteredCount = 0;
        $filteredContent = $content;

        // 按长度降序排序,优先替换长词
        usort($sensitiveWordsCache, function($a, $b) {
            return mb_strlen($b) - mb_strlen($a);
        });

        // 逐个替换敏感词
        foreach ($sensitiveWordsCache as $word) {
            if (mb_stripos($filteredContent, $word) !== false) {
                $replaceStr = str_repeat($replaceChar, mb_strlen($word));
                $filteredContent = str_ireplace($word, $replaceStr, $filteredContent);
                $filteredCount++;
            }
        }

        return [
            'content' => $filteredContent,
            'has_sensitive' => $filteredCount > 0,
            'filtered_count' => $filteredCount
        ];
    }
}

if (!function_exists('check_sensitive_words')) {

    /**
     * 检查内容是否包含敏感词
     * @param string $content 待检查的内容
     * @param bool $useCache 是否使用缓存,默认 true
     * @return array 返回检查结果和敏感词列表
     */
    function check_sensitive_words($content, $useCache = true)
    {
        if (empty($content)) {
            return [
                'has_sensitive' => false,
                'sensitive_words' => []
            ];
        }

        static $sensitiveWordsCache = null;
        
        if ($useCache && $sensitiveWordsCache === null) {
            $sensitiveWordsCache = \app\common\model\SensitiveWord::getEnabledWords();
        } elseif (!$useCache) {
            $sensitiveWordsCache = \app\common\model\SensitiveWord::getEnabledWords();
        }

        if (empty($sensitiveWordsCache)) {
            return [
                'has_sensitive' => false,
                'sensitive_words' => []
            ];
        }

        $foundSensitiveWords = [];
        foreach ($sensitiveWordsCache as $word) {
            if (mb_stripos($content, $word) !== false) {
                $foundSensitiveWords[] = $word;
            }
        }

        return [
            'has_sensitive' => !empty($foundSensitiveWords),
            'sensitive_words' => $foundSensitiveWords
        ];
    }
}

if (!function_exists('segment_text')) {

    /**
     * 对文本进行分词(使用 overtrue/pinyin)
     * @param string $text 待分词的文本
     * @param int $minLength 最小词长度,默认 2
     * @return array 分词结果
     */
    function segment_text($text, $minLength = 2)
    {
        if (empty($text)) {
            return [];
        }

        $pinyin = new \Overtrue\Pinyin\Pinyin();
        $segments = [];
        
        // 移除特殊字符和空白
        $text = preg_replace('/[^\x{4e00}-\x{9fa5}a-zA-Z0-9]/u', ' ', $text);
        $text = preg_replace('/\s+/', ' ', trim($text));
        
        if (empty($text)) {
            return [];
        }

        // 简单分词:按空格分割
        $words = explode(' ', $text);
        
        foreach ($words as $word) {
            if (mb_strlen($word) >= $minLength) {
                $segments[] = $word;
            }
        }

        return $segments;
    }
}

if (!function_exists('filter_and_segment_text')) {

    /**
     * 先过滤敏感词再分词
     * @param string $content 待处理的内容
     * @param string $replaceChar 替换字符
     * @param int $minLength 最小词长度
     * @return array 处理结果
     */
    function filter_and_segment_text($content, $replaceChar = '*', $minLength = 2)
    {
        // 先过滤敏感词
        $filterResult = filter_sensitive_words($content, $replaceChar);
        
        // 再分词
        $segments = segment_text($filterResult['content'], $minLength);
        
        return [
            'original_content' => $content,
            'filtered_content' => $filterResult['content'],
            'has_sensitive' => $filterResult['has_sensitive'],
            'filtered_count' => $filterResult['filtered_count'],
            'segments' => $segments
        ];
    }
}

业务调用

在业务中进行调用,分为两类:

  1. 对于不允许输入敏感词的场景,使用检测方法,给与用户提示并展示相应敏感词;
  2. 对于允许输入敏感词的场景,对检测到的敏感词进行相应静默过滤处理。
不允许输入敏感词

检测并给与用户提示。

php 复制代码
// 检测是否有敏感词
$sensitiveWords = check_sensitive_words($nickname);
if ($sensitiveWords['has_sensitive']) {
    $this->error('你输入的词语中含有敏感词', $sensitiveWords['sensitive_words']);
}
过滤敏感词

对输入内容进行检测、过滤,把过滤后的内容进行保存。

php 复制代码
$sensitiveWords = filter_sensitive_words($content);
$content = $sensitiveWords['content'];

总结

在Fastadmin框架中实现敏感词管理笔记

相关推荐
hhb_6182 小时前
PHP 8.x 核心特性与工程化开发实践指南
开发语言·php
不是起点的终点3 小时前
【实战】Python 一键生成数据库说明文档(对接阿里云百炼 AI,输出 Word 格式)
数据库·python·阿里云
2301_813599555 小时前
Go语言怎么做秒杀系统_Go语言秒杀系统实战教程【实用】
jvm·数据库·python
NCIN EXPE9 小时前
redis 使用
数据库·redis·缓存
MongoDB 数据平台9 小时前
为编码代理引入 MongoDB 代理技能和插件
数据库·mongodb
极客on之路9 小时前
mysql explain type 各个字段解释
数据库·mysql
代码雕刻家9 小时前
MySQL与SQL Server的基本指令
数据库·mysql·sqlserver
lThE ANDE9 小时前
开启mysql的binlog日志
数据库·mysql
yejqvow129 小时前
CSS如何控制placeholder文字的颜色_使用--placeholder伪元素
jvm·数据库·python