Browse Source

app.common

author
wanghongjun 7 months ago
parent
commit
014d7bd550
  1. 105
      app/common/controller/Api.php
  2. 390
      app/common/controller/Pub.php
  3. 346
      app/common/controller/Upload.php
  4. 54
      app/common/listener/GreenText.php
  5. 9
      app/common/listener/GroupChange.php
  6. 141
      app/common/listener/UserRegister.php
  7. 35
      app/common/middleware/ApiAuth.php
  8. 52
      app/common/middleware/CheckAuth.php
  9. 43
      app/common/middleware/ManageAuth.php
  10. 66
      app/common/task/ClearMessage.php
  11. 52
      app/common/task/SetAtRead.php

105
app/common/controller/Api.php

@ -0,0 +1,105 @@
<?php
namespace app\common\controller;
use think\App;
use app\enterprise\model\{User,Group};
use app\index\controller\Extension;
use think\facade\Session;
use think\facade\Cache;
use think\facade\Db;
use GatewayClient\Gateway;
use app\manage\model\Config;
use thans\jwt\facade\JWTAuth;
/**
* API接口类
*/
class Api
{
/**
* Request实例
* @var \think\Request
*/
protected $request;
/**
* 应用实例
* @var \think\App
*/
protected $app;
protected $middleware=['apiAuth'];
/**
* 构造方法
* @access public
* @param App $app 应用对象
*/
public function __construct(App $app)
{
$this->app = $app;
$this->request = $this->app->request;
}
// 创建用户
public function createUser()
{
$data = $this->request->param();
if(!isset($data['account']) || !isset($data['realname'])){
return warning(lang('system.parameterError'));
}
$user=new User();
$verify=$user->checkAccount($data);
if(!$verify){
return success(lang('user.exist'));
}
$salt=\utils\Str::random(4);
$data['password'] = password_hash_tp(rand(100000,999999),$salt);
$data['salt'] =$salt;
$data['register_ip'] =$this->request->ip();
$data['name_py'] = pinyin_sentence($data['realname']);
$user->save($data);
$data['user_id']=$user->user_id;
$data['open_id']=encryptIds($user->user_id);
// 监听用户注册后的操作
event('UserRegister',$data);
return success(lang('user.registerOk'), $data);
}
// 用户登录
public function login()
{
$param=$this->request->param();
$isMobile=$param['is_mobile'] ?? false;
if(!isset($param['account']) || !isset($param['open_id'])){
return warning(lang('system.parameterError'));
}
$userInfo=User::where(['account'=> $param['account']])->withoutField('register_ip,login_count,update_time,create_time')->find();
if(!$userInfo){
return warning(lang('user.exist'));
}
try{
$hash_id=decryptIds($param['open_id']);
if($hash_id!=$userInfo['user_id']){
return warning(lang('user.exist'));
}
}catch (\Exception $e){
return error($e->getMessage());
}
$md5=md5(json_encode($userInfo));
// 将用户信息缓存5分钟
Cache::set($md5,$userInfo,300);
// 生成Url
if($isMobile){
$url=getMainHost().'/h5/#/pages/login/index?token='.$md5;
}else{
$url=getMainHost().'/#/login?token='.$md5;
}
return success(lang('user.loginOk'),$url);
}
}

390
app/common/controller/Pub.php

