实现简单的敏感词验证以及file函数去空格
实现简单的敏感词验证
最近做一个留言板项目,里面牵扯到了需要对提交的留言进行验证,这可是个麻烦的工程。首先想到了是不是可以借助第三方的平台,这里尝试了百度的文本校验。但是还要花钱,于是就自己实现了一个简单的匹配。可以用于一些小的项目。
function sensitive($list, $string){
//违规词的个数
$count = 0;
//违规词
$sensitiveWord = '';
//替换后的内容
$stringAfter = $string;
//定义正则表达式
$pattern = "/".implode("|",$list)."/i";
//匹配到了结果
if(preg_match_all($pattern, $string, $matches)){
//匹配到的数组
$patternList = $matches[0];
$count = count($patternList);
//敏感词数组转字符串
$sensitiveWord = implode(',', $patternList);
//把匹配到的数组进行合并,替换使用
$replaceArray = array_combine($patternList,array_fill(0,count($patternList),'*'));
//结果替换
$stringAfter = strtr($string, $replaceArray);
}
$log = "原句为 [ {$string} ]<br/>";
if($count==0){
$log .= "暂未匹配到敏感词!";
}else{
$log .= "匹配到 [ {$count} ]个敏感词:[ {$sensitiveWord} ]<br/>".
"替换后为:[ {$stringAfter} ]";
}
return $log;
}
注意:在具体的使用时候,可以进行修改,然后封装进一个类中。《三》中提供封装的类。
//要过滤的内容
$string = 'likeyou爱液喜欢小黑暴淫爱着的大黄';
//定义敏感词数组 从文件中获取
$list = file('色情词库.txt', FILE_SKIP_EMPTY_LINES | FILE_IGNORE_NEW_LINES);
// $list_读取后的形式 = ['爱液', '爱女人', '暴淫'];
$result = sensitive($list, $string);
echo ($result);
最后得到的展示结果为:
原句为 [ likeyou爱液喜欢小黑暴淫爱着的大黄 ]
匹配到 [ 2 ]个敏感词:[ 爱液,暴淫 ]
替换后为:[ likeyou*喜欢小黑*爱着的大黄 ]
关于file函数的一个坑
当我在测试的时候,使用file将txt文件中的每一行存为一个数组项,然后再拼接成正则:
// txt文件中内容
内容1
内容2
...如此结构排列N行
$list = file('xx.txt');
$pattern = "/".implode("|",$list)."/i";
/*
打印$pattern得到的结果: 内容1 |内容2 |内容3/i"
*/
可以发现结果在内容1(空格)|内容2(空格)| 在每个项之间多了个空格!这直接导致了正则匹配的失败。
最后经过研究发现,解决这个问题需要给file函数传第二个参数:
$list= file('色情词库.txt', FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES );
或者只需要一个参数也行
$list = file('色情词库.txt', FILE_IGNORE_NEW_LINES);
这样得到的结果,拼接各个数组项后就没有空格了。最终结果是:
/内容1|内容2|内容3/i 正确的结果
将功能函数进行封装
<?php
// 脏词过滤类
class DirtywordFilter
{
private static $instance;
// 存储脏词的数组
private static $dirtys = [];
// 存储敏感词的各种txt文件的文件夹
const TXT_PATH = __DIR__ . '/txts/';
public static function getInstance()
{
// 判断当前类是否为空,为空则new本身
if (is_null(self::$instance)) {
self::$instance = new self();
}
self::$instance->getWordsToArray();
// 保证每次通过getInstance方法拿到的句柄是同一个句柄
return self::$instance;
}
// 加载禁词文件
private function getWordsToArray()
{
$dh = opendir(self::TXT_PATH);
while ($file = readdir($dh)) {
if ($file != '.' && $file != '..') {
// 读取的时候获取的每一项去掉空格
self::$dirtys[] = file(self::TXT_PATH . $file, FILE_SKIP_EMPTY_LINES | FILE_IGNORE_NEW_LINES);
}
}
closedir($dh);
}
// 过滤方法
public function filter($str)
{
$result = [
'success' => true,
'count' => 0,
'log' => '未查出敏感词'
];
foreach (self::$dirtys as $key => $dirty) {
$res = self::sensitive($dirty, $str);
// 如果违禁词大于0 马上终止循环
if ($res['count'] > 0) {
$msg = "第{$key}轮查询结果,";
$result['success'] = false;
$result['count'] = $res['count'];
$result['log'] = $msg . $res['log'];
break;
}
}
return $result;
}
/**
* @todo 敏感词过滤,返回结果
* @param array $list 定义敏感词一维数组
* @param string $string 要过滤的内容
* @return string $log 处理结果
*/
private static function sensitive($list, $string)
{
//违规词的个数
$count = 0;
//违规词
$sensitiveWord = '';
//替换后的内容
$stringAfter = $string;
//定义正则表达式
$pattern = "/".implode("|",$list)."/i";
if(preg_match_all($pattern, $string, $matches)){ //匹配到了结果
$patternList = $matches[0]; //匹配到的数组
$count = count($patternList);
$sensitiveWord = implode(',', $patternList); //敏感词数组转字符串
$replaceArray = array_combine($patternList,array_fill(0,count($patternList),'*')); //把匹配到的数组进行合并,替换使用
$stringAfter = strtr($string, $replaceArray); //结果替换
}
$log = "原句为 [ {$string} ]<br/>";
if($count == 0) {
$log .= "暂未匹配到敏感词!";
}else{
$log .= "匹配到 [ {$count} ]个敏感词:[ {$sensitiveWord} ]<br/>".
"替换后为:[ {$stringAfter} ]";
}
return [
'count' => $count,
'log' => $log
];
}
private function __construct()
{}
private function __clone()
{}
}
// 首先要引入
$dirty = DirtywordFilter::getInstance();
$res = $dirty->filter('各种敏感词');
if($res['success]) {
echo '验证成功';
} else {
echo '验证失败';
}
服务器空间有限,个人存了一些词库(txt版本的),如果有需要的同学可以邮箱联系我,我会在收到的第一时间给您发送。
如果大家有免费的内容审核平台接口使用,欢迎推荐~~