123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453 |
- <?php
- /**
- * Created by IntelliJ IDEA.
- * User: solu
- * Date: 2019/3/26
- * Time: 5:38 PM
- */
- class Telegram {
- const REDIS_PREFIX_TG_CSRF = 'globals:tg_csrf:';
- const REDIS_TG_CSRF_TTL = 60;
- const REDIS_TG_GROUP_TO_GROUP_HASH = 'globals:tg_group_to_group_hash';
- const REDIS_TG_USER_TO_USER_HASH = 'globals:tg_user_to_user_hash';
- const REDIS_TG_MESSAGE_LIST = 'globals:tg_message_list';
- private static $messageTypes = [
- 'sticker',
- 'photo',
- 'audio',
- 'video_note',
- 'video'
- ];
- /**
- * @param $message
- * @throws Exception
- */
- public static function processMessage($message) {
- // process incoming message
- // $message_id = $message['message_id'];
- $chat_id = $message['chat']['id'];
- $chatType = $message['chat']['type'];
- $from = $message['from']['id'];
- // 处理登录,绑定
- if (strpos($message['text'], '/start') !== false) {
- list($_, $token) = explode(' ', $message['text']);
- $user_id = $from;
- if (strpos($token, 'login') !== false) {
- $name = $message['chat']['first_name'];
- $message['chat']['last_name'] && $name .= "_{$message['chat']['last_name']}";
- $user_id = User::login($from, Account::TYPE_TG, $name);
- if ($user_id) {
- self::setUserByTG($from, $user_id);
- self::setCSRFStatus($token, $user_id);
- $text = 'You\'ve successfully logged in';
- } else {
- $text = 'Login failure';
- }
- } else if (strpos($token, 'bind') !== false) {
- self::setCSRFStatus($token, $user_id);
- $text = 'You\'ve successfully bind meechat account';
- } else if (strpos($token, 'sync') !== false) { // 群同步流程
- list($_, $groupId) = explode('_', $token);
- $groupId = intval($groupId);
- if (!$groupId) {
- $text = "Wrong operation!!";
- } else {
- $administrators = ThirdApi::getTelegramGroupAdministrators($groupId);
- if (in_array($from, $administrators)) {
- $text = self::buildSyncText($from, $groupId);
- } else {
- $text = "you are not administrator";
- }
- }
- } else {
- return;
- }
- self::apiRequest('sendMessage', [
- 'chat_id' => $from,
- 'text' => $text,
- 'parse_mode' => 'HTML',
- ]);
- return;
- }
- // 只转发群消息
- if (!in_array($chatType, ['group', 'supergroup'])) {
- return;
- }
- $objGroup = new GroupInfo();
- $objSession = new Session();
- // 处理升级为超级群的信息
- if (isset($message['migrate_from_chat_id'])) {
- $srcId = $message['migrate_from_chat_id'];
- $groupId = self::getGroupByTG($srcId);
- self::setGroupByTG($chat_id, $groupId);
- self::delGroupByTG($srcId);
- $objGroup->objTable->updateObject(['tg_group_id' => $chat_id], ['tg_group_id' => $srcId]);
- return;
- }
- $groupId = self::getGroupByTG($chat_id);
- if (!$groupId) {
- // 判断是否拉进MeeChat机器人
- $doGuide = false;
- if (isset($message['new_chat_members'])) {
- foreach ($message['new_chat_members'] as $member) {
- if ($member['id'] == BOT_ID) {
- $doGuide = true;
- break;
- }
- }
- }
- // 创建群的时候已拉入机器人
- if (isset($message['group_chat_created']) && $message['group_chat_created']) {
- $doGuide = true;
- }
- // 开始引导同步操作
- if ($doGuide) {
- $url = BOT_CHAT_URL . "?start=sync_{$chat_id}";
- $text = "点击<a href='{$url}'>@meechatbot</a>查看私聊信息,将该群与MeeChat群组进行关联同步
- To sync up this chat with MeeChat group, take a look to private message from <a href='{$url}'>@meechatbot</a>";
- self::apiRequest('sendMessage', [
- 'chat_id' => $chat_id,
- 'text' => $text,
- 'parse_mode' => 'HTML',
- ]);
- }
- return;
- }
- $userId = self::getUserByTG($from);
- !$userId && $userId = TG_BOT_ID;
- $extInfo = [
- 'is_tg' => 1,
- ];
- if ($userId == TG_BOT_ID) {
- $name = $message['from']['first_name'];
- $message['from']['last_name'] && $name .= "_{$message['from']['last_name']}";
- $extInfo['tg_nick'] = $name;
- }
- $msgType = Session::MSG_TYPE_TEXT;
- if (isset($message['text'])) { // 文本消息
- $text = $message['text'];
- // 不处理command
- if ($text[0] == '/') {
- return;
- }
- } else { // 图片视频音频
- $mineType = '';
- $fileId = '';
- foreach (self::$messageTypes as $messageType) {
- if (isset($message[$messageType])) {
- $entity = $message[$messageType];
- if ($messageType == 'photo') { // 图片会有多个尺寸,取原图
- $entity = array_pop($entity);
- }
- $fileId = $entity['file_id'];
- $mineType = $message[$messageType]['mime_type'] ?: '';
- break;
- }
- }
- if (!$fileId) {
- return;
- }
- // 标题
- if ($message['caption']) {
- $caption = $message['caption'];
- $caption = Utils::encodeRC4($caption);
- $objSession->sendGroupMsg($userId, $groupId, Session::MSG_TYPE_TEXT, $caption, false, true, $extInfo);
- }
- list($url, $mineType, $coverUrl) = self::getURLFromFileId($fileId, $mineType);
- $msgType = FileUrl::getType($mineType);
- $text = $url;
- $coverUrl && $extInfo['cover_url'] = $coverUrl;
- }
- $text = Utils::encodeRC4($text);
- $objSession->sendGroupMsg($userId, $groupId, $msgType, $text, false, true, $extInfo);
- }
- /**
- * 转存文件
- * @author solu
- * @param $fileId
- * @param string $mineType
- * @throws Exception
- * @return array
- */
- public static function getURLFromFileId($fileId, $mineType = '') {
- $tgFilePath = self::getFilePath($fileId);
- $url = TELEGRAM_FILE_URL . $tgFilePath;
- list($path, $filename, $_, $_) = Bs2UploadHelper::saveFileFromUrl($url);
- if (!$mineType) {
- $mineType = mime_content_type($path);
- }
- $objFile = new FileUrl();
- $url = $objFile->getFileUrl($path, $filename, $mineType);
- $url = awsReplaceImg($url);
- // 处理视频封面
- $coverUrl = '';
- if (strpos($mineType, 'video') !== false) {
- $coverUrl = $objFile->getVideoCover($path, $filename);
- $coverUrl = awsReplaceImg($coverUrl);
- }
- unlink($path);
- return [$url, $mineType, $coverUrl];
- }
- /**
- * 获取文件路径
- * @param $fileId
- * @return mixed
- * @throws Exception
- */
- private static function getFilePath($fileId) {
- $url = TELEGRAM_API_URL . 'getFile?file_id=' . $fileId;
- $objHttp = new dwHttp();
- $resp = $objHttp->get2($url);
- $data = json_decode($resp, true);
- if (!$data || !$data['ok']) {
- $msg = $data['description'] ?: 'get file info error';
- throw new Exception($msg, CODE_PARAM_ERROR);
- }
- return $data['result']['file_path'];
- }
- /**
- * @param $method
- * @param $parameters
- * @return bool|mixed
- * @throws Exception
- * @return mixed
- */
- public static function apiRequestJson($method, $parameters) {
- if (!is_string($method)) {
- throw new Exception("Method name must be a string\n");
- }
- if (!$parameters) {
- $parameters = array();
- } else if (!is_array($parameters)) {
- throw new Exception("Parameters must be an array\n");
- }
- $parameters["method"] = $method;
- $handle = curl_init(TELEGRAM_API_URL);
- curl_setopt($handle, CURLOPT_RETURNTRANSFER, true);
- curl_setopt($handle, CURLOPT_CONNECTTIMEOUT, 5);
- curl_setopt($handle, CURLOPT_TIMEOUT, 60);
- curl_setopt($handle, CURLOPT_POST, true);
- curl_setopt($handle, CURLOPT_POSTFIELDS, json_encode($parameters));
- curl_setopt($handle, CURLOPT_HTTPHEADER, array("Content-Type: application/json"));
- return self::exec_curl_request($handle);
- }
- /**
- * @param $method
- * @param $parameters
- * @return mixed
- * @throws Exception
- */
- public static function apiRequest($method, $parameters) {
- if (!is_string($method)) {
- throw new Exception("Method name must be a string\n");
- }
- if (!$parameters) {
- $parameters = array();
- } else if (!is_array($parameters)) {
- throw new Exception("Parameters must be an array\n");
- }
- foreach ($parameters as $key => &$val) {
- // encoding to JSON array parameters, for example reply_markup
- if (!is_numeric($val) && !is_string($val)) {
- $val = json_encode($val);
- }
- }
- $url = TELEGRAM_API_URL.$method.'?'.http_build_query($parameters);
- $handle = curl_init($url);
- curl_setopt($handle, CURLOPT_RETURNTRANSFER, true);
- curl_setopt($handle, CURLOPT_CONNECTTIMEOUT, 5);
- curl_setopt($handle, CURLOPT_TIMEOUT, 60);
- return self::exec_curl_request($handle);
- }
- /**
- * @param $handle
- * @return bool|mixed
- * @throws Exception
- * @return mixed
- */
- public static function exec_curl_request($handle) {
- $response = curl_exec($handle);
- if ($response === false) {
- $errno = curl_errno($handle);
- $error = curl_error($handle);
- curl_close($handle);
- throw new Exception("Curl returned error $errno: $error\n");
- }
- $http_code = intval(curl_getinfo($handle, CURLINFO_HTTP_CODE));
- curl_close($handle);
- if ($http_code >= 500) {
- // do not wat to DDOS server if something goes wrong
- sleep(10);
- return false;
- } else if ($http_code != 200) {
- $response = json_decode($response, true);
- throw new Exception("Request has failed with error {$response['error_code']}: {$response['description']}\n");
- } else {
- $response = json_decode($response, true);
- if (isset($response['description'])) {
- throw new Exception("Request was successful: {$response['description']}\n");
- }
- $response = $response['result'];
- }
- // file_put_contents('/tmp/telegram_message.log', $response, FILE_APPEND);
- return $response;
- }
- private static function getCSRFKey($token) {
- return self::REDIS_PREFIX_TG_CSRF . $token;
- }
- public static function initCSRF($token) {
- $objRedis = dwRedis::init();
- $key = self::getCSRFKey($token);
- $objRedis->setex($key, self::REDIS_TG_CSRF_TTL, 0);
- }
- /**
- * 获取状态
- * @author solu
- * @param $token
- * @return int
- */
- public static function getCSRFStatus($token) {
- $objRedis = dwRedis::init();
- $key = self::getCSRFKey($token);
- $status = $objRedis->get($key);
- return false !== $status ? intval($status) : -1;
- }
- public static function setCSRFStatus($token, $id) {
- $objRedis = dwRedis::init();
- $key = self::getCSRFKey($token);
- $objRedis->setex($key, self::REDIS_TG_CSRF_TTL, $id);
- }
- public static function setGroupByTG($tgGroup, $group) {
- $objRedis = dwRedis::init();
- $objRedis->hSet(self::REDIS_TG_GROUP_TO_GROUP_HASH, $tgGroup, $group);
- }
- public static function getGroupByTG($tgGroup) {
- $objRedis = dwRedis::init();
- return $objRedis->hGet(self::REDIS_TG_GROUP_TO_GROUP_HASH, $tgGroup);
- }
- public static function delGroupByTG($tgGroup) {
- $objRedis = dwRedis::init();
- return $objRedis->hDel(self::REDIS_TG_GROUP_TO_GROUP_HASH, $tgGroup);
- }
- public static function setUserByTG($tgUser, $user) {
- $objRedis = dwRedis::init();
- $objRedis->hSet(self::REDIS_TG_USER_TO_USER_HASH, $tgUser, $user);
- }
- public static function getUserByTG($tgUser) {
- $objRedis = dwRedis::init();
- return $objRedis->hGet(self::REDIS_TG_USER_TO_USER_HASH, $tgUser);
- }
- public static function delUserByTG($tgUser) {
- $objRedis = dwRedis::init();
- $objRedis->hDel(self::REDIS_TG_USER_TO_USER_HASH, $tgUser);
- }
- public static function pushMessageList($msg) {
- if (is_array($msg)) {
- $msg = json_encode($msg);
- }
- $objRedis = dwRedis::init();
- $objRedis->lPush(self::REDIS_TG_MESSAGE_LIST, $msg);
- }
- public static function popMessageList($objRedis = null) {
- !$objRedis && $objRedis = dwRedis::init();
- $ret = $objRedis->brPop([self::REDIS_TG_MESSAGE_LIST], 30);
- return $ret[1];
- }
- private static function buildSyncText($from, $chat_id) {
- $url = 'https://' . $_SERVER['HTTP_HOST'] . '/#/relateGroup?';
- $params = [
- 'admin_id' => $from,
- 'group_id' => $chat_id,
- 'auth_date' => time(),
- ];
- $params['hash'] = ThirdApi::genTelegramHash($params);
- $url .= http_build_query($params);
- return "<a href='{$url}'>点击选择你需要同步的MeeChat群组
- Click to choose your MeeChat group to sync up</a>";
- }
- }
|