@ -0,0 +1,390 @@
<?php
namespace app\common\controller;
use think\App;
use app\enterprise\model\{User,Group};
use app\index\controller\Extension;
use think\facade\Session;
use think\facade\Cache;
use think\facade\Db;
use GatewayClient\Gateway;
use app\manage\model\Config;
use thans\jwt\facade\JWTAuth;
use function Hyperf\Coroutine\wait;
/**
* 控制器基础类
*/
class Pub
{
/**
* Request实例
* @var \think\Request
*/
protected $request;
/**
* 应用实例
* @var \think\App
*/
protected $app;
/**
* 构造方法
* @access public
* @param App $app 应用对象
*/
public function __construct(App $app)
{
Gateway::$registerAddress = config('gateway.registerAddress');
$this->app = $app;
$this->request = $this->app->request;
// 控制器初始化
// $this->initialize();
}
public function login(){
$param=request()->param();
$token=$param['token'] ?? '';
// token一键登录
if($token){
$apiStatus=config('app.api_status');
if(!$apiStatus){
return warning(lang('system.apiClose'));
}
$userInfo=Cache::get($token);
if(!$userInfo){
return warning(lang('user.tokenFailure'));
}
}else{
$verifyTime=md5(request()->ip());
$hasError=Cache::get($verifyTime);
if($hasError && $hasError>5){
return warning(lang('user.loginLimit'));
}
$userInfo=User::where(['account'=> $param['account']])->withoutField('register_ip,login_count,update_time,create_time')->find();
if($userInfo==null){
return warning(lang('user.exist'));
}
if($userInfo['status']==0){
return warning(lang('user.forbid'));
}
$password=password_hash_tp($param['password'],$userInfo['salt']);
$code=$param['code'] ?? '';
if($code){
if($code!=Cache::get($param['account'])){
return warning(lang('user.codeErr'));
}
Cache::delete($param['account']);
}else{
if($password!=$userInfo['password']){
$hasError++;
Cache::set($verifyTime,$hasError,300);
return warning(lang('user.passError'));
}
}
}
$userInfo['avatar']=avatarUrl($userInfo['avatar'],$userInfo['realname'],$userInfo['user_id']);
// 如果用户已经有设置
$setting=$userInfo['setting'] ?: '';
if($setting){
$setting['hideMessageName']= $setting['hideMessageName']=='true' ? true : false;
$setting['hideMessageTime']= $setting['hideMessageTime']=='true' ? true : false;
$setting['avatarCricle']= $setting['avatarCricle']=='true' ? true : false;
$setting['isVoice']= $setting['isVoice']=='true' ? true : false;
$setting['sendKey']=(int)$setting['sendKey'];
$userInfo['setting']=$setting;
}
//如果登录信息中含有client——id则自动进行绑定
$client_id=$this->request->param('client_id');
if($client_id){
$cid=$this->request->header('cid','');
$this->doBindUid($userInfo['user_id'],$client_id,$cid);
}
$update=[
'last_login_time'=>time(),
'last_login_ip'=>$this->request->ip(),
'login_count'=>Db::raw('login_count+1')
];
User::where('user_id',$userInfo['user_id'])->update($update);
$userInfo['qrUrl']=getMainHost().'/scan/u/'.encryptIds($userInfo['user_id']);
unset($userInfo['password'],$userInfo['salt']);
$userInfo['displayName']=$userInfo['realname'];
$userInfo['id']=$userInfo['user_id'];
$authToken=User::refreshToken($userInfo,$param['terminal'] ?? 'web');
$data=[
'sessionId'=>Session::getId(),
'authToken'=>$authToken,
'userInfo'=>$userInfo
];
return success(lang('user.loginOk'),$data);
}
//退出登录
public function logout(){
try {
$jwtData = JWTAuth::auth();
} catch (\Exception $e) {
return success(lang('user.logoutOk'));
}
$userInfo = $jwtData['info']->getValue();
//解密token中的用户信息
$userInfo = str_encipher($userInfo,false, config('app.aes_token_key'));
if (!$userInfo) {
return success(lang('user.logoutOk'));
}
//解析json
$userInfo = (array)json_decode($userInfo, true);
if($userInfo){
$client_id=$this->request->param('client_id','');
if($client_id){
Gateway::unbindUid($client_id,$userInfo['user_id']);
// 查询团队,如果有团队则加入团队
$group=Group::getMyGroup(['gu.user_id'=>$userInfo['user_id'],'gu.status'=>1]);
if($group){
$group=$group->toArray();
$group_ids=arrayToString($group,'group_id',false);
foreach($group_ids as $v){
Gateway::leaveGroup($client_id, $v);
}
}
}
wsSendMsg(0,'isOnline',['id'=>$userInfo['user_id'],'is_online'=>0]);
}
JWTAuth::invalidate(JWTAuth::token()->get());
return success(lang('user.logoutOk'));
}
// 注册用户
public function register(){
if(env('app.demon_mode',false)){
return warning(lang('system.demoMode'));
}
try{
$data = $this->request->param();
$ip = $this->request->ip();
$systemInfo=Config::getSystemInfo();
$registerInterval=$systemInfo['sysInfo']['registerInterval'] ? : 0;
if(Cache::has('register_'.md5($ip)) && $registerInterval>0){
return warning(lang('user.registerLimit',['time'=>floor($registerInterval/60)]));
}
// 判断系统是否开启注册
if($systemInfo['sysInfo']['regtype']==2){
$inviteCode=$data['inviteCode'] ?? '';
if(!$inviteCode){
return warning(lang('user.closeRegister'));
}
if(!Cache::get($inviteCode)){
return warning(lang('user.inviteCode'));
}
}
$code=$data['code'] ?? '';
if($code){
if($code!=Cache::get($data['account'])){
return warning(lang('user.codeErr'));
}
Cache::delete($data['account']);
}
// 接入用户名检测服务
event('GreenText',['content'=>$data['realname'],'service'=>"nickname_detection"]);
$user=new User();
$verify=$user->checkAccount($data);
if(!$verify){
return warning($user->getError());
}
$salt=\utils\Str::random(4);
$data['password'] = password_hash_tp($data['password'],$salt);
$data['salt'] =$salt;
$data['register_ip'] =$this->request->ip();
$data['name_py'] = pinyin_sentence($data['realname']);
$user->save($data);
$data['user_id']=$user->user_id;
// 监听用户注册后的操作
event('UserRegister',$data);
// x分钟后才能再注册
if($registerInterval){
Cache::set('register_'.md5($ip),$ip,$registerInterval);
}
return success(lang('user.registerOk'), $data);
}catch (\Exception $e){
return error($e->getMessage());
}
}
//头像生成
public function avatar(){
circleAvatar(input('str'),input('s')?:80,input('uid'));die;
}
/**
* 将用户UId绑定到消息推送服务中
* @return \think\response\Json
*/
public function bindUid(){
$client_id=$this->request->param('client_id');
$user_id=$this->request->param('user_id');
$cid=$this->request->param('cid','');
try{
$this->doBindUid($user_id,$client_id,$cid);
}catch(\Exception $e){
// 未找到用户
}
return success('');
}
// 执行绑定
public function doBindUid($user_id,$client_id,$cid=''){
// 如果当前ID在线,将其他地方登陆挤兑下线
if(Gateway::isUidOnline($user_id)){
wsSendMsg($user_id,'offline',['id'=>$user_id,'client_id'=>$client_id,'isMobile'=>$this->request->isMobile()]);
}
Gateway::bindUid($client_id, $user_id);
// 查询团队,如果有团队则加入团队
$group=Group::getMyGroup(['gu.user_id'=>$user_id,'gu.status'=>1]);
if($group){
$group=$group->toArray();
$group_ids=arrayToString($group,'group_id',false);
foreach($group_ids as $v){
Gateway::joinGroup($client_id, $v);
}
}
if($cid){
bindCid($user_id,$cid);
}
wsSendMsg(0,'isOnline',['id'=>$user_id,'is_online'=>1]);
}
// 下线通知
public function offline(){
$user_id=input('user_id');
try{
$client_ids=Gateway::getClientIdByUid($user_id);
// 一个终端登录时才发送下线通知
if(count($client_ids)<2){
wsSendMsg(0,'isOnline',['id'=>$user_id,'is_online'=>0]);
}
}catch(\Exception $e){
// 未找到用户
}
return success('');
}
/**
* 将用户团队绑定到消息推送服务中
* @return \think\response\Json
*/
public function bindGroup(){
$client_id=input('client_id');
$group_id=input('group_id');
$group_id = explode('-', $group_id)[1];
Gateway::joinGroup($client_id, $group_id);
return success('');
}
// 获取系统配置信息
public function getSystemInfo(){
$systemInfo=Config::getSystemInfo();
$systemInfo['demon_mode']=env('app.demon_mode',false);
return success('',$systemInfo);
}
// 发送验证码
public function sendCode(){
$account=$this->request->param('account');
$type=$this->request->param('type',1);
if(in_array($type,[3,4]) && !$account){
$userInfo=request()->userInfo;
$acType=\utils\Regular::check_account($userInfo['account']);
if($acType){
$account=$userInfo['account'];
}else{
$account=$userInfo['email'];
}
};
$acType=\utils\Regular::check_account($account);
if(!$acType){
return warning(lang('user.accountVerify'));
}
if(Cache::get($account.'_time')) return warning(lang('user.waitMinute'));
if($type==1){
$text=lang('user.loginAccount');
$actions="login";
}elseif($type==2){
$text=lang('user.registerAccount');
$actions="register";
}elseif($type==3){
$text=lang('user.editPass');
$actions="changePassword";
}else{
$text=lang('user.editAccount');
$actions="changeUserinfo";
}
$code=rand(100000,999999);
Cache::set($account,$code,300);
Cache::set($account.'_time',$code,60);
if($acType==2){
$conf=Config::where(['name'=>'smtp'])->value('value');
$conf['temp']='code';
$mail=new \mail\Mail($conf);
$mail->sendEmail([$account],$text,$code);
return success(lang('system.sendOk'));
}else{
$parmes=[
'code'=>$code
];
$res=sendSms($account,$actions,$parmes);
return success($res['msg']);
}
}
// 检查app版本升级
public function checkVersion(){
$oldRelease=$this->request->param('release',0);
$setupPage=$this->request->param('setupPage',false);
$platform=$this->request->param('platform',1101);
$name=config('version.app_name');
$packageName='';
if($platform==1101){
$teminal='andriod';
}else{
$teminal='ios';
}
$versionInfo=config('version.'.$teminal);
$data=[
'versionName'=>$versionInfo['version'],
'versionCode'=>$versionInfo['release'],
'updateType'=>$versionInfo['update_type'],
'versionInfo'=>$versionInfo['update_info'],
'downloadUrl'=>'',
];
// 是否手动检测更新,是的话就不能强制更新或者静默更新
if($setupPage){
$data['updateType']='solicit';
}
// 如果旧版本大于等于当前版本则不更新
if($oldRelease>=$versionInfo['release']){
return success('',$data);
}
$downUrl='';
$andriod='';
// 如果是ios则返回ios地址
if($platform==1101){
$packageName=$name."_Setup_".$versionInfo['version'].".apk";
if(is_file(PACKAGE_PATH . $packageName)){
$andriod = getMainHost().'/unpackage/'.$packageName;
}
$downUrl=env('app.andriod_webclip','') ? : $andriod;
}else{
$downUrl=env('app.ios_webclip','');
}
$data['downloadUrl']=$downUrl;
return success('',$data);
}
}

