From b8addd6d27d8551106436ad1859ea6bf5a9d55fe Mon Sep 17 00:00:00 2001 From: net909 Date: Sat, 24 Aug 2024 19:42:31 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E7=99=BE=E5=BA=A6=E4=BA=91?= =?UTF-8?q?=E3=80=81=E7=81=AB=E5=B1=B1=E5=BC=95=E6=93=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/controller/Domain.php | 4 + app/lib/DnsHelper.php | 24 ++ app/lib/OptimizeService.php | 2 + app/lib/dns/baidu.php | 4 +- app/lib/dns/dnspod.php | 2 +- app/lib/dns/huoshan.php | 383 +++++++++++++++++++++++++++++++ app/view/domain/account.html | 4 +- app/view/domain/domain.html | 6 +- app/view/domain/record.html | 21 +- app/view/user/user.html | 6 +- config/app.php | 2 +- public/static/images/huoshan.ico | Bin 0 -> 69694 bytes public/static/js/custom.js | 16 +- 13 files changed, 450 insertions(+), 24 deletions(-) create mode 100644 app/lib/dns/huoshan.php create mode 100644 public/static/images/huoshan.ico diff --git a/app/controller/Domain.php b/app/controller/Domain.php index 39f23d1..bbd01bf 100644 --- a/app/controller/Domain.php +++ b/app/controller/Domain.php @@ -362,6 +362,10 @@ class Domain extends BaseController $row['LineName'] = isset($recordLine[$row['Line']]) ? $recordLine[$row['Line']]['name'] : $row['Line']; } + if($dns->type == 'baidu'){ + return json($domainRecords['list']); + } + return json(['total'=>$domainRecords['total'], 'rows'=>$domainRecords['list']]); } diff --git a/app/lib/DnsHelper.php b/app/lib/DnsHelper.php index 7c3b673..fa01136 100644 --- a/app/lib/DnsHelper.php +++ b/app/lib/DnsHelper.php @@ -39,6 +39,17 @@ class DnsHelper 'redirect' => false, 'log' => false, ], + 'baidu' => [ + 'name' => '百度云', + 'config' => [ + 'ak' => 'AccessKey', + 'sk' => 'SecretKey' + ], + 'remark' => 2, + 'status' => false, + 'redirect' => false, + 'log' => false, + ], 'west' => [ 'name' => '西部数码', 'config' => [ @@ -50,6 +61,17 @@ class DnsHelper 'redirect' => false, 'log' => false, ], + 'huoshan' => [ + 'name' => '火山引擎', + 'config' => [ + 'ak' => 'AccessKeyId', + 'sk' => 'SecretAccessKey' + ], + 'remark' => 2, + 'status' => true, + 'redirect' => false, + 'log' => false, + ], 'dnsla' => [ 'name' => 'DNSLA', 'config' => [ @@ -95,6 +117,7 @@ class DnsHelper $config['domain'] = $domain; $config['domainid'] = $domainid; $model = new $class($config); + $model->type = $dnstype; return $model; } return false; @@ -108,6 +131,7 @@ class DnsHelper $config['domain'] = $config['name']; $config['domainid'] = $config['thirdid']; $model = new $class($config); + $model->type = $dnstype; return $model; } return false; diff --git a/app/lib/OptimizeService.php b/app/lib/OptimizeService.php index 10c4aeb..72d5d03 100644 --- a/app/lib/OptimizeService.php +++ b/app/lib/OptimizeService.php @@ -13,6 +13,8 @@ class OptimizeService 'huawei' => ['DEF'=>'default_view', 'CT'=>'Dianxin', 'CU'=>'Liantong', 'CM'=>'Yidong', 'AB'=>'Abroad'], 'west' => ['DEF'=>'', 'CT'=>'LTEL', 'CU'=>'LCNC', 'CM'=>'LMOB', 'AB'=>'LFOR'], 'dnsla' => ['DEF'=>'', 'CT'=>'84613316902921216', 'CU'=>'84613316923892736', 'CM'=>'84613316953252864', 'AB'=>''], + 'huoshan' => ['DEF'=>'default', 'CT'=>'telecom', 'CU'=>'unicom', 'CM'=>'mobile', 'AB'=>'oversea'], + 'baidu' => ['DEF'=>'default', 'CT'=>'ct', 'CU'=>'cnc', 'CM'=>'cmnet', 'AB'=>''], ]; private $ip_address = []; diff --git a/app/lib/dns/baidu.php b/app/lib/dns/baidu.php index dc2ca1a..4c1b3a8 100644 --- a/app/lib/dns/baidu.php +++ b/app/lib/dns/baidu.php @@ -50,8 +50,8 @@ class baidu implements DnsInterface { //获取解析记录列表 public function getDomainRecords($PageNumber=1, $PageSize=20, $KeyWord = null, $SubDomain = null, $Value = null, $Type = null, $Line = null, $Status = null){ $query = ['rr' => $KeyWord]; - if(!isNullOrEmpty(($SubDomain))){ - $param['rr'] = $SubDomain; + if(!isNullOrEmpty($SubDomain)){ + $query['rr'] = $SubDomain; } $data = $this->send_reuqest('GET', '/v1/dns/zone/'.$this->domain.'/record', $query); if($data){ diff --git a/app/lib/dns/dnspod.php b/app/lib/dns/dnspod.php index 670826e..fad8228 100644 --- a/app/lib/dns/dnspod.php +++ b/app/lib/dns/dnspod.php @@ -91,7 +91,7 @@ class dnspod implements DnsInterface { ]; } return ['total' => $data['RecordCountInfo']['TotalCount'], 'list' => $list]; - }elseif($this->error == '记录列表为空。'){ + }elseif($this->error == '记录列表为空。' || $this->error == 'No records on the list.'){ return ['total' => 0, 'list' => []]; } return false; diff --git a/app/lib/dns/huoshan.php b/app/lib/dns/huoshan.php new file mode 100644 index 0000000..5288a5b --- /dev/null +++ b/app/lib/dns/huoshan.php @@ -0,0 +1,383 @@ + ['level' => 1, 'name' => '免费版', 'ttl' => 600], + 'professional_inner' => ['level' => 2, 'name' => '专业版', 'ttl' => 300], + 'enterprise_inner' => ['level' => 3, 'name' => '企业版', 'ttl' => 60], + 'ultimate_inner' => ['level' => 4, 'name' => '旗舰版', 'ttl' => 1], + 'ultimate_exclusive_inner' => ['level' => 5, 'name' => '尊享版', 'ttl' => 1], + ]; + + function __construct($config){ + $this->AccessKeyId = $config['ak']; + $this->SecretAccessKey = $config['sk']; + $this->domain = $config['domain']; + $this->domainid = $config['domainid']; + } + + public function getError(){ + return $this->error; + } + + public function check(){ + if($this->getDomainList() != false){ + return true; + } + return false; + } + + //获取域名列表 + public function getDomainList($KeyWord=null, $PageNumber=1, $PageSize=20){ + $query = ['PageNumber' => $PageNumber, 'PageSize' => $PageSize, 'Key' => $KeyWord]; + $data = $this->send_reuqest('GET', 'ListZones', $query); + if($data){ + $list = []; + if(!empty($data['Zones'])){ + foreach($data['Zones'] as $row){ + $list[] = [ + 'DomainId' => $row['ZID'], + 'Domain' => $row['ZoneName'], + 'RecordCount' => $row['RecordCount'], + ]; + } + } + return ['total' => $data['Total'], 'list' => $list]; + } + return false; + } + + //获取解析记录列表 + public function getDomainRecords($PageNumber=1, $PageSize=20, $KeyWord = null, $SubDomain = null, $Value = null, $Type = null, $Line = null, $Status = null){ + $query = ['ZID' => intval($this->domainid), 'PageNumber' => $PageNumber, 'PageSize' => $PageSize, 'SearchOrder' => 'desc']; + if(!empty($SubDomain) || !empty($Type) || !empty($Line) || !empty($Value)){ + $query += ['Host' => $SubDomain, 'Value' => $Value, 'Type' => $Type, 'Line' => $Line]; + }elseif(!empty($KeyWord)){ + $query += ['Host' => $KeyWord]; + } + $data = $this->send_reuqest('GET', 'ListRecords', $query); + if($data){ + $list = []; + foreach($data['Records'] as $row){ + $list[] = [ + 'RecordId' => $row['RecordID'], + 'Domain' => $this->domain, + 'Name' => $row['Host'], + 'Type' => $row['Type'], + 'Value' => $row['Value'], + 'Line' => $row['Line'], + 'TTL' => $row['TTL'], + 'MX' => $row['Weight'], + 'Status' => $row['Enable'] ? '1' : '0', + 'Weight' => $row['Weight'], + 'Remark' => $row['Remark'], + 'UpdateTime' => $row['UpdatedAt'], + ]; + } + return ['total' => $data['TotalCount'], 'list' => $list]; + } + return false; + } + + //获取子域名解析记录列表 + public function getSubDomainRecords($SubDomain, $PageNumber=1, $PageSize=20, $Type = null, $Line = null){ + return $this->getDomainRecords($PageNumber, $PageSize, null, $SubDomain, null, $Type, $Line); + } + + //获取解析记录详细信息 + public function getDomainRecordInfo($RecordId){ + $data = $this->send_reuqest('GET', 'QueryRecord', ['RecordID' => $RecordId]); + if($data){ + if($data['name'] == $data['zone_name']) $data['name'] = '@'; + return [ + 'RecordId' => $data['RecordID'], + 'Domain' => $this->domain, + 'Name' => $data['Host'], + 'Type' => $data['Type'], + 'Value' => $data['Value'], + 'Line' => $data['Line'], + 'TTL' => $data['TTL'], + 'MX' => $data['Weight'], + 'Status' => $data['Enable'] ? '1' : '0', + 'Weight' => $data['Weight'], + 'Remark' => $data['Remark'], + 'UpdateTime' => $data['UpdatedAt'], + ]; + } + return false; + } + + //添加解析记录 + public function addDomainRecord($Name, $Type, $Value, $Line = '0', $TTL = 600, $MX = 1, $Remark = null){ + $params = ['ZID' => intval($this->domainid), 'Host' => $Name, 'Type' => $this->convertType($Type), 'Value' => $Value, 'Line'=>$Line, 'TTL' => intval($TTL), 'Remark' => $Remark]; + if($Type == 'MX')$param['Weight'] = intval($MX); + $data = $this->send_reuqest('POST', 'CreateRecord', $params); + return is_array($data) ? $data['RecordID'] : false; + } + + //修改解析记录 + public function updateDomainRecord($RecordId, $Name, $Type, $Value, $Line = '0', $TTL = 600, $MX = 1, $Remark = null){ + $params = ['RecordID' => $RecordId, 'Host' => $Name, 'Type' => $this->convertType($Type), 'Value' => $Value, 'Line'=>$Line, 'TTL' => intval($TTL), 'Remark' => $Remark]; + if($Type == 'MX')$param['Weight'] = intval($MX); + $data = $this->send_reuqest('POST', 'UpdateRecord', $params); + return is_array($data); + } + + //修改解析记录备注 + public function updateDomainRecordRemark($RecordId, $Remark){ + return false; + } + + //删除解析记录 + public function deleteDomainRecord($RecordId){ + $data = $this->send_reuqest('POST', 'DeleteRecord', ['RecordID' => $RecordId]); + return $data; + } + + //设置解析记录状态 + public function setDomainRecordStatus($RecordId, $Status){ + $params = ['RecordID' => $RecordId, 'Enable' => $Status == '1']; + $data = $this->send_reuqest('POST', 'UpdateRecordStatus', $params); + return is_array($data); + } + + //获取解析记录操作日志 + public function getDomainRecordLog($PageNumber = 1, $PageSize = 20, $KeyWord = null, $StartDate = null, $endDate = null){ + return false; + } + + //获取解析线路列表 + public function getRecordLine(){ + $domainInfo = $this->getDomainInfo(); + if(!$domainInfo) return false; + $level = $this->getTradeInfo($domainInfo['TradeCode'])['level']; + $data = $this->send_reuqest('GET', 'ListLines', []); + if($data){ + $list = []; + $list['default'] = ['name' => '默认', 'parent' => null]; + foreach($data['Lines'] as $row){ + if($row['Value'] == 'default') continue; + if($row['Level'] > $level) continue; + $list[$row['Value']] = ['name' => $row['Name'], 'parent' => isset($row['FatherValue']) ? $row['FatherValue'] : null]; + } + + $data = $this->send_reuqest('GET', 'ListCustomLines', []); + if($data && $data['TotalCount'] > 0){ + $list['N.customer_lines'] = ['name' => '自定义线路', 'parent' => null]; + foreach($data['CustomerLines'] as $row){ + $list[$row['Line']] = ['name' => $row['NameCN'], 'parent' => 'N.customer_lines']; + } + } + + return $list; + } + return false; + } + + //获取域名概览信息 + public function getDomainInfo(){ + if(!empty($this->domainInfo)) return $this->domainInfo; + $query = ['ZID' => intval($this->domainid)]; + $data = $this->send_reuqest('GET', 'QueryZone', $query); + if($data){ + $this->domainInfo = $data; + return $data; + } + return false; + } + + //获取域名最低TTL + public function getMinTTL(){ + $domainInfo = $this->getDomainInfo(); + if($domainInfo){ + $ttl = $this->getTradeInfo($domainInfo['TradeCode'])['ttl']; + return $ttl; + } + return false; + } + + private function convertType($type){ + return $type; + } + + private function getTradeInfo($trade_code){ + if(array_key_exists($trade_code, self::$trade_code_list)){ + $trade_code = $trade_code; + }else{ + $trade_code = 'free_inner'; + } + return self::$trade_code_list[$trade_code]; + } + + private function send_reuqest($method, $action, $params = []){ + if(!empty($params)){ + $params = array_filter($params, function($a){ return $a!==null;}); + } + + $query = [ + 'Action' => $action, + 'Version' => $this->version, + ]; + + $body = ''; + if($method == 'GET'){ + $query = array_merge($query, $params); + }else{ + $body = !empty($params) ? json_encode($params) : ''; + } + + $time = time(); + $headers = [ + 'Host' => $this->endpoint, + 'X-Date' => gmdate("Ymd\THis\Z", $time), + //'X-Content-Sha256' => hash("sha256", $body), + ]; + if($body){ + $headers['Content-Type'] = 'application/json'; + } + $path = '/'; + + $authorization = $this->generateSign($method, $path, $query, $headers, $body, $time); + $headers['Authorization'] = $authorization; + + $url = 'https://'.$this->endpoint.$path.'?'.http_build_query($query); + $header = []; + foreach($headers as $key => $value){ + $header[] = $key.': '.$value; + } + return $this->curl($method, $url, $body, $header); + } + + private function generateSign($method, $path, $query, $headers, $body, $time){ + $algorithm = "HMAC-SHA256"; + + // step 1: build canonical request string + $httpRequestMethod = $method; + $canonicalUri = $path; + if(substr($canonicalUri, -1) != "/") $canonicalUri .= "/"; + $canonicalQueryString = $this->getCanonicalQueryString($query); + [$canonicalHeaders, $signedHeaders] = $this->getCanonicalHeaders($headers); + $hashedRequestPayload = hash("sha256", $body); + $canonicalRequest = $httpRequestMethod."\n" + .$canonicalUri."\n" + .$canonicalQueryString."\n" + .$canonicalHeaders."\n" + .$signedHeaders."\n" + .$hashedRequestPayload; + + // step 2: build string to sign + $date = gmdate("Ymd\THis\Z", $time); + $shortDate = substr($date, 0, 8); + $credentialScope = $shortDate . '/' .$this->region . '/' . $this->service . '/request'; + $hashedCanonicalRequest = hash("sha256", $canonicalRequest); + $stringToSign = $algorithm."\n" + .$date."\n" + .$credentialScope."\n" + .$hashedCanonicalRequest; + + // step 3: sign string + $kDate = hash_hmac("sha256", $shortDate, $this->SecretAccessKey, true); + $kRegion = hash_hmac("sha256", $this->region, $kDate, true); + $kService = hash_hmac("sha256", $this->service, $kRegion, true); + $kSigning = hash_hmac("sha256", "request", $kService, true); + $signature = hash_hmac("sha256", $stringToSign, $kSigning); + + // step 4: build authorization + $credential = $this->AccessKeyId . '/' . $shortDate . '/' . $this->region . '/' . $this->service . '/request'; + $authorization = $algorithm . ' Credential=' . $credential . ", SignedHeaders=" . $signedHeaders . ", Signature=" . $signature; + + return $authorization; + } + + private function escape($str) + { + $search = ['+', '*', '%7E']; + $replace = ['%20', '%2A', '~']; + return str_replace($search, $replace, urlencode($str)); + } + + private function getCanonicalQueryString($parameters) + { + if(empty($parameters)) return ''; + ksort($parameters); + $canonicalQueryString = ''; + foreach ($parameters as $key => $value) { + $canonicalQueryString .= '&' . $this->escape($key). '=' . $this->escape($value); + } + return substr($canonicalQueryString, 1); + } + + private function getCanonicalHeaders($oldheaders){ + $headers = array(); + foreach ($oldheaders as $key => $value) { + $headers[strtolower($key)] = trim($value); + } + ksort($headers); + + $canonicalHeaders = ''; + $signedHeaders = ''; + foreach ($headers as $key => $value) { + $canonicalHeaders .= $key . ':' . $value . "\n"; + $signedHeaders .= $key . ';'; + } + $signedHeaders = substr($signedHeaders, 0, -1); + return [$canonicalHeaders, $signedHeaders]; + } + + private function curl($method, $url, $body, $header){ + $ch = curl_init($url); + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); + curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); + curl_setopt($ch, CURLOPT_HTTPHEADER, $header); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + curl_setopt($ch, CURLOPT_TIMEOUT, 10); + curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method); + if(!empty($body)){ + curl_setopt($ch, CURLOPT_POSTFIELDS, $body); + } + $response = curl_exec($ch); + $errno = curl_errno($ch); + if ($errno) { + $this->setError('Curl error: ' . curl_error($ch)); + } + curl_close($ch); + if ($errno) return false; + + $arr=json_decode($response,true); + if($arr){ + if(isset($arr['ResponseMetadata']['Error']['MessageCN'])){ + $this->setError($arr['ResponseMetadata']['Error']['MessageCN']); + return false; + }elseif(isset($arr['ResponseMetadata']['Error']['Message'])){ + $this->setError($arr['ResponseMetadata']['Error']['Message']); + return false; + }elseif(isset($arr['Result'])){ + return $arr['Result']; + }else{ + return true; + } + }else{ + $this->setError('返回数据解析失败'); + return false; + } + } + + private function setError($message){ + $this->error = $message; + //file_put_contents('logs.txt',date('H:i:s').' '.$message."\r\n", FILE_APPEND); + } +} \ No newline at end of file diff --git a/app/view/domain/account.html b/app/view/domain/account.html index 4d323bb..3e8675b 100644 --- a/app/view/domain/account.html +++ b/app/view/domain/account.html @@ -198,7 +198,7 @@ function save(){ }, function(){ layer.closeAll(); $("#modal-store").modal('hide'); - searchSubmit(); + searchRefresh(); }); }else{ layer.alert(data.msg, {icon: 2}) @@ -220,7 +220,7 @@ function delItem(id) { layer.close(ii); if(data.code == 0){ layer.closeAll(); - searchSubmit(); + searchRefresh(); }else{ layer.alert(data.msg, {icon: 2}); } diff --git a/app/view/domain/domain.html b/app/view/domain/domain.html index 927523e..60d1811 100644 --- a/app/view/domain/domain.html +++ b/app/view/domain/domain.html @@ -244,7 +244,7 @@ function saveAdd(){ }, function(){ layer.closeAll(); $("#modal-store").modal('hide'); - searchSubmit(); + searchRefresh(); }); }else{ layer.alert(data.msg, {icon: 2}) @@ -289,7 +289,7 @@ function saveEdit(){ }, function(){ layer.closeAll(); $("#modal-store2").modal('hide'); - searchSubmit(); + searchRefresh(); }); }else{ layer.alert(data.msg, {icon: 2}) @@ -311,7 +311,7 @@ function delItem(id) { layer.close(ii); if(data.code == 0){ layer.closeAll(); - searchSubmit(); + searchRefresh(); }else{ layer.alert(data.msg, {icon: 2}); } diff --git a/app/view/domain/record.html b/app/view/domain/record.html index 5645f5a..03735a8 100644 --- a/app/view/domain/record.html +++ b/app/view/domain/record.html @@ -225,11 +225,12 @@ td{overflow: hidden;text-overflow: ellipsis;white-space: nowrap;max-width:360px; - +