Message.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277
  1. <?php
  2. /**
  3. * raingad IM [ThinkPHP6]
  4. * @author xiekunyu <raingad@foxmail.com>
  5. */
  6. namespace app\enterprise\model;
  7. use app\BaseModel;
  8. use think\facade\Db;
  9. use think\facade\Cache;
  10. class Message extends BaseModel
  11. {
  12. protected $pk="msg_id";
  13. protected $json = ["extends"];
  14. protected $jsonAssoc = true;
  15. protected static $fileType=['file','image','video','voice','emoji'];
  16. // 添加聊天记录
  17. public static function addData($data){
  18. return Db::name('message')->insert($data);
  19. }
  20. // 更新消息状态
  21. public static function editData($update,$map){
  22. return Db::name('message')->where($map)->update($update);
  23. }
  24. // 查询聊天记录
  25. public static function getList($map,$where,$sort,$listRows,$pageSize){
  26. $list= Db::name('message')
  27. ->where($map)
  28. ->where($where)
  29. ->order($sort)
  30. ->paginate(['list_rows'=>$listRows,'page'=>$pageSize]);
  31. return $list;
  32. }
  33. // 发送消息
  34. public function sendMessage($param,$globalConfig=false){
  35. $is_group = $param['is_group'] ?? 0;
  36. $uid=self::$uid ? : ($param['user_id'] ?? 1);
  37. if($param['toContactId']==-1){
  38. $is_group=0;
  39. }
  40. // 如果是系统账号,直接禁言
  41. if($is_group>1){
  42. $this->error=lang('im.forbidChat');
  43. return false;
  44. }
  45. $isForward=$param['is_forward'] ?? 0;
  46. $sendInterval = $globalConfig['chatInfo']['sendInterval'] ?? 0;
  47. // 如果设置了消息频率则验证,转发不收限制
  48. if ($sendInterval && !$isForward) {
  49. if (Cache::has('send_' . $uid)) {
  50. $this->error=lang('im.sendTimeLimit',['time'=>$sendInterval]);
  51. return false;
  52. }
  53. }
  54. if($param['type']=='text'){
  55. // 限制文字内容长度
  56. $text = strip_tags($param['content']);
  57. $textLen = mb_strlen($text);
  58. if ($textLen > 2048) {
  59. $this->error=lang('im.msgContentLimit') . $textLen;
  60. return false;
  61. }
  62. $param['content'] = preg_link($param['content']);
  63. // 接入聊天内容检测服务
  64. event('GreenText',['content'=>$param['content'],'service'=>"chat_detection"]);
  65. }
  66. $chatSetting = $globalConfig['chatInfo'];
  67. if($param['toContactId']!=-1){
  68. if ($is_group == 0) {
  69. $kefuUser=$chatSetting['autoAddUser']['user_ids'] ?? [];
  70. $manageUser=User::where([['status','=',1],['role','>',0]])->column('user_id');
  71. $kefu=array_unique(array_merge($kefuUser,$manageUser));
  72. $csUid = self::$userInfo['cs_uid'] ?? 0;
  73. $manage=false;
  74. // 发送者和接受者是客服或者管理员也可以发送消息
  75. if(in_array($uid,$kefu) || in_array($param['toContactId'],$kefu)){
  76. $manage=true;
  77. }
  78. if($chatSetting['simpleChat'] == 0 && !$manage){
  79. $this->error=lang('im.forbidChat');
  80. return false;
  81. }
  82. // 如果是单聊,并且是社区模式和不是自己的客服、需要判断是否是好友
  83. if ($globalConfig['sysInfo']['runMode'] == 2 && $csUid != $param['toContactId'] && !$manage) {
  84. // 判断我是不是对方的客服
  85. $cus = User::where(['user_id' => $param['toContactId']])->value('cs_uid');
  86. if ($cus != $uid) {
  87. $friend = Friend::where(['friend_user_id' => $uid, 'create_user' => $param['toContactId']])->find();
  88. if (!$friend) {
  89. $this->error=lang('im.notFriend');
  90. return false;
  91. }
  92. $otherFriend = Friend::where(['friend_user_id' => $param['toContactId'], 'create_user' => $uid])->find();
  93. if (!$otherFriend) {
  94. $this->error=lang('im.friendNot');
  95. return false;
  96. }
  97. }
  98. }
  99. }else{
  100. // 群聊必须群成员才能发送消息
  101. $group_id = explode('-', $param['toContactId'])[1] ?? '';
  102. if(!$group_id){
  103. $this->error=lang('system.parameterError');
  104. return false;
  105. }
  106. if(!self::nospeak($group_id,$uid)){
  107. if($isForward){
  108. return false;
  109. }
  110. return shutdown(lang('group.notSpeak'));
  111. }
  112. // 群聊必须群成员才能发送消息
  113. $groupUser=GroupUser::where(['user_id'=>$uid,'status'=>1,'group_id'=>$group_id,'delete_time'=>0])->find();
  114. if(!$groupUser){
  115. $this->error = lang('group.notCustom');
  116. return false;
  117. }
  118. if($groupUser['no_speak_time']>time()){
  119. $this->error = lang('group.notSpeak',['time'=>date('Y-m-d H:i:s',$groupUser['no_speak_time'])]);
  120. return false;
  121. }
  122. }
  123. }
  124. if ($sendInterval) {
  125. Cache::set('send_' . $uid, time(), $sendInterval);
  126. }
  127. return self::sendMsg($param,$is_group);
  128. }
  129. //实际发送消息
  130. public static function sendMsg($param,$is_group=0,$is_sys=0){
  131. $uid=self::$uid ?: ($param['user_id'] ?? 1);
  132. $toContactId=$param['toContactId'];
  133. $manage=[];
  134. // 重新建立会话,更新会话删除记录
  135. $isDelChat=ChatDelog::where(['user_id'=>$uid,'to_user'=>$toContactId])->find();
  136. if($isDelChat){
  137. ChatDelog::where(['user_id'=>$uid,'to_user'=>$toContactId])->delete();
  138. ChatDelog::updateCache($uid);
  139. }
  140. if($is_group==1){
  141. $group_id = explode('-', $param['toContactId'])[1] ?? '';
  142. $chat_identify=$toContactId;
  143. $toContactId=$group_id;
  144. $manage=GroupUser::getGroupManage($group_id);
  145. }else{
  146. $chat_identify=chat_identify($param['user_id'],$toContactId);
  147. }
  148. $fileSzie=isset($param['file_size'])?$param['file_size']:'';
  149. $fileName=isset($param['file_name'])?$param['file_name']:'';
  150. $ossUrl=getDiskUrl();
  151. // 如果是转发图片文件的消息,必须把域名去除掉
  152. $content=$param['content'];
  153. if(in_array($param['type'],self::$fileType)){
  154. if(strpos($param['content'],$ossUrl)!==false){
  155. $content=str_replace($ossUrl,'',$param['content']);
  156. }
  157. }
  158. $param['content']=$content;
  159. $atList=($param['at'] ?? null) ? array_map('intval', $param['at']): [];
  160. // 如果at里面有0,代表@所有人
  161. if($atList && in_array(0,$atList)){
  162. $atList=GroupUser::where([['group_id','=',$toContactId],['status','=',1],['user_id','<>',$param['user_id']]])->column('user_id');
  163. }
  164. $at=$atList ? implode(',',$atList) : null;
  165. $data=[
  166. 'from_user'=>$param['user_id'],
  167. 'to_user'=>$toContactId,
  168. 'id'=>$param['id'],
  169. 'content'=>str_encipher($param['content'],true),
  170. 'chat_identify'=>$chat_identify,
  171. 'create_time'=>time(),
  172. 'type'=>$param['type'],
  173. 'is_group'=>$toContactId==-1 ? 3 : $is_group,
  174. 'is_read'=>$is_group ? 1 : 0,
  175. 'file_id'=>$param['file_id'] ?? 0,
  176. "file_cate"=>$param['file_cate'] ?? 0,
  177. 'file_size'=>$fileSzie,
  178. 'file_name'=>$fileName,
  179. 'at'=>$at,
  180. 'pid'=>$param['pid'] ?? 0,
  181. 'extends'=>($param['extends'] ?? null) ? $param['extends'] : null,
  182. ];
  183. $message=new self();
  184. $message->update(['is_last'=>0],['chat_identify'=>$chat_identify]);
  185. $message->save($data);
  186. // 拼接消息推送
  187. $type=$is_group?'group':'simple';
  188. $sendData=$param;
  189. $sendData['status']='succeed';
  190. $sendData['at']=$atList;
  191. $sendData['msg_id']=$message->msg_id;
  192. $sendData['is_read']=0;
  193. $sendData['to_user']=$toContactId;
  194. $sendData['role']=$manage[self::$uid] ?? 3;
  195. $sendData['sendTime']=(int)$sendData['sendTime'];
  196. //这里单聊中发送对方的消息,对方是接受状态,自己是对方的联系人,要把发送对象设置为发送者的ID。
  197. if($is_group){
  198. $sendData['toContactId']=$param['toContactId'];
  199. // 将团队所有成员的未读状态+1
  200. GroupUser::editGroupUser([['group_id','=',$toContactId],['user_id','<>',$uid]],['unread'=>Db::raw('unread+1')]);
  201. }else{
  202. $sendData['toContactId']=$uid;
  203. }
  204. $sendData['fromUser']['id']=(int)$sendData['fromUser']['id'];
  205. $sendData['fileSize']=$fileSzie;
  206. $sendData['fileName']=$fileName;
  207. if(in_array($sendData['type'],self::$fileType)){
  208. $sendData['content']=getFileUrl($sendData['content']);
  209. if($sendData['type']=='image'){
  210. $pre=1;
  211. }else{
  212. $pre=2;
  213. }
  214. $sendData['preview']=previewUrl($sendData['content'],$pre);
  215. $sendData['extUrl']=getExtUrl($sendData['content']);
  216. $sendData['download']= $sendData['file_id'] ? getMainHost().'/filedown/'.encryptIds($sendData['file_id']) : '';
  217. }
  218. $forContactId=$sendData['toContactId'];
  219. if($is_sys){
  220. $forContactId=$toContactId;
  221. }
  222. if($is_group==0){
  223. $toContactId=[$toContactId,$param['user_id']];
  224. }
  225. $sendData['toUser']=$param['toContactId'];
  226. $user=new User();
  227. // 将聊天窗口的联系人信息带上,方便临时会话
  228. $sendData['contactInfo']=$user->setContact($forContactId,$is_group,$sendData['type'],$sendData['content']);
  229. // 向发送方发送消息
  230. wsSendMsg($toContactId,$type,$sendData,$is_group);
  231. $sendData['toContactId']=$param['toContactId'];
  232. return $sendData;
  233. }
  234. // 群禁言
  235. public static function nospeak($group_id,$user_id){
  236. $group=Group::find($group_id);
  237. if($group->owner_id==$user_id){
  238. return true;
  239. }
  240. if($group->setting){
  241. $setting=json_decode($group->setting,true);
  242. $nospeak=isset($setting['nospeak'])?$setting['nospeak']:0;
  243. $role=GroupUser::where(['group_id'=>$group_id,'user_id'=>$user_id])->value('role');
  244. if($nospeak==1 && $role>2){
  245. return false;
  246. }elseif($nospeak==2 && $role!=1){
  247. return false;
  248. }
  249. }
  250. return true;
  251. }
  252. // 将消息中的@用户加入到atListQueue中
  253. public static function setAtread($messages,$user_id){
  254. foreach($messages as $k=>$v){
  255. if(!isset($v['at'])){
  256. continue;
  257. }
  258. if($v['at'] && in_array($user_id,$v['at'])){
  259. $atListQueue=Cache::get("atListQueue");
  260. $atListQueue[$v['msg_id']][]=$user_id;
  261. Cache::set("atListQueue",$atListQueue);
  262. }
  263. }
  264. }
  265. }