346
app/common/controller/Upload.php

@ -0,0 +1,346 @@
<?php
/**
* lvzheAdmin [a web admin based ThinkPHP5]
* @author xiekunyu<raingad@foxmail.com>
*/
namespace app\common\controller;
use app\BaseController;
use app\enterprise\model\{File as FileModel,Message,User,Emoji};
use app\manage\model\{Config};
use think\facade\Filesystem;
use think\facade\Request;
use think\File;
use FFMpeg\FFMpeg;
use FFMpeg\FFProbe;
use FFMpeg\Coordinate\TimeCode;
class Upload extends BaseController
{
protected $middleware = ['checkAuth'];
protected $disk='';
protected $url='';
public function __construct()
{
parent::__construct(app());
$this->disk=env('filesystem.driver','local');
$this->url=getDiskUrl().'/';
}
/**
* 文件上传
*/
public function upload($data,$path,$prefix = "",$fileObj = true)
{
$message=$data['message'] ?? '';
if($message){
$message=json_decode($message,true);
}
$uid=request()->userInfo['user_id'] ?? 1;
if($fileObj){
$filePath = $path;
}else{
$filePath = new File($path);
}
$info=$this->getFileInfo($filePath,$path,$fileObj);
if($info['ext']=='' && $message){
$pathInfo = pathinfo($message['fileName'] ?? '');
$info['ext'] = $pathInfo['extension'];
$info['name'] =$message['fileName'] ?? '';
}
$conf=Config::where(['name'=>'fileUpload'])->value('value');
if($conf['size']*1024*1024 < $info['size']){
return shutdown(lang('file.uploadLimit',['size'=>$conf['size']]));
}
// 兼容uniapp文件上传
if($info['ext']=='' && isset($data['ext'])){
$info['ext']=$data['ext'];
}
$info['ext']=strtolower($info['ext']);
if(!in_array($info['ext'],$conf['fileExt'])){
return shutdown(lang('file.typeNotSupport'));
}
$fileType=getFileType($info['ext']);
$imageInfo=[];
if($fileType==2){
$filecate="image";
$imageInfo=$this->getImageSizeInfo($info['path']);
}elseif($fileType==3){
$msgType=$message['type'] ?? '';
// 如果是语音消息,类型才为语音,否者为文件,主要是兼容发送音频文件
if($msgType=='voice'){
$filecate="voice";
}else{
$filecate="file";
}
}elseif($fileType==4){
$filecate="video";
}else{
$filecate="file";
}
if(!$prefix){
$prefix=$filecate.'/'.date('Y-m-d').'/'.$uid."/";
}
$name=str_replace('.'.$info['ext'],'',$info['name']);
$file=FileModel::where(['md5'=>$info['md5']])->find();
// 判断文件是否存在,如果有则不再上传
if(!$file){
$newName = uniqid() . '.' . $info['ext'];
$object = $prefix . $newName;
if($this->disk=='local'){
$object='storage/'.$object;
}
Filesystem::disk($this->disk)->putFileAs($prefix, $filePath, $newName);
}else{
$object = $file['src'];
}
// 把左边的/去掉再加上,避免有些有/有些没有
$object='/'.ltrim($object,'/');
$ret = [
"src" => $object,
"name" => $name,
"cate" => $fileType,
"size" => $info['size'],
"md5" => $info['md5'],
"file_type" => $info['mime'],
"ext" => $info['ext'],
"type" =>2,
'user_id'=>$uid,
'videoInfo'=>$imageInfo
];
if($message){
// 自动获取视频第一帧,视频并且是使用的阿里云
if($message['type']=='video'){
$videoInfo=$this->getVideoCover($filePath);
if($videoInfo){
$extends=$videoInfo['videoInfo'];
$extends['poster']=$this->url.$videoInfo['src'];
$message['extends']=$extends;
}else{
$message['extends']['poster']=getMainHost().'/static/common/img/video.png';
}
// if($this->disk=='aliyun'){
// $message['extends']['poster']=$this->url.$ret['src'].'?x-oss-process=video/snapshot,t_1000,m_fast,w_800,f_png';
// }else{
// $message['extends']['poster']=getMainHost().'/static/common/img/video.png';
// }
}
// 如果发送的文件是图片、视频、音频则将消息类型改为对应的类型
if(in_array($fileType,[2,3,4])){
$message['type']=$filecate;
}
if($message['type']=='image'){
$message['extends']=$imageInfo;
}
$newFile=new FileModel;
// 录音就不保存了
if($message['type']!='voice'){
$newFile->save($ret);
}
$message['content']=$ret['src'];
$message['file_id']=$newFile->file_id ?? 0;
$message['file_cate']=$fileType;
$message['file_size']=$info['size'];
$message['file_name']= $name.'.'.$info['ext'];
$message['user_id']= $uid;
$messageModel=new Message();
$data=$messageModel->sendMessage($message,$this->globalConfig);
if(!$data){
return shutdown($messageModel->getError());
}
return $data;
}else{
return $ret;
}
}
// 上传一般文件
public function uploadFile(){
$param=$this->request->param();
try{
$file=request()->file('file');
$info=$this->upload($param,$file);
return success(lang('file.uploadOk'),$info);
} catch(\Exception $e) {
return error($e->getMessage().$e->getLine());
}
}
// 获取上传文件的信息
protected function getFileInfo($file,$path,$isObj=false){
$info= [
'path'=>$file->getRealPath(),
'size'=>$file->getSize(),
'mime'=>$file->getMime(),
'ext'=>$file->extension(),
'md5'=>$file->md5(),
];
if($isObj){
$info['name']=$file->getOriginalName();
}else{
// 根据路径获取文件名
$pathInfo = pathinfo($path);
$info['name'] = $pathInfo['basename'];
}
return $info;
}
// 上传图片
public function uploadImage(){
$param=request::param();
try{
$file=request()->file('file');
$info=$this->upload($param,$file,'image/'.date('Y-m-d').'/');
$url=$this->url.$info['src'];
return success(lang('file.uploadOk'),$url);
} catch(\Exception $e) {
return error($e->getMessage());
}
}
// 普通上传头像
public function uploadAvatar(){
$param=request::param();
try{
$file=request()->file('file');
$uid=request()->userInfo['user_id'];
$info=$this->upload($param,$file,'avatar/'.$uid.'/');
User::where(['user_id'=>$uid])->update(['avatar'=>$info['src']]);
$url=$this->url.$info['src'];
return success(lang('file.uploadOk'),$url);
} catch(\Exception $e) {
return error($e->getMessage());
}
}
// 服务器上传头像
public function uploadLocalAvatar($file,$param,$uid){
try{
$info=$this->upload($param,$file,'avatar/'.$uid.'/',false);
return $info['src'];
} catch(\Exception $e) {
return $e->getMessage().$e->getLine();
}
}
// 上传表情
public function uploadEmoji(){
$param=request::param();
try{
$file=request()->file('file');
$filePath = $file;
$uid=request()->userInfo['user_id'] ?? 1;
$info=$this->getFileInfo($filePath,$file,true);
if($info['ext']==''){
$pathInfo = pathinfo($message['fileName'] ?? '');
$info['ext'] = $pathInfo['extension'];
$info['name'] =$message['fileName'] ?? '';
}
// 表情不能大于1m
if(2*1024*1024 < $info['size']){
return shutdown(lang('file.uploadLimit',['size'=>2]));
}
// 兼容uniapp文件上传
if($info['ext']=='' && isset($param['ext'])){
$info['ext']=$param['ext'];
}
$info['ext']=strtolower($info['ext']);
if(!in_array($info['ext'],['jpg','jpeg','gif','png'])){
return shutdown(lang('file.typeNotSupport'));
}
$prefix='emoji/'.$uid.'/';
$name=str_replace('.'.$info['ext'],'',$info['name']);
$fileInfo=FileModel::where(['md5'=>$info['md5']])->find();
// 判断文件是否存在,如果有则不再上传
if(!$fileInfo){
$newName = uniqid() . '.' . $info['ext'];
$object = $prefix . $newName;
if($this->disk=='local'){
$object='storage/'.$object;
}
Filesystem::disk($this->disk)->putFileAs($prefix, $filePath, $newName);
$ret = [
"src" => $object,
"name" => $name,
"cate" => 1,
"size" => $info['size'],
"md5" => $info['md5'],
"file_type" => $info['mime'],
"ext" => $info['ext'],
"type" =>2,
'user_id'=>$uid,
];
$fileInfo=new FileModel;
$fileInfo->save($ret);
}else{
$object = $fileInfo->src;
}
// 把左边的/去掉再加上,避免有些有/有些没有
$object='/'.ltrim($object,'/');
$emojiInfo=[
'user_id' => $uid,
"src" => $object,
"name" => $name,
"type" => 2,
"file_id" => $fileInfo->file_id,
];
Emoji::create($emojiInfo);
return success('',$this->url.$object);
} catch(\Exception $e) {
return $e->getMessage().$e->getLine();
}
}
// 获取图片的尺寸
protected function getImageSizeInfo($file){
$extends=[];
// 如果图片获取图片的尺寸
$imageSize = getimagesize($file);
$extends['width']=$imageSize[0];
$extends['height']=$imageSize[1];
// 如果宽大于高则为横图,宽度填充模式,否则为竖图,高度填充模式
if($imageSize[0]>=$imageSize[1]){
$extends['fixMode']=1; // 宽度填充
}else{
$extends['fixMode']=2; // 高度填充
}
if($imageSize[0]<200 && $imageSize[1]<240){
$extends['fixMode']=3; // 小图
}
return $extends;
}
// 获取视频封面
public function getVideoCover($filePath){
$fileName=pathinfo($filePath,PATHINFO_FILENAME).'.jpg';
$ffmpegPath=env('ffmpeg.bin_path','');
if(!$ffmpegPath){
return false;
}
$path=array(
'ffmpeg.binaries' => $ffmpegPath.'/ffmpeg',
'ffprobe.binaries' => $ffmpegPath.'/ffprobe',
'timeout' => 3600, // 进程超时时间
'ffmpeg.threads' => 12, // FFMpeg应使用的线程数
);
$ffmpeg = FFMpeg::create($path);
$ffprobe = FFProbe::create($path);
$duration=$ffprobe->format($filePath)->get('duration');// 获取 duration 属性
$video = $ffmpeg->open($filePath);
$frame = $video->frame(TimeCode::fromSeconds(1));
$tempPath=root_path().'public/temp';
$savePath=$tempPath. '/' .$fileName;
$frame->save($savePath);
$info=$this->upload([],$savePath,'cover/'.date('Y-m-d').'/',false);
$info['videoInfo']['duration']= ceil($duration);
unlink($savePath);
return $info;
}
}

