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框架中实现敏感词管理笔记

相关推荐
YL2004042618 小时前
MySQL-基础篇-事务
数据库·mysql
whn197718 小时前
达梦dbms_sql对字段类型的展示
数据库
ITMr.罗18 小时前
【无标题】
数据库
KaMeidebaby18 小时前
卡梅德生物技术快报|细菌 FISH 实验 + 流式细胞术:尿路感染活菌快速定量系统实现与数据验证
前端·数据库·其他·百度·新浪微博
昆曲之源_娄江河畔19 小时前
DBGridEh Footer的使用
前端·数据库·delphi·dbgrideh
邮专薛之谦19 小时前
MySQL 完整SQL指令大全(含详细解释+实战示例)
数据库·sql·mysql
YL2004042619 小时前
MySQL-进阶篇-SQL优化
数据库·sql·mysql
Irissgwe19 小时前
redis之典型应用-缓存cache
数据库·redis·缓存·缓存击穿·缓存雪崩·redis淘汰策略
幽络源小助理19 小时前
最新短网址系统源码 分用户链接 - 幽络源免费源码分享
前端·php
Shely201719 小时前
数据库索引
数据库·mysql