[工作]聊天监控自动规则逻辑封禁

雨中笑 经验 602热度

简介违规词匹配自动封禁规则的一些思路

最近的项目是要把聊天监控做成自动封禁,不用客服人员手动操作,节源开支。而封禁规则的话是动态变动的 ,规则分为,敏感规则、高危规则、致命规则,每个规则里面分禁登和禁言两种方式,两种方式中可以选择是永久封禁还是封禁几分钟几小时几天的,并且还区分规则原因等。

那么这里就遇到需要解决的问题:

1、一个玩家发的一条聊天信息可能触发多个敏感词,怎么匹配违规词归属于哪一类的封禁规则和优先封禁那种情况

2、自动封禁怎么执行

为了实现方法,这边在后台另外做了一个自动封禁规则的管理,分敏感规则、高危规则、致命规则三种类型,设置充值区间,用户言论归属标签几小时内达到多少次会实行怎么样的封禁规则和是否有效等

解决第一点可以先把自动封禁规则按照总的封禁规则的优先级进行排序,排序后在循环每条玩家匹配的违规词,再根据违规的规则查看次数,满足的就进入封禁的脚本,次数还不满足的就进入队列记录,到达次数后再封禁。

实现第二点可以另外把违规检测获取得到满足自动封禁规则的违规存在另一个数据表中,设置定时封禁状态 1成功,2不成功,0未封禁和定时处理次数,根据这些来定时去跑等

相关代码

    /**
* 获得自动封禁规则排好顺序的数据(缓存5分钟)
* @author: Fanjialong<1171843306@qq.com>
* @datetime: 2020-08-26
* @param int $cache
* @return array|mixed
*/
public function getAutoForbidRuleCache($cache=1){
$key = "getAutoForbidRuleCache";
$is = $this->_redis->get($key);
if($is && $cache)
return json_decode($is,true);
$data = $this->_model->select(['is_delete'=>0,'status'=>1]); //获取排好序后的封禁规则数据 $rule = (new ForbidRuleLogic())->rulePrioritize($cache);
foreach ($data as &$v){
if(!isset($rule[$v['rule_id']])){
unset($v);
continue;
}
$r = $rule[$v['rule_id']];
$v['rule_name'] = $r['rule_name'];
$v['rule_type'] = $r['rule_type'];
$v['rule_status'] = $r['rule_status'];
$v['rule_reason'] = $r['rule_reason'];
$v['rule_length'] = $r['rule_length'];
$v['remarks'] = $r['remarks'];
}
unset($v);

//自动封禁规则排序
$re = [];
foreach ($rule as $k => $v){
foreach ($data as $val){
if($val['rule_id'] == $k){
$re[$k][] = $val;
}
}
}

$res = [];
foreach ($re as $val){
foreach ($val as $v){
$res[] = $v;
}
}

$this->_redis->setex($key, 300, json_encode($res,JSON_UNESCAPED_UNICODE));
return $res;
}

    /**
* 违禁词封禁操作检测
* @author: Fanjialong<1171843306@qq.com>
* @datetime: 2020-08-26

    * @return array|void
*/
public function illegalChatsCrond()
{
$cacheKey = 'kf_system_illegalChatsCrond';
//检测封禁开关
$run = $this->checkSwitch($cacheKey);
if (!$run) {
return ;
}
self::dump("违禁词封禁操作检测脚本开始!");

//获取一天的数据
$new = time();
$time = 86400;
$datenew = $new - $time;
$data = $this->_model->select(['status' => 0, 'add_time[>=]' => $datenew]);
self::dump("需要执行的数据有:".count($data));
$autoRule = (new AutoForbidRuleLogic())->getAutoForbidRuleCache();

$break = 0;
foreach ($data as $val) {
self::dump("执行违规词数据:".$val['id']);
foreach ($autoRule as $r) {
if($break){
$break = 0;
break;
}
if ($r['pay_end'] > $val['role_charge'] && $val['role_charge'] >= $r['pay_start']) { //查看是否满足充值
$label = explode(',', $r['label_id']);
$word = json_decode($val['words'], true);
foreach ($word as $w) {
if (in_array($w['label'], $label) && $w['type'] == $r['type']) { //查看违规标签是否在自动封禁标签中
if ($r['num'] <= 1) { //插入封禁记录
$this->addAutoForbidLog($val, $r, $w);
$break = 1;
break;
} else {
$key = $cacheKey."__".$val['user_id'] . "__" . $val['cate_id'] . "__" . $val['channel'] . "__" . $val['server_id'] . "__" . $val['role_id'] . "__" . $r['rule_id'];
//检测队列值是否满足时间,增加当前时间并返回队列次数
$count = $this->checkRedis($key,$r['length']);
self::dump($r['rule_name'].$key."队列数据有:".$count);
if ($count >= $r['num']) {
$this->addAutoForbidLog($val, $r, $w);
//删除队列
$this->_redis->expire($key, 0);
$break = 1;
break;
}
//设置过期时间为一天
$this->_redis->expire($key, $time);
}
}
}
}
}
}
//更改为已执行过
$this->_model->editWhere(['status' => 0, 'add_time[<]' => $new, 'add_time[>=]' => $datenew], ['status' => 1]);
self::dump("违禁词封禁操作检测脚本结束!");
}