54
app/common/listener/GreenText.php

@ -0,0 +1,54 @@
<?php
namespace app\common\listener;
use think\api\Client;
// 检测敏感词
class GreenText
{
protected $contentTypes = [
'ad' => '广告引流',
'political_content' => '涉政内容',
'profanity' => '辱骂内容',
'contraband' => '违禁内容',
'sexual_content' => '色情内容',
'violence' => '暴恐内容',
'nonsense' => '无意义内容',
'negative_content' => '不良内容',
'religion' => '宗教内容',
'cyberbullying' => '网络暴力',
'ad_compliance' => '广告法合规'
];
public function handle($data){
$token = config('app.thinkapi_token');
if(!$token){
return true;
}
$client = new Client($token);
$pattern = '/<[^>]*>/';
$content = preg_replace($pattern, '', $data['content']);
$result = $client->greenText()
->withService($data['service'])
->withContent(\utils\Str::msubstr($content,0,500))
->request();
if($result && $result['code']==0){
$data=$result['data'] ?? '';
$labels=$data['labels'] ?? '';
if(!$labels){
return true;
}
$labels=explode(',',$labels);
$keywords=[];
if($labels){
foreach($labels as $v){
$keywords[]=$this->contentTypes[$v] ?? $v;
}
$msg="您发布的内容包含".implode('、',$keywords)."等违规内容,系统已自动清除!";
return shutdown($msg,500);
}
}
return true;
}
}

