Session.php 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406
  1. <?php
  2. /**
  3. * 会话信息
  4. * @author benzhan
  5. */
  6. class Session extends Model {
  7. protected $tableName = 'session';
  8. protected $dbKey = 'dw_chat';
  9. const MSG_TYPE_TEXT = 0;
  10. const MSG_TYPE_IMAGE = 1;
  11. const MSG_TYPE_VIDEO = 2;
  12. const MSG_TYPE_AUDIO = 3;
  13. const MSG_TYPE_REDPACK = 4;
  14. /**
  15. * 填充会话列表
  16. * @param string $user_id 用户id
  17. * @param array $list 会话列表
  18. * @param int $currentGroupId 当前群id
  19. *
  20. * @return mixed
  21. */
  22. public function fillSession($user_id, $list, $currentGroupId) {
  23. $group_ids = [];
  24. $user_ids = [];
  25. foreach ($list as $item) {
  26. if ($item['is_group']) {
  27. $group_ids[] = $item['session_id'];
  28. } else {
  29. // 把自己的用户名换掉
  30. $user_ids[] = str_replace([$user_id, '-'], ['', ''], $item['session_id']);
  31. }
  32. }
  33. $objUserInfo = new TableHelper('user_info', 'dw_chat');
  34. $_field = 'user_id, user_name, nick_name, cover_photo';
  35. $users = $objUserInfo->getAll(['user_id' => $user_ids], compact('_field'));
  36. $users = arrayFormatKey($users, 'user_id');
  37. $objGroupInfo = new TableHelper('group_info', 'dw_chat');
  38. $_field = 'group_id, group_name, group_title, cover_photo';
  39. $groups = $objGroupInfo->getAll(['group_id' => $group_ids], compact('_field'));
  40. $groups = arrayFormatKey($groups, 'group_id');
  41. $userGroups = [];
  42. if ($currentGroupId) {
  43. $objUserGroup = new UserGroup();
  44. $userGroups = $objUserGroup->objTable->getAll(['user_id' => $user_ids, 'group_id' => $currentGroupId], ['_field' => 'user_id, group_id']);
  45. $userGroups = arrayFormatKey($userGroups, 'user_id', 'group_id');
  46. }
  47. foreach ($list as $i => $item) {
  48. if ($item['is_group']) {
  49. $group = $groups[$item['session_id']];
  50. $item['name'] = $group['group_title'] ?: $group['group_name'];
  51. $item['cover_photo'] = $group['cover_photo'];
  52. } else {
  53. // 把自己的用户名换掉
  54. $key = str_replace([$user_id, '-'], ['', ''], $item['session_id']);
  55. $user = $users[$key];
  56. $item['name'] = $user['nick_name'];
  57. $item['cover_photo'] = $user['cover_photo'];
  58. $item['in_group'] = $userGroups[$key] ? 1 : 0; // 已经在群
  59. }
  60. $list[$i] = $item;
  61. }
  62. return $list;
  63. }
  64. public function getMsgList($session_id, $read_hash, $load_type, $is_group) {
  65. $where2 = [
  66. 'state' => 1,
  67. ];
  68. if ($is_group) {
  69. $_field = '`hash`, `from`, `msg`, `msg_type`, `state`, create_time_int';
  70. $objMsg = new TableHelper('group_msg', 'dw_chat');
  71. $where2['group_id'] = $session_id;
  72. } else {
  73. $_field = '`hash`, `from`, `to`, `msg`, `msg_type`, `state`, create_time_int';
  74. $objMsg = new TableHelper('person_msg', 'dw_chat');
  75. $where2['session_id'] = $session_id;
  76. }
  77. if ($read_hash) {
  78. $currentRow = $objMsg->getRow(['hash' => $read_hash], compact('_field'));
  79. $create_time_int = (int) $currentRow['create_time_int'];
  80. } else {
  81. $create_time_int = 0;
  82. }
  83. $_limit = 100;
  84. $maxNum = 1000;
  85. $need_clear = false;
  86. if ($load_type == 0) {
  87. // 正常加载
  88. if ($create_time_int > 0) {
  89. $_limit = $maxNum;
  90. // 需要判断是否存在过多未读消息
  91. $_where = "create_time_int > {$create_time_int}";
  92. $num = $objMsg->getCount($where2, compact('_where'));
  93. if ($num > $maxNum) {
  94. // 这种情况抛弃create_time_int...,消息太多了,只拿最新的1000条记录
  95. $create_time_int = 0;
  96. $need_clear = true;
  97. }
  98. }
  99. $create_time_int && $_where = "create_time_int > {$create_time_int}";
  100. $_sortKey = "create_time_int DESC";
  101. $keyWord2 = compact('_where', '_sortKey', '_limit', '_field');
  102. $list = $objMsg->getAll($where2, $keyWord2);
  103. } else {
  104. // 加载历史记录
  105. $_where = "create_time_int < {$create_time_int}";
  106. $_sortKey = "create_time_int DESC";
  107. $keyWord3 = compact('_where', '_sortKey', '_limit', '_field');
  108. $list = $objMsg->getAll($where2, $keyWord3);
  109. }
  110. $list = array_reverse($list);
  111. $list = $this->appendExtInfo($list);
  112. $user_ids = array_column($list, 'from');
  113. if (!$is_group) {
  114. $to_ids = array_column($list, 'to');
  115. $user_ids = array_merge($user_ids, $to_ids);
  116. }
  117. $user_ids = array_unique($user_ids);
  118. $userMap = $this->getUserMap($user_ids);
  119. return compact('userMap', 'list', 'need_clear');
  120. }
  121. /**
  122. * 额外信息
  123. * @author solu
  124. * @param $list
  125. * @return mixed
  126. */
  127. private function appendExtInfo($list) {
  128. $userId = User::getUserId();
  129. $objRedpackLog = new RedpackLog();
  130. $trxIds = array_map(function($v) {
  131. $msg = Utils::decodeRC4($v['msg']);
  132. $data = json_decode($msg, true);
  133. return $data['trxId'];
  134. }, array_filter($list, function($v) {
  135. return $v['msg_type'] == self::MSG_TYPE_REDPACK;
  136. }));
  137. $redpack = [];
  138. if ($trxIds) {
  139. $objRedpack = new Redpack();
  140. $redpack = $objRedpack->objTable->getAll(['transfer_trx_id' => $trxIds], ['_field' => 'transfer_trx_id, status']);
  141. $redpack = arrayFormatKey($redpack, 'transfer_trx_id', 'status');
  142. }
  143. foreach ($list as $k => $v) {
  144. if ($v['msg_type'] == self::MSG_TYPE_REDPACK) {
  145. $msg = Utils::decodeRC4($v['msg']);
  146. $data = json_decode($msg, true);
  147. $trxId = $data['trxId'];
  148. $v['ext']['grabbed'] = $objRedpackLog->userGrabbed($userId, $trxId);
  149. $v['ext']['redpack_status'] = intval($redpack[$trxId]);
  150. }
  151. $list[$k] = $v;
  152. }
  153. return $list;
  154. }
  155. public function getUserMap($user_ids) {
  156. $objUserInfo = new TableHelper('user_info', 'dw_chat');
  157. $datas = $objUserInfo->getAll(['user_id' => $user_ids], ['_field' => 'user_id, user_name, nick_name, cover_photo']);
  158. return arrayFormatKey($datas, 'user_id');
  159. }
  160. /**
  161. * 修改状态
  162. * @param $session_id
  163. * @param $newData
  164. * @param $ext;
  165. */
  166. public function updateState($session_id, $newData, $ext = []) {
  167. $where = compact('session_id');
  168. $where = array_merge($where, $ext);
  169. $newData['update_time'] = NOW;
  170. $newData['update_time_int'] = microtime(true) * 1000;
  171. $this->objTable->updateObject($newData, $where);
  172. }
  173. /**
  174. * 检测私聊session
  175. * @author solu
  176. * @param $from
  177. * @param $sessionId
  178. * @return array
  179. * @throws Exception
  180. */
  181. public function checkPersonSession($from, $sessionId) {
  182. $uids = explode('-', $sessionId);
  183. $uids = array_filter($uids, function ($v) {return $v > 0;});
  184. // if (count($uids) != 2 || !$this->objTable->getRow(['user_id' => $from, 'session_id' => $sessionId])) {
  185. // throw new Exception('session_id error', CODE_PARAM_ERROR);
  186. // }
  187. if (!in_array($from, $uids)) {
  188. throw new Exception('user not in session', CODE_NO_PERMITION);
  189. }
  190. $to = 0;
  191. foreach ($uids as $uid) {
  192. if ($uid != $from) {
  193. $to = $uid;
  194. break;
  195. }
  196. }
  197. return [$from, $to];
  198. }
  199. /**
  200. * 检测群session
  201. * @author solu
  202. * @param $from
  203. * @param $sessionId
  204. * @return bool
  205. * @throws Exception
  206. */
  207. public function checkGroupSession($from, $sessionId) {
  208. if (!$this->objTable->getRow(['user_id' => $from, 'session_id' => $sessionId])) {
  209. throw new Exception('user not in session', CODE_NO_PERMITION);
  210. }
  211. return true;
  212. }
  213. public static function getPersonSessionId($from, $to) {
  214. if ($from > $to) {
  215. return "{$to}-{$from}";
  216. } else {
  217. return "{$from}-{$to}";
  218. }
  219. }
  220. private function initPersonSession($from, $to) {
  221. $session_id = self::getPersonSessionId($from, $to);
  222. $num = $this->objTable->getCount(compact('session_id'));
  223. if (!$num) {
  224. // 插入双方的session
  225. $datas = [[
  226. 'user_id' => $from,
  227. 'session_id' => $session_id,
  228. 'is_group' => 0,
  229. ], [
  230. 'user_id' => $to,
  231. 'session_id' => $session_id,
  232. 'is_group' => 0,
  233. ]
  234. ];
  235. // 第一次初始化,需要初始化
  236. $this->objTable->addObjectsIfNoExist($datas);
  237. }
  238. }
  239. /**
  240. * 发送私聊消息
  241. * @author solu
  242. * @param $from
  243. * @param $sessionId
  244. * @param $msg_type
  245. * @param $msg
  246. * @param $noEvent
  247. * @return array
  248. * @throws Exception
  249. */
  250. public function sendPersonMsg($from, $sessionId, $msg_type, $msg, $noEvent = false) {
  251. list($from, $to) = $this->checkPersonSession($from, $sessionId);
  252. $this->initPersonSession($from, $to);
  253. $t = self::getMS();
  254. 0 == $msg_type && $msg = htmlentities($msg);
  255. $data = [
  256. 'session_id' => $sessionId,
  257. 'from' => intval($from),
  258. 'to' => intval($to),
  259. 'msg_type' => $msg_type,
  260. 'msg' => $msg,
  261. 'create_time' => NOW,
  262. 'create_time_int' => $t,
  263. ];
  264. $data['hash'] = self::_genHash($data);
  265. $objPersonMsg = new TableHelper('person_msg', 'dw_chat');
  266. if (!$objPersonMsg->addObject($data)) {
  267. throw new Exception('send message error', CODE_NORMAL_ERROR);
  268. }
  269. $eventData = [
  270. 'type' => 'msg',
  271. 'from' => $from,
  272. 'to' => strval($to),
  273. 'content' => self::_msgHandle($msg, $msg_type),
  274. 'hash' => $data['hash'],
  275. 'timestamp' => $t,
  276. ];
  277. !$noEvent && ThirdApi::pushPersonEvent($to, $eventData);
  278. $this->updateState($sessionId, []);
  279. $eventData['content'] = $msg;
  280. return $eventData;
  281. }
  282. /**
  283. * 发送群聊消息
  284. * @author solu
  285. * @param $from
  286. * @param $groupId
  287. * @param $msg_type
  288. * @param $msg
  289. * @param $noEvent
  290. * @return array
  291. * @throws Exception
  292. */
  293. public function sendGroupMsg($from, $groupId, $msg_type, $msg, $noEvent = false) {
  294. $userMap = null;
  295. if (!$this->objTable->getRow(['user_id' => $from, 'session_id' => $groupId])) {
  296. // 聊天就自动加入群
  297. $objGroup = new GroupInfo();
  298. $objGroup->joinGroup($from, $groupId);
  299. // 第一次发言,需要返回用户信息
  300. $userMap = $this->getUserMap($from);
  301. } else if ((new UserGroup())->isBlock($groupId, $from)) {
  302. throw new Exception('Banned', CODE_NORMAL_ERROR);
  303. }
  304. $t = self::getMS();
  305. 0 == $msg_type && $msg = htmlentities($msg);
  306. $data = [
  307. 'group_id' => intval($groupId),
  308. 'from' => $from,
  309. 'msg_type' => $msg_type,
  310. 'msg' => $msg,
  311. 'create_time' => NOW,
  312. 'create_time_int' => $t,
  313. ];
  314. $data['hash'] = self::_genHash($data);
  315. $objGroupMsg = new TableHelper('group_msg', 'dw_chat');
  316. if (!$objGroupMsg->addObject($data)) {
  317. throw new Exception('send message error', CODE_NORMAL_ERROR);
  318. }
  319. $eventData = [
  320. 'type' => 'msg',
  321. 'msg_type' => $msg_type,
  322. 'from' => $from,
  323. 'content' => self::_msgHandle($msg, $msg_type),
  324. 'hash' => $data['hash'],
  325. 'timestamp' => $t,
  326. ];
  327. !$noEvent && ThirdApi::pushGroupEvent($groupId, $eventData);
  328. $eventData['content'] = $msg;
  329. $eventData['userMap'] = $userMap;
  330. return $eventData;
  331. }
  332. private static function _genHash($data) {
  333. return md5(json_encode($data));
  334. }
  335. public static function _msgHandle($content, $msg_type, $len = 16) {
  336. if ($msg_type > 0) { // 只处理文本
  337. return $content;
  338. }
  339. $source = Utils::decodeRC4($content);
  340. !$source && $source = $content;
  341. if (mb_strlen($source) > $len) {
  342. $source = mb_substr($source, 0, $len);
  343. }
  344. return Utils::encodeRC4($source);
  345. }
  346. public static function getMS() {
  347. return intval(microtime(true) * 1000);
  348. }
  349. }