/**
* 小于规则时间段则删除
* @author: Fanjialong<1171843306@qq.com>
* @datetime: 2020-08-26
* @param $key
* @param $length
* @return int
*/
public function checkRedis($key,$length)
{
$this->_redis->rpush($key, time());
$redisData = $this->_redis->lrange($key, 0, -1);
$date = time() - $length;
self::dump("队列包含时间".json_encode($redisData));
$num = count($redisData);
foreach ($redisData as $res) {
if ($res < $date) {
//小于指定时间则删除
$this->_redis->lrem($key, $res, 0);
$num--;
}
}
return $num;
}

/**
* 检测封禁开关
* @author: Fanjialong<1171843306@qq.com>
* @datetime: 2020-08-26
* @param $cacheKey
* @return bool
*/
public function checkSwitch($cacheKey){
//检测封禁总开关
$autoBanLocal = new AutomaticBanMonitorLogic();
$data = $autoBanLocal->isAutomaticBanMonitor();
if (!$data) {
self::dump("自动封禁预警总开关已关闭!");
return false;
}
//控制当前脚本
$run = self::crondRedis($cacheKey);
return $run;
}

/**
* 违规词入库封禁脚本
* @author: Fanjialong<1171843306@qq.com>
* @datetime: 2020-08-26
* @param $data
* @param $rule
* @param $word
*/
public function addAutoForbidLog($data, $rule, $word)
{
$model = new AutoForbidDataModel();
// 调用服务封禁接口
$param = [
'user_id' => $data['user_id'],
'channel' => $data['channel'],
'cate_id' => $data['cate_id'],
'role_id' => $data['role_id'],
'role_name' => $data['role_name'],
'server_id' => $data['server_id'],
'server_name' => $data['server_name'],
'forbid_type' => ForbidLogic::$forbid_type[$rule['rule_type']],
'start_time' => time(),
'end_time' => $rule['rule_length'] == 0 ? 0 : $rule['rule_length'] + time(),
'offline' => 1,
'forbid_msg' => $rule['remarks'],
'callback_info' => $data['callback_info'],
'op_uid' => 0,
'sys' => 1,
'forbid_chat_content' => $data['forbid_chat_content'],
'ip' => $data['ip'],
'rule_id' => $rule['rule_id'],
'forbid_reason' => $rule['rule_reason'],
'remark' => $rule['remarks'],
'add_time' => time(),
'illegal_chat' => $word['name'],
'illegal_type' => $word['type'],
'illegal_label_id' => $word['label'],
];
// 永久封禁的则传10年的时间戳
if ($param['end_time'] == 0) {
$param['end_time'] =
$param['start_time'] + 86400 * 365 * 10;
}
$re = $model->add($param);
$re && self::dump("插入封禁脚本成功!返回id:".json_encode($re,JSON_UNESCAPED_UNICODE));
}

