diff --git a/cmdRoute.php b/cmdRoute.php
index d14ff1f..b751084 100644
--- a/cmdRoute.php
+++ b/cmdRoute.php
@@ -1,22 +1,22 @@
'127.0.0.1',
+ 'port' => 6379,
+ 'passwd' => '',
+ 'prefix' => 'tgdc-'
+ );
+
+ private function getDcDetail($dc) { // 获取DC信息
+ switch ($dc) {
+ case 'DC1':
+ return array(
+ 'as' => 'AS59930',
+ 'ip' => '149.154.175.0/24',
+ 'addr' => '美国佛罗里达州迈阿密'
+ );
+ case 'DC2':
+ case 'DC3':
+ case 'DC4':
+ return array(
+ 'as' => 'AS62041',
+ 'ip' => '149.154.160.0/21',
+ 'addr' => '荷兰阿姆斯特丹'
+ );
+ case 'DC5':
+ return array(
+ 'as' => 'AS62014',
+ 'ip' => '149.154.168.0/22',
+ 'addr' => '新加坡'
+ );
+ default:
+ return array();
+ }
+ }
+
+ private function curl($url) { // curl模拟 5s超时
+ $curl = curl_init();
+ curl_setopt($curl, CURLOPT_URL, $url);
+ curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
+ curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, 5);
+ $content = curl_exec($curl);
+ curl_close($curl);
+ return $content;
+ }
+
+ private function getRedisData($account) { // 查询Redis缓存,不存在返回NULL
+ $redis = new Redis();
+ $redis->connect(tgDC::redisSetting['host'], tgDC::redisSetting['port']);
+ if (tgDC::redisSetting['passwd'] != '') {
+ $redis->auth(tgDC::redisSetting['passwd']);
+ }
+ $redisKey = tgDC::redisSetting['prefix'] . $account;
+ $redisValue = $redis->exists($redisKey) ? $redis->get($redisKey) : NULL;
+ return $redisValue;
+ }
+
+ private function setRedisData($account, $data, $cacheTTL = 600000) { // 写入信息到Redis缓存
+ $redis = new Redis();
+ $redis->connect(tgDC::redisSetting['host'], tgDC::redisSetting['port']);
+ if (tgDC::redisSetting['passwd'] != '') {
+ $redis->auth(tgDC::redisSetting['passwd']);
+ }
+ $redisKey = tgDC::redisSetting['prefix'] . $account;
+ $redis->set($redisKey, $data); // 写入数据库
+ $redis->pexpire($redisKey, $cacheTTL); // 设置过期时间 默认十分钟
+ }
+
+ private function checkAccount($account) { // 检查用户名是否合法
+ preg_match('/^[a-zA-Z0-9_]+$/', $account, $match);
+ if (count($match) === 0 or strlen($account) < 5) { // 用户名由至少5位 0-9/a-z/A-Z/_ 组成
+ return false;
+ }
+ if (substr($account, 0, 1) === '_' || substr($account, -1) === '_') { // 不能以_开头结尾
+ return false;
+ }
+ return true;
+ }
+
+ private function getTgUserInfo($account) { // 获取Telegram用户信息
+ $info['account'] = $account;
+ $info['name'] = null;
+ $info['dc'] = null;
+
+ $html = $this->curl('https://t.me/' . $account); // 获取原始HTML数据
+ $html = preg_replace('/[\t\n\r]+/', '', $html); // 去除干扰
+ if (!is_string($html) || $html == '') { return $info; } // 用户名无效
+
+ $avatarRegex = '//';
+ $nameRegex = '/(.+?)<\/span>/';
+ preg_match_all($avatarRegex, $html, $avatarMatch); // 匹配目标头像
+ preg_match_all($nameRegex, $html, $nameMatch); // 匹配目标名称
+
+ if ($nameMatch[1]) {
+ $info['name'] = $nameMatch[1][0]; // 获取用户名
+ }
+ if ($avatarMatch[1]) {
+ $avatarUrl = $avatarMatch[1][0]; // 获取头像链接
+ }
+ if ($avatarUrl) { // 头像存在
+ $dcRegex = '/https:\/\/cdn(.+)\.telesco\.pe\//';
+ preg_match_all($dcRegex, $avatarUrl, $dcMatch); // 根据cdn?.telesco.pe获取DC
+ if ($dcMatch[1]) {
+ $info['dc'] = 'DC' . $dcMatch[1][0];
+ }
+ }
+ if ($info['dc']) {
+ $info += $this->getDcDetail($info['dc']); // 匹配DC参数
+ }
+ return $info;
+ }
+
+ private function getUserInfo($account) { // 获取用户信息,带缓存
+ $info = $this->getRedisData($account); // 查询缓存数据
+ if (!$info) { // 缓存未命中
+ $info = $this->getTgUserInfo($account); // 发起查询
+ if (!$info['name'] && !$info['dc']) { // 用户名与头像均无
+ $cacheTTL = 120000; // 缓存2min
+ } else if ($info['name'] && !$info['dc']) { // 存在用户名但未设置头像
+ $cacheTTL = 20000; // 缓存20s
+ } else {
+ $cacheTTL = 600000; // 其余情况缓存10min
+ }
+ $this->setRedisData($account, json_encode($info), $cacheTTL); // 缓存数据
+ } else { // 缓存命中
+ $info = json_decode($info, true); // 使用缓存数据
+ }
+ return $info;
+ }
+
+ public function getInfo($account) { // 外部调用入口
+ if (substr($account, 0, 1) === '@') { // 用户名前可带有@
+ $account = substr($account, 1);
+ }
+ if (!$this->checkAccount($account)) { // 用户名不合法
+ return array(
+ 'text' => '用户名无效'
+ );
+ }
+ $info = $this->getUserInfo($account);
+ if (!$info['name'] && !$info['dc']) { // 用户名与头像均无
+ return array(
+ 'text' => '@' . $info['account'] . ' 无法识别'
+ );
+ } else if ($info['name'] && !$info['dc']) { // 存在用户名但未设置头像
+ return array(
+ 'text' => '@' . $info['account'] . ' 未设置头像或不可见'
+ );
+ }
+ $msg = '@' . $info['account'] . ' (' . $info['name'] . ')' . PHP_EOL;
+ $msg .= '' . $info['as'] . ' (' . $info['ip'] . ')
' . PHP_EOL;
+ $msg .= '' . $info['dc'] . ' - ' . $info['addr'] . PHP_EOL;
+ return array(
+ 'parse_mode' => 'HTML', // HTML格式输出
+ 'text' => $msg
+ );
+ }
+}
+
+function tgDC($rawParam) { // DC查询入口
+ global $chatId, $userAccount;
+ if ($rawParam === '') {
+ $rawParam = $userAccount;
+ }
+ sendMessage($chatId, (new tgDC)->getInfo($rawParam));
+}
+
+?>
\ No newline at end of file