Browse Source

refactor: new IP info model

dev
Dnomd343 3 years ago
parent
commit
5a72e26a7b
  1. 10
      .env.example
  2. 3
      functions/Curl.php
  3. 72
      functions/DNS.php
  4. 7
      functions/Domain.php
  5. 3
      main.php
  6. 176
      models/ipInfo.php
  7. 6
      models/tgDC.php

10
.env.example

@ -11,16 +11,16 @@ REDIS_PORT=6379
REDIS_PASSWD=
REDIS_PREFIX=tgbot
# ChinaZ API
ICP_KEY=
ICP_API=https://apidatav2.chinaz.com/single/icp
# IP Info
ECHOIP_API=https://api.343.re/ip/
ECHOIP_HOST=ip.343.re
# KMS Check
KMS_API=https://kms.343.re/
# ChinaZ API
ICP_KEY=
ICP_API=https://apidatav2.chinaz.com/single/icp
# CFOP Pic
CFOP_GAN=BQACAgUAAxkBAAIBtGEOLnr4Q6D4Z_80bgfXq5xsZMeWAAKtAwACWy55VOU-SGKqc7aMIAQ
CFOP_MFG=BQACAgUAAxkBAAIB3WEOVHKeYrrGhFo-GffB0W-tQRKlAALQAwACWy55VGny8ArGMkfoIAQ

3
functions/Curl.php

@ -1,11 +1,14 @@
<?php
class Curl {
public $ua = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.131 Safari/537.36 Edg/92.0.902.67';
public function get($url, $timeOut = 30) { // curl模拟Get 默认30s超时
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, $url);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, $timeOut);
curl_setopt($curl, CURLOPT_USERAGENT, $this->ua);
$content = curl_exec($curl);
curl_close($curl);
return $content;

72
functions/DNS.php

@ -0,0 +1,72 @@
<?php
class DNS {
public function resolveA($domain) { // DNS解析A记录
$ipAddr = array();
$rs = dns_get_record(strtolower($domain), DNS_A);
foreach ($rs as $record) {
$ipAddr[] = ip2long($record['ip']);
}
sort($ipAddr); // 解析结果排序
foreach ($ipAddr as &$ip) {
$ip = long2ip($ip);
}
return $ipAddr;
}
public function resolveAAAA($domain) { // DNS解析AAAA记录
$ipAddr = array();
$rs = dns_get_record(strtolower($domain), DNS_AAAA);
foreach ($rs as $record) {
$ipAddr[] = $this->ip2long6($record['ipv6']);
}
sort($ipAddr); // 解析结果排序
foreach ($ipAddr as &$ip) {
$ip = $this->long2ip6($ip);
}
return $ipAddr;
}
public function resolveIP($domain) { // DNS解析IP记录 A/AAAA
$ipAddr = array();
$ipv4 = $this->resolveA($domain);
foreach ($ipv4 as $ip) {
$ipAddr[] = $ip;
}
$ipv6 = $this->resolveAAAA($domain);
foreach ($ipv6 as $ip) {
$ipAddr[] = $ip;
}
return $ipAddr;
}
private function ip2long6($ipv6) { // 压缩IPv6地址为long
$ip_n = inet_pton($ipv6);
$bits = 15;
while ($bits >= 0) {
$bin = sprintf("%08b", (ord($ip_n[$bits])));
$ipv6long = $bin.$ipv6long;
$bits--;
}
return gmp_strval(gmp_init($ipv6long, 2), 10);
}
private function long2ip6($ipv6long) { // 解压long为IPv6地址
$bin = gmp_strval(gmp_init($ipv6long, 10), 2);
if (strlen($bin) < 128) {
$pad = 128 - strlen($bin);
for ($i = 1; $i <= $pad; $i++) {
$bin = '0' . $bin;
}
}
$bits = 0;
while ($bits <= 7) {
$bin_part = substr($bin, ($bits * 16), 16);
$ipv6 .= dechex(bindec($bin_part)) . ':';
$bits++;
}
return inet_ntop(inet_pton(substr($ipv6, 0, -1)));
}
}
?>

7
functions/ExtractDomain.php → functions/Domain.php