/**
* 自动批量封禁定时脚本
* @author: Fanjialong<1171843306@qq.com>
* @datetime: 2020-08-25
* @return array|void
*/
public function autoForbidDataCrond()
{
//脚本控制
$cacheKey = "kf_system_autoForbidDataCrond";
$run = $this->checkSwitch($cacheKey);
if(!$run){
return;
}
self::dump("自动批量封禁定时脚本开始!");

//检查封禁数量
$key = $cacheKey."_num";
$is = $this->_redis->get($key);
$banModel = new AutomaticBanMonitorModel();
$ban = $banModel->select([]);
$banData = isset($ban[0]) ? $ban[0] : [];
if(!$is){
$this->_redis->setex($key, 60, 1);
}elseif($banData && $is >= $banData['num']){
$this->send($banData);
}elseif($is>500){ //默认一分钟封禁超过xx则关闭(技术部安全措施)
$this->send($banData,$cacheKey);
}

$model = new AutoForbidDataModel();
$forbidLogic = new ForbidLogic();
//获取一天中未封禁和次数少于3的记录
$time = 86400;
$date = time() - $time;
$data = $model->select(['status[!]'=>1,'num[<]'=>3,'add_time[>=]'=>$date]);
self::dump("获得需要自动封禁数据有:".count($data));
foreach ($data as $val){
// 调用服务封禁接口
$srv_param = [
'user_id' => $val['user_id'],
'channel' => $val['channel'],
'cate_id' => $val['cate_id'],
'role_id' => $val['role_id'],
'role_name' => $val['role_name'],
'server_id' => $val['server_id'],
'server_name' => $val['server_name'],
'forbid_type' => $val['forbid_type'],
'start_time' => $val['start_time'],
'end_time' => $val['end_time'],
'offline' => 1,
'forbid_msg' => $val['forbid_msg'],
'callback_info' => $val['callback_info'],
'op_uid' => 0,
'sys' => 1,
'forbid_chat_content' => $val['forbid_chat_content'],
'ip' => $val['ip'],
'rule_id' => $val['rule_id'],
'forbid_reason' => $val['forbid_reason'],
'remark' => $val['remark'],
];

list($state, $msg) = $forbidLogic->reqForbid($srv_param);
$update = [];
if (!$state) {
$num = 0;
$update['status'] = 2;
$str = '自动封禁失败, ' . '[msg]' . $msg .'自动封禁ID:'.$val['id']. '[req_data]' . json_encode($srv_param, JSON_UNESCAPED_UNICODE);
self::dump($str,'notic_error');
} else {
$update['status'] = 1;
$num = $this->_redis->incr($key);
$str = '自动封禁成功, ' . '[msg]' . $msg .'自动封禁ID:'.$val['id']. '[req_data]' . json_encode($srv_param, JSON_UNESCAPED_UNICODE);
self::dump($str);
}
$update['num'] = $val['num'] + 1;
$model->edit($val['id'],$update);
//超过阀值关闭脚本并通知
if($num>=$banData['num']){
$this->send($banData);
break;
}elseif($is>500){ //默认一分钟封禁超过xx则关闭(技术部安全措施)
$this->send($banData,$cacheKey);
break;
}
}
self::dump("自动批量封禁定时脚本结束!");
return;
}