9
app/common/listener/GroupChange.php

@ -0,0 +1,9 @@
<?php
namespace app\common\listener;
// 群聊变更
class GroupChange
{
public function handle($data){
}
}

141
app/common/listener/UserRegister.php

@ -0,0 +1,141 @@
<?php
namespace app\common\listener;
use app\enterprise\model\{User,Message,Group,GroupUser};
use app\manage\model\{Config};
// 监听用户注册后的操作
class UserRegister
{
public function handle(User $user,$data){
try{
// 查询相关配置信息
$sysInfo=Config::where(['name'=>'sysInfo'])->value('value');
if($sysInfo['runMode']!=2){
return true;
}
// 获取聊天设置
$chatInfo=Config::where(['name'=>'chatInfo'])->value('value');
$autoAdduser=$chatInfo['autoAddUser'] ?? [];
$autoTask=$this->createConf();
// 是否开启自动客服
if($autoAdduser && $autoAdduser['status']==1){
// 获取客服ID
if($autoTask['user_id']!=0){
$autoTask['user_id']=$this->findNextOrFirstId($autoAdduser['user_ids'], $autoTask['user_id'] ? : $autoAdduser['user_ids'][0]);
}else{
$autoTask['user_id']=$autoAdduser['user_ids'][0] ?? '';
}
if($autoTask['user_id']){
$user->update(['cs_uid'=>$autoTask['user_id']],['user_id'=>$data['user_id']]);
// 如果设置了欢迎语则发送欢迎语
if($autoAdduser['welcome'] ?? ''){
$userInfo=$user->field('user_id,realname,avatar')->where(['user_id'=>$autoTask['user_id']])->find();
if($userInfo){
$userInfo['dispalayName']=$userInfo['realname'];
$userInfo['id']=$userInfo['user_id'];
$userInfo['avatar']=avatarUrl($userInfo['avatar'],$userInfo['realname'],$userInfo['user_id']);
$msg=[
'id'=>\utils\Str::getUuid(),
'user_id'=>$autoTask['user_id'],
'content'=>$autoAdduser['welcome'],
'toContactId'=>$data['user_id'],
'sendTime'=>time()*1000,
'type'=>'text',
'is_group'=>0,
'status'=>'succeed',
'fromUser'=>$userInfo,
'at'=>[]
];
Message::sendMsg($msg);
}
}
}
}
$autoAddGroup=$chatInfo['autoAddGroup'] ?? [];
// 是否自动加入群聊
if($autoAddGroup && $autoAddGroup['status']==1){
$group_id=$autoTask['group_id']??0;
$uid=$autoAddGroup['owner_uid'] ?? 0;
// 未设置群主就不能生成群
if($uid){
$userInfo=$user->field('user_id,realname,avatar')->where(['user_id'=>$uid])->find();
// 成员不存在也不进行操作了
if(!$userInfo){
return false;
}
$groupInfo=Group::where(['group_id'=>$group_id])->find();
// 如果没有群ID就需要创建
if(!$groupInfo){
$groupInfo=$this->createGroup($autoAddGroup,$userInfo,$autoTask['group_num']);
}
$groupUserCount=GroupUser::where(['group_id'=>$group_id,'status'=>1])->count();
if($groupUserCount > ($autoAddGroup['userMax'] ?? 100) - 1 ){
// 创建下一个群聊
$groupInfo=$this->createGroup($autoAddGroup,$userInfo,++$autoTask['group_num']);
}
$groupInfo['joinerName']=$data['realname'];
// 进入群聊并发送通知
GroupUser::joinGroup($data['user_id'],$uid,$groupInfo,'autoAddGroup');
// 记录本次的群聊ID
$autoTask['group_id']=$groupInfo['group_id'];
}
}
Config::update(['value'=>$autoTask],['name'=>'autoTask']);
return true;
}catch(\Exception $e){
return shutdown($e->getMessage().$e->getLine());
}
}
// 创建配置文件
public function createConf(){
$autoTask=Config::where(['name'=>'autoTask'])->value('value');
if($autoTask){
return $autoTask;
}else{
$autoTask=[
'group_id'=>0, //群聊ID
'group_num'=>1, //群聊序号
'user_id'=>0, //上一次的客服ID
];
Config::create(['name'=>'autoTask','value'=>$autoTask]);
return $autoTask;
}
}
// 查找ID的下一个值,如果未找到则使用第一个ID
public function findNextOrFirstId($ids, $searchId) {
if(!$ids){
return 0;
}
// 遍历数组查找$searchId
foreach ($ids as $k => $v) {
// 如果找到了$searchId,则返回它的下一个值(如果存在)
if ($v == $searchId && isset($ids[$k + 1])) {
return $ids[$k + 1];
}
}
// 如果未找到$searchId,则返回第一个元素
return $ids[0];
}
// 自动创建群聊
public function createGroup($autoAddGroup,$userInfo,$group_num){
$data=[
'create_user'=>$userInfo['user_id'],
'owner_id'=>$userInfo['user_id'],
'name'=>($autoAddGroup['name'] ?? lang('group.name')).$group_num,
'name_py'=>pinyin_sentence($autoAddGroup['name'].$group_num),
'setting'=>json_encode(['manage' => 0, 'invite' => 1, 'nospeak' => 0]),
];
$group=new Group;
$group->save($data);
// 群主首先进群
$group->joinerName=$userInfo['realname'];
GroupUser::joinGroup($userInfo['user_id'],$userInfo['user_id'],$group,'autoCreateGroup');
return $group;
}
}

