Files
dnsmgr/app/service/OptimizeService.php
2025-10-16 23:09:13 +08:00

251 lines
9.4 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
namespace app\service;
use Exception;
use think\facade\Db;
use app\lib\DnsHelper;
/**
* CF优选IP
*/
class OptimizeService
{
private $ip_address = [];
private $add_num = 0;
private $change_num = 0;
private $del_num = 0;
public static function get_license($api, $key)
{
if ($api == 2) {
throw new Exception('当前接口暂不支持');
} elseif ($api == 1) {
$url = 'https://api.hostmonit.com/get_license?license='.$key;
} else {
$url = 'https://www.wetest.vip/api/cf2dns/get_license?license='.$key;
}
$response = get_curl($url);
$arr = json_decode($response, true);
if (isset($arr['code']) && $arr['code'] == 200 && isset($arr['count'])) {
return $arr['count'];
} elseif (isset($arr['info'])) {
throw new Exception('获取剩余请求次数失败,'.$arr['info']);
} else {
throw new Exception('获取剩余请求次数失败');
}
}
public function get_ip_address($cdn_type = 1, $ip_type = 'v4')
{
$api = config_get('optimize_ip_api', 0);
if ($api == 1) {
$url = 'https://api.hostmonit.com/get_optimization_ip';
} else {
$url = 'https://www.wetest.vip/api/cf2dns/';
if ($cdn_type == 1) {
$url .= 'get_cloudflare_ip';
} elseif ($cdn_type == 2) {
$url .= 'get_cloudfront_ip';
} elseif ($cdn_type == 3) {
$url .= 'get_gcore_ip';
} elseif ($cdn_type == 4) {
$url .= 'get_edgeone_ip';
}
}
$params = [
'key' => config_get('optimize_ip_key', 'o1zrmHAF'),
'type' => $ip_type,
];
$response = get_curl($url, json_encode($params), 0, 0, 0, 0, ['Content-Type' => 'application/json; charset=UTF-8']);
$arr = json_decode($response, true);
if (isset($arr['code']) && $arr['code'] == 200) {
return $arr['info'];
} elseif (isset($arr['info'])) {
throw new Exception('获取优选IP数据失败'.$arr['info']);
} elseif (isset($arr['msg'])) {
throw new Exception('获取优选IP数据失败'.$arr['msg']);
} else {
throw new Exception('获取优选IP数据失败原因未知');
}
}
public function get_ip_address2($cdn_type = 1, $ip_type = 'v4')
{
$key = $cdn_type.'_'.$ip_type;
if (!isset($this->ip_address[$key])) {
$info = $this->get_ip_address($cdn_type, $ip_type);
$res = [];
if (isset($info['DEF'])) {
$res['DEF'] = $info['DEF'];
}
if (isset($info['CT'])) {
$res['CT'] = $info['CT'];
}
if (isset($info['CU'])) {
$res['CU'] = $info['CU'];
}
if (isset($info['CM'])) {
$res['CM'] = $info['CM'];
}
$this->ip_address[$key] = $res;
}
return $this->ip_address[$key];
}
//批量执行优选任务
public function execute()
{
$minute = config_get('optimize_ip_min', '30');
$last = config_get('optimize_ip_time', null, true);
if ($last && strtotime($last) > time() - $minute * 60) {
return false;
}
$list = Db::name('optimizeip')->where('active', 1)->select();
if (count($list) == 0) {
return false;
}
echo '开始执行IP优选任务共获取到'.count($list).'个待执行任务'."\n";
foreach ($list as $row) {
try {
$result = $this->execute_one($row);
Db::name('optimizeip')->where('id', $row['id'])->update(['status' => 1, 'errmsg' => null, 'updatetime' => date('Y-m-d H:i:s')]);
echo '优选任务'.$row['id'].'执行成功:'.$result."\n";
} catch (Exception $e) {
Db::name('optimizeip')->where('id', $row['id'])->update(['status' => 2, 'errmsg' => $e->getMessage(), 'updatetime' => date('Y-m-d H:i:s')]);
echo '优选任务'.$row['id'].'执行失败:'.$e->getMessage()."\n";
}
}
config_set('optimize_ip_time', date("Y-m-d H:i:s"));
return true;
}
//执行单个优选任务
public function execute_one($row)
{
$this->add_num = 0;
$this->change_num = 0;
$this->del_num = 0;
$ip_types = explode(',', $row['ip_type']);
foreach ($ip_types as $ip_type) {
if (empty($ip_type)) {
continue;
}
$drow = Db::name('domain')->alias('A')->join('account B', 'A.aid = B.id')->where('A.id', $row['did'])->field('A.*,B.type,B.ak,B.sk,B.ext')->find();
if (!$drow) {
throw new Exception('域名不存在ID'.$row['did'].'');
}
if (!isset(DnsHelper::$line_name[$drow['type']])) {
throw new Exception('不支持的DNS服务商');
}
$info = $this->get_ip_address2($row['cdn_type'], $ip_type);
$dns = DnsHelper::getModel($drow['aid'], $drow['name'], $drow['thirdid']);
$domainRecords = $dns->getSubDomainRecords($row['rr'], 1, 100);
if (!$domainRecords) {
throw new Exception('获取记录列表失败,'.$dns->getError());
}
if ($row['type'] == 1 && isset($info['DEF']) && !empty($info['DEF'])) {
$row['type'] = 0;
}
foreach ($info as $line => $iplist) {
if (empty($iplist)) {
continue;
}
$record_num = $row['recordnum'];
$get_ips = array_column($iplist, 'ip');
if ($drow['type'] == 'huawei') {
sort($get_ips);
$get_ips = array_slice($get_ips, 0, $row['recordnum']);
$get_ips = [implode(',', $get_ips)];
$record_num = 1;
}
if ($row['type'] == 1 && $line == 'CT') {
$line = 'DEF';
}
if (!isset(DnsHelper::$line_name[$drow['type']][$line])) {
continue;
}
$line_name = DnsHelper::$line_name[$drow['type']][$line];
$this->process_dns_line($dns, $row, $domainRecords['list'], $record_num, $get_ips, $line_name, $ip_type);
}
}
return '成功添加'.$this->add_num.'条记录,修改'.$this->change_num.'条记录,删除'.$this->del_num.'条记录';
}
//处理单个线路的解析记录
private function process_dns_line($dns, $row, $record_list, $record_num, $get_ips, $line_name, $ip_type)
{
$records = array_filter($record_list, function ($v) use ($line_name) {
return $v['Line'] == $line_name;
});
//删除CNAME记录
$cname_records = array_filter($records, function ($v) {
return $v['Type'] == 'CNAME';
});
if (!empty($cname_records)) {
foreach ($cname_records as $record) {
$dns->deleteDomainRecord($record['RecordId']);
}
}
//处理A/AAAA记录
$ip_records = array_filter($records, function ($v) use ($ip_type) {
return $v['Type'] == ($ip_type == 'v6' ? 'AAAA' : 'A');
});
if (!empty($ip_records) && is_array($ip_records[array_key_first($ip_records)]['Value'])) { //处理华为云记录
foreach ($ip_records as &$ip_record) {
sort($ip_record['Value']);
$ip_record['Value'] = implode(',', $ip_record['Value']);
}
}
$exist_ips = array_column($ip_records, 'Value');
$add_ips = array_diff($get_ips, $exist_ips);
$del_ips = array_diff($exist_ips, $get_ips);
$correct_ips = array_diff($exist_ips, $del_ips);
$correct_count = count($correct_ips);
if (!empty($del_ips)) {
foreach ($ip_records as $record) {
if (in_array($record['Value'], $del_ips)) {
$add_ip = array_pop($add_ips);
if ($add_ip) {
$res = $dns->updateDomainRecord($record['RecordId'], $row['rr'], $ip_type == 'v6' ? 'AAAA' : 'A', $add_ip, $line_name, $row['ttl']);
if (!$res) {
throw new Exception('修改解析失败,'.$dns->getError());
}
$this->change_num++;
$correct_count++;
} else {
$res = $dns->deleteDomainRecord($record['RecordId']);
if (!$res) {
throw new Exception('删除解析失败,'.$dns->getError());
}
$this->del_num++;
}
}
}
}
if ($correct_count < $record_num && !empty($add_ips)) {
foreach ($add_ips as $add_ip) {
$res = $dns->addDomainRecord($row['rr'], $ip_type == 'v6' ? 'AAAA' : 'A', $add_ip, $line_name, $row['ttl']);
if (!$res) {
throw new Exception('添加解析失败,'.$dns->getError());
}
$this->add_num++;
$correct_count++;
if ($correct_count >= $record_num) {
break;
}
}
}
}
}