'); $text = preg_replace_callback("/\<(blockquote|strong|pre|ol|ul|em|p|s|u)(.*?)\>/is", function (array $match) { // 不用去除 li 和 a 标签,上面已经处理过了 preg_match("/<[^>]*?style=([\"'])(.*?)\\1[^>]*?>/is", $match[0], $matchs); $attach = ''; if ($matchs) { $styleArray = explode(';', $matchs[2]); $validStyles = array_filter($styleArray, function ($styleItem) { return preg_match('/\s*(?:color|font-size|background-color|font-weight|font-family|text-decoration|font-style)\s*:/i', $styleItem); // 只保留指定样式 }); if ($validStyles) { $attach = ' style="' . implode(';', $validStyles) . '"'; } } return "<{$match[1]}{$attach}>"; }, $text); $text = preg_replace_callback("/\[:LINK:(.*?):(.*?):\]/i", function (array $match) { return "" . base64_decode($match[2]) . ""; }, $text); $text = preg_replace_callback("/\[:IMAGE:(.*?):(.*?):(.*?):(.*?):(.*?):\]/i", function (array $match) { $wh = $match[2] === 'auto' ? "" : " width=\"{$match[2]}\" height=\"{$match[3]}\""; $src = str_starts_with($match[4], "base64-") ? base64_decode(substr($match[4], 7)) : "{{RemoteURL}}{$match[4]}"; return ""; }, $text); $text = preg_replace("/\[:@:(.*?):(.*?):\]/i", "@$2", $text); $text = preg_replace("/\[:#:(.*?):(.*?):\]/is", "#$2", $text); $text = preg_replace("/\[:~:(.*?):(.*?):\]/i", "~$2", $text); $text = preg_replace("/\[:QUICK:(.*?):(.*?):\]/i", "$2", $text); return preg_replace("/^(
<\/p>)+|(
<\/p>)+$/i", "", $text); } /** * 发送消息、修改消息 * @param string $action 动作 * - reply-98:回复消息ID=98 * - update-99:更新消息ID=99(标记修改) * - change-99:更新消息ID=99(不标记修改) * - forward-99:转发消息ID=99 * @param int $dialog_id 会话ID(即 聊天室ID) * @param string $type 消息类型 * @param array $msg 发送的消息 * @param int|null $sender 发送的会员ID(默认自己,0为系统) * @param bool $push_self 推送-是否推给自己 * @param bool $push_retry 推送-失败后重试1次(有时候在事务里执行,数据还没生成时会出现找不到消息的情况) * @param bool|null $push_silence 推送-静默 * - type = [text|file|record|meeting] 默认为:false * @return array */ public static function sendMsg($action, $dialog_id, $type, $msg, $sender = null, $push_self = false, $push_retry = false, $push_silence = null) { $link = 0; $mtype = $type; if ($type === 'text') { if (str_contains($msg['text'], ' $item) { $aiUser = User::whereEmail($matchs[1][$key])->whereDisableAt(null)->first(); if ($aiUser) { $msg['text'] = str_replace($item, "userid}\">@{$aiUser->nickname}", $msg['text']); } } } elseif ($type === 'file') { if (in_array($msg['ext'], ['jpg', 'jpeg', 'webp', 'png', 'gif'])) { $mtype = 'image'; } } if ($push_silence === null) { $push_silence = !in_array($type, ["text", "file", "record", "meeting"]); } // $update_id = intval(preg_match("/^update-(\d+)$/", $action, $match) ? $match[1] : 0); $change_id = intval(preg_match("/^change-(\d+)$/", $action, $match) ? $match[1] : 0); $reply_id = intval(preg_match("/^reply-(\d+)$/", $action, $match) ? $match[1] : 0); $forward_id = intval(preg_match("/^forward-(\d+)$/", $action, $match) ? $match[1] : 0); $sender = $sender === null ? User::userid() : $sender; // $dialog = WebSocketDialog::find($dialog_id); if (empty($dialog)) { throw new ApiException('获取会话失败'); } if ($sender > 0) { $dialog->checkMute($sender); } // $modify = 1; if ($change_id) { $modify = 0; $update_id = $change_id; } if ($update_id) { // 修改 $dialogMsg = self::whereId($update_id)->whereDialogId($dialog_id)->first(); if (empty($dialogMsg)) { throw new ApiException('消息不存在'); } $oldMsg = Base::json2array($dialogMsg->getRawOriginal('msg')); if ($dialogMsg->type === 'vote') { if ($dialogMsg->userid != $sender) { $msg = [ 'votes' => $msg['votes'], ]; } } else { if ($dialogMsg->type !== 'text') { throw new ApiException('此消息不支持此操作'); } if ($dialogMsg->userid != $sender) { throw new ApiException('仅支持修改自己的消息'); } } // $updateData = [ 'mtype' => $mtype, 'link' => $link, 'msg' => array_merge($oldMsg, $msg), 'modify' => $modify, ]; $dialogMsg->updateInstance($updateData); $dialogMsg->key = $dialogMsg->generateMsgKey(); $dialogMsg->save(); // WebSocketDialogUser::whereDialogId($dialog->id)->whereUserid($sender)->whereHide(1)->change([ 'hide' => 0, // 修改消息时,显示会话(仅自己) 'updated_at' => Carbon::now()->toDateTimeString('millisecond'), ]); // $dialogMsg->msgJoinGroup($dialog); // $dialog->pushMsg('update', array_merge($updateData, [ 'id' => $dialogMsg->id ])); // return Base::retSuccess('修改成功', $dialogMsg); } else { // 发送 if ($reply_id) { // 回复 $replyRow = self::whereId($reply_id)->whereDialogId($dialog_id)->first(); if (empty($replyRow)) { throw new ApiException('回复的消息不存在'); } $replyMsg = Base::json2array($replyRow->getRawOriginal('msg')); unset($replyMsg['reply_data']); $msg['reply_data'] = [ 'id' => $replyRow->id, 'userid' => $replyRow->userid, 'type' => $replyRow->type, 'msg' => $replyMsg, ]; $replyRow->increment('reply_num'); } // $dialogMsg = self::createInstance([ 'dialog_id' => $dialog_id, 'dialog_type' => $dialog->type, 'reply_id' => $reply_id, 'forward_id' => $forward_id, 'userid' => $sender, 'type' => $type, 'mtype' => $mtype, 'link' => $link, 'msg' => $msg, 'read' => 0, ]); AbstractModel::transaction(function () use ($dialogMsg) { $dialogMsg->send = 1; $dialogMsg->key = $dialogMsg->generateMsgKey(); $dialogMsg->save(); // if ($dialogMsg->type === 'meeting') { MeetingMsg::createInstance([ 'meetingid' => $dialogMsg->msg['meetingid'], 'dialog_id' => $dialogMsg->dialog_id, 'msg_id' => $dialogMsg->id, ])->save(); } // WebSocketDialogUser::whereDialogId($dialogMsg->dialog_id)->change([ 'hide' => 0, // 有新消息时,显示会话(会话内所有会员) 'last_at' => Carbon::now(), 'updated_at' => Carbon::now()->toDateTimeString('millisecond'), ]); }); // $task = new WebSocketDialogMsgTask($dialogMsg->id); if ($push_self) { $task->setIgnoreFd(null); } if ($push_retry) { $task->setMsgNotExistRetry(true); } if ($push_silence) { $task->setSilence($push_silence); } Task::deliver($task); // return Base::retSuccess('发送成功', $dialogMsg); } } /** * 将被@的人加入群 * @param WebSocketDialog $dialog 对话 * @return array */ public function msgJoinGroup(WebSocketDialog $dialog) { $updateds = []; $silences = []; foreach ($dialog->dialogUser as $dialogUser) { $updateds[$dialogUser->userid] = $dialogUser->updated_at; $silences[$dialogUser->userid] = $dialogUser->silence; } $userids = array_keys($silences); // 提及会员 $mentions = []; if ($this->type === 'text') { preg_match_all("//", $this->msg['text'], $matchs); if ($matchs) { $mentions = array_values(array_filter(array_unique($matchs[1]))); } } // 将会话以外的成员加入会话内 $diffids = array_values(array_diff($mentions, $userids)); if ($diffids) { // 仅(群聊)且(是群主或没有群主)才可以@成员以外的人 if ($dialog->type === 'group' && in_array($dialog->owner_id, [0, $this->userid])) { $dialog->joinGroup($diffids, $this->userid); $dialog->pushMsg("groupJoin", null, $diffids); $userids = array_values(array_unique(array_merge($mentions, $userids))); } } return compact('updateds', 'silences', 'userids', 'mentions'); } }