35
app/common/middleware/ApiAuth.php

@ -0,0 +1,35 @@
<?php
namespace app\common\middleware;
//验证权限
class ApiAuth
{
public function handle($request, \Closure $next)
{
$apiStatus=config('app.api_status');
if(!$apiStatus){
return shutdown(lang('system.apiClose'));
}
$appId=config('app.app_id');
$appSecret=config('app.app_secret');
$header = $request->header();
$app_id=$header['x-im-appid'] ?? '';
$timeStamp=$header['x-im-timestamp'] ?? 0;
$sign=$header['x-im-sign'] ?? '';
if(!$app_id || !$timeStamp || !$sign){
return shutdown(lang('system.parameterError'));
}
// 时间戳不能大约60秒
if(time()-$timeStamp>60){
return shutdown(lang('system.longTime'));
}
if($appId!=$app_id){
return shutdown(lang('system.appIdError'));
}
$signStr=md5($appId.$timeStamp.$appSecret);
if($sign!=$signStr){
return shutdown(lang('system.signError'));
}
return $next($request);
}
}

52
app/common/middleware/CheckAuth.php

@ -0,0 +1,52 @@
<?php
namespace app\common\middleware;
use Exception;
use thans\jwt\exception\TokenInvalidException;
use thans\jwt\facade\JWTAuth;
use think\facade\Cache;
//验证权限
class CheckAuth
{
public function handle($request, \Closure $next)
{
try {
$jwtData = JWTAuth::auth();
} catch (Exception $exception) {
//token有误
if (get_class($exception) == TokenInvalidException::class) {
return shutdown(lang('user.loginError'), -1);
}
$errorMsgArr = [
'Must have token' => lang('user.mustToken'),
'The token is in blacklist.' => lang('user.blacklist'),
'The token is expired.' => lang('user.expired'),
'The token is in blacklist grace period list.' => lang('user.expired')
];
return shutdown($errorMsgArr[$exception->getMessage()] ?? $exception->getMessage(), -1);
}
$userInfo = $jwtData['info']->getValue();
//解密token中的用户信息
$userInfo = str_encipher($userInfo,false, config('app.aes_token_key'));
if (!$userInfo) {
return shutdown(lang('user.loginError'), -1);
}
//解析json
$userInfo = (array)json_decode($userInfo, true);
if(cache('forbidUser_'.$userInfo['id'])){
JWTAuth::invalidate(JWTAuth::token()->get());
Cache::delete('forbidUser_'.$userInfo['id']);
return shutdown(lang('user.forbid'), -1);
}
//已经登陆,将用户信息存入请求头
$request->userInfo = $userInfo;
$request->uid = $userInfo['id'];
$request->userToken = JWTAuth::token()->get();
return $next($request);
}
}

