好不容易做个网站上线了,结果被一些别有用心的人灌水,发垃圾广告,垃圾评论,导致一些不该出现的词出现,往往出现这个,我们需要在后台不断的审核,删除,若是全部用人来做的话,想想这个
工作量都让人头疼,我们通常的做法是用程序过滤一部分,在加人工审核,当然程序若是能过滤掉100%是最好的,但是程序过滤的永远是第一次发生后的,预知就有点无能为力了。
DFA算法(确定有穷自动机)
安装包地址:https://packagist.org/packages/lustre/php-dfa-sensitive
github地址:https://github.com/FireLustre/php-dfa-sensitive
安装扩展
composer require lustre/php-dfa-sensitive
引人
use DfaFilter\SensitiveHelper;
调用
1、数组调用
$wordData = array(
'小秘',
'小李',
'小红',
'小红红',
'小莉莉',
......
);
$handle = SensitiveHelper::init()->setTree($wordData);
2、文件调用
$wordFilePath = 'data/words.txt'; //敏感词文件,文件中每个词一行
$handle = SensitiveHelper::init()->setTreeByFile($wordFilePath);
3、检测是否有敏感词
$islegal = $handle->islegal($content);
4、敏感词过滤
// 敏感词替换为*为例(会替换为相同字符长度的*)
$filterContent = $handle->replace($content, '*', true);
// 或敏感词替换为***为例
$filterContent = $handle->replace($content, '***');
5、标记敏感词
$markedContent = $handle->mark($content, '<mark>', '</mark>');
6、获取文字中的敏感词
// 获取内容中所有的敏感词
$sensitiveWordGroup = $handle->getBadWord($content);
// 仅且获取一个敏感词
$sensitiveWordGroup = $handle->getBadWord($content, 1);
封装为类
<?php
namespace App\Services;
use DfaFilter\SensitiveHelper;
class SensitiveWords
{
protected static $handle = null;
private function __construct()
{
}
private function __clone()
{
}
/**
* 获取实例
*/
public static function getInstance($word_path = [])
{
if (!self::$handle) {
//默认的一些敏感词库
$default_path = [
include_once('data/1.txt'), //敏感词文件
include_once('data/2.txt'),
include_once('data/3.txt'),
include_once('data/4.txt'),
];
$paths = array_merge($default_path, $word_path);
self::$handle = SensitiveHelper::init();
if (!empty($paths)) {
foreach ($paths as $path) {
self::$handle->setTreeByFile($path);
}
}
}
return self::$handle;
}
/**
* 检测是否含有敏感词
*/
public static function isLegal($content)
{
return self::getInstance()->islegal($content);
}
/**
* 敏感词过滤
*/
public static function replace($content, $replace_char = '', $repeat = false, $match_type = 1)
{
return self::getInstance()->replace($content, $replace_char, $repeat, $match_type);
}
/**
* 标记敏感词
*/
public static function mark($content, $start_tag, $end_tag, $match_type = 1)
{
return self::getInstance()->mark($content, $start_tag, $end_tag, $match_type);
}
/**
* 获取文本中的敏感词
*/
public static function getBadWord($content, $match_type = 1, $word_num = 0)
{
return self::getInstance()->getBadWord($content, $match_type, $word_num);
}
}
在项目中,使用 SensitiveWords::getBadWord() 来获取文本中是否有敏感词。
$bad_word = SensitiveWords::getBadWord($content);
if (!empty($bad_word)) {
throw new \Exception('包含敏感词:' . current($bad_word));
}
对于网站的敏感词,我们总是在与攻击者斗智斗勇,上面的是一种过滤的算法,不一定是最好的,我们往往还需要结合正则表达式,字符串过滤,火星文过滤等等技术手段,减少这方面词的出现。
存在问题
如果单纯只加入关键字匹配,用户反过滤的方法五花八门,包括中间加入空格或者其他标点符号。
例子
敏感词:扣扣
用户处理后:
扣 扣
扣,扣
扣@扣
扣1扣
这时候代码的正则匹配就可能匹配不出来。
解决办法:
先对用户数据去除所有的标点符号和一些特殊字符,然后再进行敏感词判断。
$flag_arr=array('?','!','¥','(',')',':','‘','’','“','”','《','》',',','…','。','、','nbsp','】','【','~');
$content_filter=preg_replace('/\s/','',preg_replace("/[[:punct:]]/",'',strip_tags(html_entity_decode(str_replace($flag_arr,'',$content),ENT_QUOTES,'UTF-8'))));
下面是我找到的一些敏感词包,大家需要的可以去下载。