/**
* 发送通知
* @author: Fanjialong<1171843306@qq.com>
* @datetime: 2020-08-25
* @param $item
* @param $cacheKey
*/
public function send($item,$cacheKey='')
{
$mgs = "超过封禁次数关闭封禁总开关";
$crontabModel = new CrontabMonitorModel();
$cache = [];
$cache[] = AutomaticBanMonitorLogic::cacheKey; //预警总开关
if($cacheKey){
$cache[] = $cacheKey;
$mgs .= ";关闭{$cacheKey}开关";
}
$crontabModel->editWhere(['module'=>$cache],['status'=>2]);
self::dump($mgs);

$sendUserArr = explode(',', $item['send_user']);
$sendWayArr = explode(',', $item['send_way']);

//2.筛选超出异常工单阈值
//并且推送次数未满的配置 (不做限制)
$recordModel = (new AdminMessageRecordLogic())->_model;
$module = 'kf_SystemConfig_autoForbidDataCrond'; //ct_ac

$date = date("H:i");
//通知模板标题+内容
$template = EimLogic::getMsgTemplate(22);
$title = $template['title'];
$content = sprintf($template['content'],
$date,
$item['num']
);

if (mb_strlen($content, 'UTF-8') > 1100) {
$content = mb_substr($content, 0, 1000, 'UTF-8') . '......';
}

//每个用户添加消息记录
$recordData = [];
$userInfo = [];
$userModel = new AdminUser();
foreach ($sendUserArr as $sendUser) {
$userRow = $userModel->get(['id' => $sendUser], ['id', 'email', 'name', 'phone']);
if ($userRow) {
$userInfo[$sendUser] = $userRow;
}

$recordTmp['pid'] = $item['id'];
$recordTmp['user_id'] = $sendUser;
$recordTmp['module'] = $module;
$recordTmp['content'] = $content;
$recordTmp['url'] = '';
$recordTmp['add_time'] = time();
$recordData[] = $recordTmp;
}
if ($recordData) {
$recordModel->add($recordData);
}

//针对每个发送方式发送通知
foreach ($sendWayArr as $sendWay) {
switch ($sendWay) {
//企点
case '1':
try {
$contentNoSign = preg_replace("/【3k游戏】/", '', $content);
$eimParams = [
'scene_id' => 22,
'user_ids' => $sendUserArr,
'tips_title' => $title,
'tips_content' => $contentNoSign,
'tips_url' => '',
];
EimLogic::sendEimMsgToUsers($eimParams);
} catch (\Exception $e) {
Log::notice("发送企点通知失败-自动封禁监控:[{$e->getCode()}]" . $e->getMessage(), 'eim_msg');
self::dump("配置{$item['id']}发送企点通知失败:" . $e->getMessage(), 'notic_error');
}
break;
//邮件
case '2':
try {
$phpEmail = new PhpMail();
$contentNoSign = preg_replace("/【3k游戏】/", '', $content);
foreach ($sendUserArr as $uid) {
if (!empty($userInfo[$uid])) {
$phpEmail->sendMail($userInfo[$uid]['email'], $userInfo[$uid]['name'], $title, $contentNoSign);
} else {
self::dump("配置{$item['id']}发送邮件,用户{$uid}不存在");
}
}
} catch (\Exception $e) {
Log::notice("发送邮件失败-自动封禁监控:[{$e->getCode()}]" . $e->getMessage(), 'email_msg');
self::dump("配置{$item['id']}发送邮件失败:" . $e->getMessage(), 'notic_error');
}
break;
//短信
case '3':
try {
$phones = array_column($userInfo, 'phone');
foreach ($phones as $p) {
Sms::send($p, strip_tags($content), 1, '客服系统-自动封禁监控');
}
} catch (\Exception $e) {
Log::notice("发送短信失败-自动封禁监控:[{$e->getCode()}]" . $e->getMessage(), 'sms_msg');
self::dump("配置{$item['id']}发送短信失败:" . $e->getMessage(), 'notic_error');
}
break;
//企业微信
case '5':
try {
$contentNoSign = preg_replace("/【3k游戏】/", '', $content);
$eimParams = [
'scene_id' => 22,
'user_ids' => $sendUserArr,
'tips_title' => $title,
'tips_content' => $contentNoSign,
'tips_url' => '',
];
QyWeixinLogic::sendMessageByParams($eimParams);
} catch (\Exception $e) {
Log::notice("发送企业微信通知失败-自动封禁监控:[{$e->getCode()}]" . $e->getMessage(), 'qt_weixin_msg');
self::dump("配置{$item['id']}发送企业微信通知失败:" . $e->getMessage(), 'notic_error');
}
break;
default:
break;
}
}
}


很赞哦!(1)

本文阅读量 1835发布于 2020年8月26日

您的访问IP 18.222.21.30最早于 2024年5月14日 5时51分01秒 阅读过本文 为本文提供了 1 热度 1 阅读量

文章评论
回帖