43
app/common/middleware/ManageAuth.php

@ -0,0 +1,43 @@
<?php
namespace app\common\middleware;
//验证权限
class ManageAuth
{
public function handle($request, \Closure $next)
{
// 设置演示模式,演示模式下无法修改配置
$request->demonMode=env('app.demon_mode',false);
if($request->userInfo['user_id']!=1){
if(!$request->demonMode){
if($request->userInfo['role']==0){
shutdown(lang('system.notAuth'),-1);
}
}else{
$rules=[
'user/add',
'user/edit',
'user/del',
'user/setrole',
'user/setstatus',
'user/editpassword',
'group/del',
'group/changeowner',
'group/delgroupuser',
'task/starttask',
'task/stoptask',
'config/setconfig',
'index/publishnotice',
'index/delnotice',
'message/dealmsg',
];
// 获取pathinfo信息
$pathinfo = strtolower($request->pathinfo());
if(in_array($pathinfo,$rules)){
return shutdown(lang('system.demoMode'),400);
}
}
}
return $next($request);
}
}

66
app/common/task/ClearMessage.php

@ -0,0 +1,66 @@
<?php
namespace app\common\task;
use yunwuxin\cron\Task;
use think\Exception;
use app\manage\model\{Config};
use app\enterprise\model\Message;
// 自动清理消息定时任务
class ClearMessage extends Task
{
// 定时任务日志内容
protected $content='';
protected $path='';
protected $daytime=86400;
/**
* 自动写入定时任务日志
* @return \think\response\Json
*/
protected function writeLog($text)
{
$this->path = root_path() . 'crontab.txt';
$content = '重置中!';
if (!file_exists($this->path)) {
fopen($this->path, 'w');
}
if (date('d') != 10) {
$content = file_get_contents($this->path);
}
file_put_contents($this->path, $content . date('Y-m-d H:i:s') . ':' . $text . PHP_EOL);
}
public function configure()
{
//设置每天2点执行
$this->dailyAt('02:00');
}
/**
* 执行任务
* @return mixed
*/
protected function execute()
{
if(date('H:i')!='02:00'){
return false;
}
try {
$config=Config::getSystemInfo();
$status=$config['chatInfo']['msgClear'] ?? false;
$days=$config['chatInfo']['msgClearDay'] ?? 0;
if($status && $days){
$time=time() - ($days * $this->daytime);
$where[]=['create_time','<',$time];
Message::where($where)->delete();
}
print "****************消息清理成功******************\n";
} catch (Exception $e) {
print '消息清理失败:'.$e->getMessage()."\n";
}
}
}

