$groupId]; !$group && $group = $this->objTable->getRow($where); if (!$group || $group['state'] != self::STATE_USE) { throw new Exception('group not exists', CODE_PARAM_ERROR); } $objSession = new Session(); $objUserGroup = new TableHelper('user_group', 'dw_chat'); $row = $objUserGroup->getRow(['user_id' => $userId, 'group_id' => $groupId, 'state' => UserGroup::STATE_IN_GROUP]); if (!$row) { $data = [ 'user_id' => $userId, 'group_id' => $groupId, 'join_time' => NOW, 'state' => UserGroup::STATE_IN_GROUP, ]; if (!$objUserGroup->replaceObject($data)) { throw new Exception('join fail', CODE_DB_ERROR); } $memberNum = $group['member_num'] + 1; $where['member_num'] = $group['member_num']; if (!$this->objTable->updateObject(['member_num' => $memberNum], $where)) { throw new Exception('update group info fail', CODE_DB_ERROR); } // 给自己发消息订阅新群组 ThirdApi::pushPersonEvent($userId, [ 'type' => 'join_group', 'group_id' => $groupId, ]); // 发群消息 try { $objSession->sendGroupMsg($userId, $groupId, Session::MSG_TYPE_EVENT, '', false, true, ['event_type' => 'join']); } catch (Exception $e) { var_log($e->getMessage()); } // $user_info = User::getUserInfoById($userId); // // 给群组发消息有人加入了 // ThirdApi::pushGroupEvent($groupId, [ // 'type' => 'join', // 'group_id' => $groupId, // 'user_info' => $user_info, // ]); } $where = [ 'user_id' => $userId, 'session_id' => $groupId, ]; // 有可能删除了会话 if (!$objSession->objTable->getCount($where)) { $sessData = $where; $sessData['is_group'] = 1; $objSession->objTable->replaceObject($sessData); } return true; } /** * 加入群组 * @author solu * @param $userId * @param $groupId * @param $group * @param $memberNum * @return bool * @throws Exception */ public function appendToGroup($userIds, $groupId, $memberNum = 0) { $userGroupDatas = []; $sessDatas = []; foreach ($userIds as $userId) { $userGroupDatas[] = [ 'user_id' => $userId, 'group_id' => $groupId, 'join_time' => NOW, 'state' => UserGroup::STATE_IN_GROUP, ]; $sessDatas[] = [ 'user_id' => $userId, 'session_id' => $groupId, 'is_group' => 1, ]; } $objUserGroup = new UserGroup(); $objUserGroup->objTable->replaceObjects2($userGroupDatas); $objSession = new Session(); $objSession->objTable->replaceObjects2($sessDatas); $where = ['group_id' => $groupId]; $newData = [ 'member_num' => count($userIds) + $memberNum, 'group_name' => $groupId, ]; $this->objTable->updateObject($newData, $where); } /** * 离开群组 * @author solu * @param $userId * @param $groupId * @param $group * @return bool * @throws Exception */ public function leaveGroup($userId, $groupId, $group = []) { $groupId = (int) $groupId; $where = ['group_id' => $groupId]; !$group && $group = $this->objTable->getRow($where); if (!$group) { throw new Exception('group not exists', CODE_PARAM_ERROR); } $objUserGroup = new UserGroup(); if (!$objUserGroup->inGroup($groupId, $userId)) { throw new Exception('not in group', CODE_PARAM_ERROR); } $groupUserIds = $objUserGroup->getUserIdListSortByAdminAndJoinTime($groupId); $isCreator = $this->isCreator($groupId, $userId); $objSession = new Session(); $objUserGroup->objTable->autoCommit(false); $ugWhere = [ 'user_id' => $userId, 'group_id' => $groupId, ]; if (!$objUserGroup->objTable->updateObject(['state' => UserGroup::STATE_LEAVE, 'is_admin' => 0], $ugWhere)) { throw new Exception('leave fail', CODE_DB_ERROR); } $creatorField = ''; if (count($groupUserIds) == 1) { // 最后一个人离开,去掉群主,群解散 $creatorField = ' , creator=0'; } elseif ($isCreator) { // 群主离开, 群主顺移给下一位 $newCreator = 0; for ($i = 0; $i < count($groupUserIds); $i++) { if ($groupUserIds[$i] == $userId) { continue; } $newCreator = $groupUserIds[$i]; break; } $creatorField = " , creator={$newCreator}"; // 新群主设置成管理员 $objUserGroup->setData($groupId, $newCreator, ['is_admin' => 1]); } $sql = "UPDATE group_info SET member_num = member_num - 1 {$creatorField} WHERE group_id = {$groupId}"; $this->objDb->update($sql); $sessWhere = [ 'user_id' => $userId, 'session_id' => $groupId, ]; if (!$objSession->objTable->delObject($sessWhere)) { throw new Exception('delete session error', CODE_DB_ERROR); } $objUserGroup->objTable->commit(); // 发群消息 try { $objSession->sendGroupMsg($userId, $groupId, Session::MSG_TYPE_EVENT, '', false, true, ['event_type' => 'leave_group']); } catch (Exception $e) { var_log($e->getMessage()); } // 给自己发消息订阅新群组 ThirdApi::pushPersonEvent($userId, [ 'type' => 'leave_group', 'group_id' => $groupId, ]); // $user_info = User::getUserInfoById($userId); // // // 给群组发消息有人离开了 // ThirdApi::pushGroupEvent($groupId, [ // 'type' => 'leave', // 'group_id' => $groupId, // 'user_id' => $userId, // 'user_info' => $user_info, // ]); return true; } /** * 更新信息 * @author solu * @param $userId * @param $groupId * @param array $data * @return bool|int * @throws Exception */ public function setData($userId, $groupId, array $data) { if (!(new UserGroup())->isAdmin($groupId, $userId)) { throw new Exception('no permission', CODE_NO_PERMITION); } $data['update_time'] = NOW; return $this->objTable->updateObject($data, ['group_id' => $groupId]); } /** * 分享连接 * @author solu * @param string $name * @return string */ public static function genInviteUrl($name) { if (!$name) { return ''; } return sprintf('%s/s/%s', URL_SELF, $name); } /** * 是否群主 * @author solu * @param $groupId * @param $userId * @return bool */ public function isCreator($groupId, $userId) { $creator = $this->objTable->getOne(['group_id' => $groupId], ['_field' => 'creator']); return intval($creator) == $userId; } /** * 设置群管理 * @author solu * @param $groupId * @param $creator * @param $userIds * @return bool * @throws Exception */ public function addAdmin($groupId, $creator, $userIds) { if (!$this->isCreator($groupId, $creator)) { throw new Exception('no permission', CODE_NO_PERMITION); } $objUserGroup = new UserGroup(); $c = $objUserGroup->objTable->getCount(['group_id' => $groupId, 'is_admin' => 1]); $c += count($userIds); if ($c > self::MAX_ADMIN_COUNT) { throw new Exception('too many admins', CODE_NORMAL_ERROR); } if (!$objUserGroup->setData($groupId, $userIds, ['is_admin' => 1])) { throw new Exception('set admin fail', CODE_NORMAL_ERROR); } return true; } /** * 移除管理员 * @author solu * @param $groupId * @param $creator * @param $userId * @return bool * @throws Exception */ public function removeAdmin($groupId, $creator, $userId) { if (!$this->isCreator($groupId, $creator)) { throw new Exception('no permission', CODE_NO_PERMITION); } if ($userId == $creator) { throw new Exception('can not remove creator', CODE_NORMAL_ERROR); } $objUserGroup = new UserGroup(); if (!$objUserGroup->setData($groupId, $userId, ['is_admin' => 0])) { throw new Exception('set admin fail', CODE_NORMAL_ERROR); } return true; } /** * 搜索群用户信息 * @author solu * @param $groupId * @param $keyword * @return array */ public function memberSearch($groupId, $keyword) { $objUserGroup = new UserGroup(); $userIds = $objUserGroup->objTable->getCol(['group_id' => $groupId], ['_field' => 'user_id']); if (!$userIds) { return []; } $objUserInfo = new TableHelper('user_info', 'dw_chat'); // $keyword 是外部传来的参数,会有注入攻击 $keyword = $objUserInfo->escape($keyword); $userInfo = $objUserInfo->getAll(['user_id' => $userIds], [ '_where' => "(user_name like '{$keyword}%' || nick_name like '{$keyword}%')", '_field' => 'user_id, user_name, nick_name, cover_photo', '_sortKey' => 'last_login_time DESC', // '_debug' => true, ]); coverReplaceArrImage($userInfo, 'cover_photo'); return $userInfo; } /** * 获取用户名 * @author solu * @param $groupId * @return string */ public static function getGroupNameById($groupId) { $objRedis = dwRedis::init(); $userName = $objRedis->hGet(self::REDIS_GROUP_ID_HASH, $groupId); if (!$userName) { $obj = new GroupInfo(); $userName = $obj->objTable->getOne(['group_id' => $groupId], ['_field' => 'group_title']); if ($userName) { self::setGroupNameById($groupId, $userName, $objRedis); } } return $userName; } public static function setGroupNameById($groupId, $user_name, $objRedis = null) { !$objRedis && $objRedis = dwRedis::init(); $objRedis->hSet(self::REDIS_GROUP_ID_HASH, $groupId, $user_name); } /** * 转移群主 * @author solu * @param $groupId * @param $old * @param $new * @return bool * @throws Exception */ public function changeCreator($groupId, $old, $new) { if (!$this->isCreator($groupId, $old)) { throw new Exception('no permission', CODE_NO_PERMITION); } if ($old == $new) { throw new Exception('same creator', CODE_NORMAL_ERROR); } $this->objTable->updateObject(['creator' => $new], ['group_id' => $groupId]); (new UserGroup())->setData($groupId, $old, ['is_admin' => 0]); return true; } /** * 获取客服id * @author solu * @param $userIds * @return array */ public function getGroupServerFromUserIds($userIds) { $items = $this->objTable->getAll(['server_id' => $userIds], ['_field' => 'group_id, server_id']); return arrayFormatKey($items, 'server_id', 'group_id'); } public function checkPermission($group_id, $user_id) { $_field = 'is_public'; $objGroupInfo = new GroupInfo(); $is_public = (int) $objGroupInfo->objTable->getOne(['group_id' => $group_id], compact('_field')); if (!$is_public) { // 私有群要判断用户是否存在 if ($user_id) { $objUserGroup = new UserGroup(); $state = 1; $count = $objUserGroup->objTable->getCount(compact('group_id', 'user_id', 'state')); if (!$count) { Response::error(CODE_NO_PERMITION, 'the group is private'); } } else { Response::error(CODE_NO_PERMITION, 'the group is private'); } } } public function getGroupIdFromTgGroupId($tgGroupId) { $groupId = $this->objTable->getOne(['tg_group_id' => $tgGroupId], ['_field' => 'group_id']); return intval($groupId); } /** * 热门群组 * @return array */ public function getHotList() { $list = $this->objTable->getAll(['is_auth' => 1, 'is_public' => 1], ['_limit' => 100]); $fillNum = 24 - count($list); if ($fillNum > 0) { // 找用户自发来补充 $keyWord = ['_limit' => 200, '_sortKey' => 'member_num DESC']; $list2 = $this->objTable->getAll(['is_auth' => 0, 'is_public' => 1], $keyWord); // 随机取10个 $list2 = $this->array_random_assoc($list2, 24 - count($list)); $list = array_merge($list, $list2); } $group_ids = array_column($list, 'group_id'); $existList = []; $userId = User::getUserId(); if ($userId) { $_field = 'group_id'; $objUserGroup = new UserGroup(); $where = ['group_id' => $group_ids, 'state' => 1, 'user_id' => $userId]; $existList = $objUserGroup->objTable->getCol($where, ['_field' => $_field]); } foreach ($list as $i => $value) { $value['is_join'] = in_array($value['group_id'], $existList) ? 1 : 0; $value['cover_photo'] = awsReplaceImg($value['cover_photo']); $list[$i] = $value; } return $list; } private function array_random_assoc($arr, $num = 1) { $keys = array_keys($arr); shuffle($keys); $r = array(); for ($i = 0; $i < $num; $i++) { $r[$keys[$i]] = $arr[$keys[$i]]; } return $r; } /** * 创建群 * @param $args * @return array|null * @throws Exception */ public function create($args) { $creator = $args['creator']; $user_id_list = arrayPop($args, 'user_id_list'); if (!$creator) { throw new Exception("miss creator", CODE_PARAM_ERROR); } $state = self::STATE_USE; $num = $this->objTable->getCount(compact('creator', 'state')); if ($num >= 100) { throw new Exception("create group num >= {$num}", CODE_NO_PERMITION); } $args['server_id'] = $args['creator']; $memberNum = 0; $args['member_num'] = $memberNum; $args['create_time'] = $args['update_time'] = NOW; $this->objTable->addObject($args); $group_id = $this->objTable->getInsertId(); // 设置group_name $this->objTable->updateObject(['group_name' => $group_id], ['group_id' => $group_id]); // 默认加群 $this->joinGroup($creator, $group_id); $memberNum++; // 设置为管理员 $objUserGroup = new UserGroup(); $data = [ 'is_admin' => 1, 'state' => UserGroup::STATE_IN_GROUP, ]; $objUserGroup->setData($group_id, $creator, $data); $friend_ids = $this->_getFriendList($creator, $user_id_list); if ($friend_ids) { $this->appendToGroup($friend_ids, $group_id, $memberNum); } $objSession = new Session(); $_field = 'session_id, is_group, read_hash, is_pin, pin_time_int, is_mute'; $sesion = $objSession->objTable->getRow(['session_id' => $group_id], compact('_field')); $sesion['name'] = $args['group_title']; $sesion['cover_photo'] = $args['cover_photo']; return $sesion; } // 只过滤出真正的朋友 private function _getFriendList($userId, $friend_id_list) { $friend_ids = explode(',', $friend_id_list); $map = []; foreach ($friend_ids as $friend_id) { $friend_id = (int) $friend_id; $sessionId = Session::getPersonSessionId($userId, $friend_id); $map[$sessionId] = $friend_id; } if (!$map) { return []; } $where = [ 'user_id' => $userId, 'session_id' => array_keys($map), ]; $_field = 'session_id'; $objSession = new Session(); $sessionIds = $objSession->objTable->getCol($where, compact('_field')); if (!$sessionIds) return []; $friend_ids = []; foreach ($sessionIds as $sessionId) { $friend_ids[] = $map[$sessionId]; } return $friend_ids; } /** * 删除群 * @author solu * @param $creator * @param $groupId * @return bool * @throws Exception */ public function discard($creator, $groupId) { if (!$this->objTable->getRow(['group_id' => $groupId, 'creator' => $creator])) { throw new Exception('group not found', CODE_PARAM_ERROR); } $objUserGroup = new UserGroup(); $objSession = new Session(); $this->objTable->autoCommit(false); $this->objTable->updateObject(['member_num' => 0, 'state' => self::STATE_DISCARD], ['group_id' => $groupId]); $objUserGroup->objTable->updateObject(['state' => UserGroup::STATE_LEAVE], ['group_id' => $groupId]); $objSession->objTable->delObject(['session_id' => $groupId, 'is_group' => 1]); $this->objTable->commit(); return true; } }