@ -1,5 +1,12 @@
<?php
class Domain { // 域名相关功能
public function isDomain($domain) { // 检测是否为域名
preg_match('/^(?=^.{3,255}$)[a-zA-Z0-9][-a-zA-Z0-9]{0,62}(\.[a-zA-Z0-9][-a-zA-Z0-9]{0,62})+$/', $domain, $match);
return (count($match) != 0);
}
}
class extractDomain {
private $tldDB = './db/tldInfo.db'; // 顶级域名数据库

3
main.php

@ -2,12 +2,13 @@
require_once 'env.php';
require_once 'route.php';
require_once 'functions/DNS.php';
require_once 'functions/Curl.php';
require_once 'functions/Domain.php';
require_once 'functions/Punycode.php';
require_once 'functions/SqliteDB.php';
require_once 'functions/RedisCache.php';
require_once 'functions/TgInterface.php';
require_once 'functions/ExtractDomain.php';
fastcgi_finish_request(); // 断开连接
$env = loadEnv('.env'); // 载入环境变量

176
models/ipInfo.php

@ -1,11 +1,10 @@
<?php
class ipInfo {
class ipInfo { // 查询IP详细信息
private $apiPath;
public function __construct() {
global $env;
$this->apiPath = $env['ECHOIP_API'];
$this->apiPath = 'https://' . $GLOBALS['env']['ECHOIP_HOST'] . '/info/';
}
private function changeCoor($num) { // 转为时分秒格式
@ -27,83 +26,32 @@ class ipInfo {
return $str;
}
public function getInfo($ip) {
if (!filter_var($ip, FILTER_VALIDATE_IP)) { // IP地址不合法
return array(
'status' => 'error',
'message' => 'Illegal IP Address'
);
}
$redis = new redisCache('ip');
private function getIpInfo($ip) { // 向上游查询IP信息
$content = (new Curl)->get($this->apiPath . $ip);
$info = json_decode($content, true);
if ($info['status'] !== 'T') { return null; }
unset($info['status']);
return $info + array(
'locCoor' => $this->coorFormat($info['loc']) // 经纬度格式
);
}
public function getInfo($ip) { // 查询IP信息 错误返回null
$redis = new RedisCache('ip');
$info = $redis->getData($ip); // 查询缓存数据
if (!$info) { // 缓存未命中
$info = json_decode(file_get_contents($this->apiPath . $ip), true);
if ($info['status'] !== 'T') { // 上游接口错误
return array(
'status' => 'error',
'message' => 'Server Error'
);
}
unset($info['status']);
if ($info['loc'] != NULL) {
$info['locCoor'] = $this->coorFormat($info['loc']); // 转换为经纬度格式
}
$redis->setData($ip, json_encode($info), 1800); // 缓存30min
$info = $this->getIpInfo($ip);
if ($info === null) { return null; } // 服务错误 返回null
$redis->setData($ip, json_encode($info), 43200); // 缓存12h
} else { // 缓存命中
$info = json_decode($info, true); // 使用缓存数据
}
return array(
'status' => 'ok',
'data' => json_encode($info) // 返回查询结果
);
return $info; // 查询成功 返回结果
}
}
class ipInfoEntry {
private function isDomain($domain) { // 检测是否为域名
preg_match('/^(?=^.{3,255}$)[a-zA-Z0-9][-a-zA-Z0-9]{0,62}(\.[a-zA-Z0-9][-a-zA-Z0-9]{0,62})+$/', $domain, $match);
return (count($match) != 0);
}
private function dnsResolveIPv4($domain) { // DNS解析A记录
$ipAddr = array();
$rs = dns_get_record(strtolower($domain), DNS_A);
foreach ($rs as $record) {
$ipAddr[] = $record['ip'];
}
return $ipAddr;
}
private function dnsResolveIPv6($domain) { // DNS解析AAAA记录
$ipAddr = array();
$rs = dns_get_record(strtolower($domain), DNS_AAAA);
foreach ($rs as $record) {
$ipAddr[] = $record['ipv6'];
}
return $ipAddr;
}
private function dnsResolve($domain) { // DNS解析IP记录
$ipAddr = array();
$ipv4 = $this->dnsResolveIPv4($domain);
foreach ($ipv4 as $ip) {
$ipAddr[] = $ip;
}
$ipv6 = $this->dnsResolveIPv6($domain);
foreach ($ipv6 as $ip) {
$ipAddr[] = $ip;
}
return $ipAddr;
}
private function getInfo($ip) {
$content = (new ipInfo)->getInfo($ip); // 发起查询
if ($content['status'] !== 'ok') {
return array(
'text' => $content['message'] // 返回错误信息
);
}
$info = json_decode($content['data'], true);
class ipInfoEntry { // IP信息查询入口
private function genMessage($info) { // 生成返回信息
$msg = '<b>IP:</b> <code>' . $info['ip'] . '</code>' . PHP_EOL;
if ($info['as'] != NULL) {
$msg .= '<b>AS:</b> <a href="https://bgpview.io/asn/' . substr($info['as'], 2) . '">';
@ -122,43 +70,37 @@ class ipInfoEntry {
if ($info['scope'] != NULL) { $msg .= '<b>Scope:</b> <code>' . $info['scope'] . '</code>' . PHP_EOL; }
if ($info['detail'] != NULL) { $msg .= '<b>Detail:</b> ' . $info['detail'] . PHP_EOL; }
return array(
'text' => $msg,
'parse_mode' => 'HTML', // HTML格式输出
'disable_web_page_preview' => 'true', // 不显示页面预览
'text' => $msg,
'reply_markup' => json_encode(array( // 显示按钮
'inline_keyboard' => array([[
'text' => 'View on echoIP',
'url' => 'https://ip.dnomd343.top/?ip=' . $ip
]])
))
'reply_markup' => $this->genButton('View on echoIP', $info['ip']) // 显示按钮
);
}
public function query($rawParam) { // ipInfo查询入口
if ($rawParam == '' || $rawParam === 'help') { // 显示使用说明
tgApi::sendMessage(array(
'parse_mode' => 'Markdown',
'text' => '*Usage:* `/ip IPv4/IPv6/Domain`',
'reply_markup' => json_encode(array( // 显示echoIP按钮
'inline_keyboard' => array([[
'text' => 'Get my IP address',
'url' => 'https://ip.dnomd343.top/'
]])
))
));
return;
}
if (filter_var($rawParam, FILTER_VALIDATE_IP)) { // 参数为IP地址
tgApi::sendMessage($this->getInfo($rawParam)); // 发起查询
return;
}
if (!$this->isDomain($rawParam)) {
tgApi::sendText('Illegal Request'); // 非法请求
private function genButton($text, $ip = '') { // 生成ehcoIP页面链接按钮 默认为主页
$url = 'https://' . $GLOBALS['env']['ECHOIP_HOST'] . '/';
if ($ip !== '') { $url .= '?ip=' . $ip; }
return json_encode(array(
'inline_keyboard' => array([[ // echoIP按钮
'text' => $text,
'url' => $url
]])
));
}
private function sendInfo($ip) { // 查询并发送IP信息
$info = (new ipInfo)->getInfo($ip);
if ($info === null) {
tgApi::sendText('Server error'); // 上游查询错误
return;
}
$ips = $this->dnsResolve($rawParam);
tgApi::sendMessage($this->genMessage($info));
}
private function sendDomainInfo($domain) { // 查询并发送域名解析结果
$ips = (new DNS)->resolveIP($domain);
if (count($ips) == 0) { // 解析不到IP记录
tgApi::sendMarkdown('Nothing found of `' . $rawParam . '`');
tgApi::sendMarkdown('Nothing found of `' . $domain . '`');
return;
}
foreach ($ips as $ip) {
@ -170,27 +112,47 @@ class ipInfoEntry {
if (count($ips) >= 2) {
$buttons[] = array([ // 两个及以上的IP 添加显示全部的按钮
'text' => 'Get all detail',
'callback_data' => '/ip ' . $rawParam
'callback_data' => '/ip ' . $domain
]);
}
tgApi::sendMessage(array(
'parse_mode' => 'Markdown',
'text' => 'DNS resolve of `' . $rawParam . '`',
'reply_markup' => json_encode(array( // 显示IP列表按钮
'text' => 'DNS resolve of `' . $domain . '`',
'reply_markup' => json_encode(array( // IP列表按钮
'inline_keyboard' => $buttons
))
));
}
private function sendHelp() { // 发送使用说明
$helpMessage = array(
'parse_mode' => 'Markdown',
'text' => '*Usage:* `/ip IPv4/IPv6/Domain`',
'reply_markup' => $this->genButton('Get my IP address') // echoIP主页链接
);
tgApi::sendMessage($helpMessage);
}
public function query($rawParam) { // ipInfo查询入口
if ($rawParam == '' || $rawParam === 'help') {
$this->sendHelp(); // 显示使用说明
} else if (filter_var($rawParam, FILTER_VALIDATE_IP)) { // 参数为IP地址
$this->sendInfo($rawParam); // 查询并发送IP信息
} else if ((new Domain)->isDomain($rawParam)) { // 参数为域名
$this->sendDomainInfo($rawParam); // 查询并发送域名信息
} else {
tgApi::sendText('Illegal Request'); // 非法请求
}
}
public function callback($rawParam) { // ipInfo回调入口
if (filter_var($rawParam, FILTER_VALIDATE_IP)) { // 参数为IP地址
$this->query($rawParam);
} else { // 参数为域名
global $tgEnv;
tgApi::deleteMessage(array(
'message_id' => $tgEnv['messageId']
'message_id' => $GLOBALS['tgEnv']['messageId']
));
$ips = $this->dnsResolve($rawParam);
$ips = (new DNS)->resolveIP($rawParam);
foreach ($ips as $ip) {
$this->query($ip); // 逐个输出
}

6
models/tgDC.php

@ -83,7 +83,7 @@ class tgDCEntry { // DC查询入口
return true;
}
private function showHelp() { // 显示帮助信息
private function sendHelp() { // 显示帮助信息
$message = tgApi::sendMarkdown('*Usage:* `/dc username`');
$message = json_decode($message, true);
return $message['result']['message_id']; // 返回消息ID
@ -133,11 +133,11 @@ class tgDCEntry { // DC查询入口
public function query($rawParam) { // tgDC查询入口
global $tgEnv;
if ($rawParam === 'help') { $this->showHelp(); } // 显示使用说明
if ($rawParam === 'help') { $this->sendHelp(); } // 显示使用说明
if ($rawParam == '') {
$rawParam = $tgEnv['userAccount']; // 空指令时查询对方信息
if (!$tgEnv['isGroup']) {
$messageId = $this->showHelp(); // 非群组发送使用说明
$messageId = $this->sendHelp(); // 非群组发送使用说明
}
}
if (substr($rawParam, 0, 1) === '@') {

Loading…
Cancel
Save