52
app/common/task/SetAtRead.php

@ -0,0 +1,52 @@
<?php
namespace app\common\task;
use yunwuxin\cron\Task;
use think\Exception;
use think\facade\Cache;
use app\manage\model\{Config};
use app\enterprise\model\Message;
// 自动清理消息定时任务
class SetAtRead extends Task
{
// 定时任务日志内容
protected $content='';
protected $path='';
protected $daytime=86400;
public function configure()
{
//设置每天8点执行
$this->everyMinute();
}
/**
* 执行任务
* @return mixed
*/
protected function execute()
{
try {
$atListQueue=Cache::get('atListQueue');
if($atListQueue){
foreach ($atListQueue as $key=>$val){
$message=Message::where('msg_id',$key)->value('at');
$atList=($message ?? null) ? explode(',',$message): [];
// 两个数组取差集
$uniqueArr=array_unique($val);
$newAtList = array_filter($atList, function ($value) use ($uniqueArr) {
return !in_array($value, $uniqueArr);
});
Message::where('msg_id',$key)->update(['at'=>implode(',',$newAtList)]);
}
Cache::delete('atListQueue');
}
print "****************设置已读成功******************\n";
} catch (Exception $e) {
print '设置已读失败:'.$e->getMessage()."\n";
}
}
}
Loading…
Cancel
Save