diff --git a/app/common.php b/app/common.php
index 8d87b95..f654125 100644
--- a/app/common.php
+++ b/app/common.php
@@ -482,4 +482,23 @@ function convertDomainToUtf8($domain) {
} else {
return $domain;
}
-}
\ No newline at end of file
+}
+
+function getDomainDate($domain)
+{
+ try {
+ $whois = \Iodev\Whois\Factory::get()->createWhois();
+ $info = $whois->loadDomainInfo($domain);
+ if ($info) {
+ if ($info->expirationDate > 0) {
+ return [date('Y-m-d H:i:s', $info->creationDate), date('Y-m-d H:i:s', $info->expirationDate)];
+ } else {
+ throw new Exception('域名到期时间未知');
+ }
+ } else {
+ throw new Exception('域名信息未找到');
+ }
+ } catch (Exception $e) {
+ throw new Exception('查询域名whois失败: ' . $e->getMessage());
+ }
+}
diff --git a/app/controller/Domain.php b/app/controller/Domain.php
index 6eab4d5..a78a4cc 100644
--- a/app/controller/Domain.php
+++ b/app/controller/Domain.php
@@ -5,8 +5,9 @@ namespace app\controller;
use app\BaseController;
use think\facade\Db;
use think\facade\View;
-use think\facade\Request;
+use think\facade\Cache;
use app\lib\DnsHelper;
+use app\service\ExpireNoticeService;
use Exception;
class Domain extends BaseController
@@ -179,6 +180,7 @@ class Domain extends BaseController
if (!checkPermission(1)) return json(['total' => 0, 'rows' => []]);
$kw = input('post.kw', null, 'trim');
$type = input('post.type', null, 'trim');
+ $status = input('post.status', null, 'trim');
$offset = input('post.offset/d', 0);
$limit = input('post.limit/d', 10);
@@ -192,6 +194,13 @@ class Domain extends BaseController
if (request()->user['level'] == 1) {
$select->where('is_hide', 0)->where('A.name', 'in', request()->user['permission']);
}
+ if (!isNullOrEmpty($status)) {
+ if ($status == '2') {
+ $select->where('A.expiretime', '<=', date('Y-m-d H:i:s'));
+ } elseif ($status == '1') {
+ $select->where('A.expiretime', '<=', date('Y-m-d H:i:s', time() + 86400 * 30))->where('A.expiretime', '>', date('Y-m-d H:i:s'));
+ }
+ }
$total = $select->count();
$rows = $select->fieldRaw('A.*,B.type,B.remark aremark')->order('A.id', 'desc')->limit($offset, $limit)->select();
@@ -240,11 +249,13 @@ class Domain extends BaseController
if (!$row) return json(['code' => -1, 'msg' => '域名不存在']);
$is_hide = input('post.is_hide/d');
$is_sso = input('post.is_sso/d');
+ $is_notice = input('post.is_notice/d');
$remark = input('post.remark', null, 'trim');
if (empty($remark)) $remark = null;
Db::name('domain')->where('id', $id)->update([
'is_hide' => $is_hide,
'is_sso' => $is_sso,
+ 'is_notice' => $is_notice,
'remark' => $remark,
]);
return json(['code' => 0, 'msg' => '修改域名配置成功!']);
@@ -280,8 +291,15 @@ class Domain extends BaseController
if (empty($ids)) return json(['code' => -1, 'msg' => '参数不能为空']);
$remark = input('post.remark', null, 'trim');
if (empty($remark)) $remark = null;
- Db::name('domain')->where('id', 'in', $ids)->update(['remark' => $remark]);
- return json(['code' => 0, 'msg' => '成功修改' . count($ids) . '个域名!']);
+ $count = Db::name('domain')->where('id', 'in', $ids)->update(['remark' => $remark]);
+ return json(['code' => 0, 'msg' => '成功修改' . $count . '个域名!']);
+ } elseif ($act == 'batchsetnotice') {
+ if (!checkPermission(2)) return $this->alert('error', '无权限');
+ $ids = input('post.ids');
+ $is_notice = input('post.is_notice/d', 0);
+ if (empty($ids)) return json(['code' => -1, 'msg' => '参数不能为空']);
+ $count = Db::name('domain')->where('id', 'in', $ids)->update(['is_notice' => $is_notice]);
+ return json(['code' => 0, 'msg' => '成功修改' . $count . '个域名!']);
} elseif ($act == 'batchdel') {
if (!checkPermission(2)) return $this->alert('error', '无权限');
$ids = input('post.ids');
@@ -1029,4 +1047,33 @@ class Domain extends BaseController
$domainRecords = $dns->getWeightSubDomains($page, $limit, $keyword);
return json(['total' => $domainRecords['total'], 'rows' => $domainRecords['list']]);
}
+
+ public function expire_notice()
+ {
+ if (!checkPermission(2)) return $this->alert('error', '无权限');
+ if ($this->request->isPost()) {
+ $params = input('post.');
+ foreach ($params as $key => $value) {
+ if (empty($key)) {
+ continue;
+ }
+ config_set($key, $value);
+ Cache::delete('configs');
+ }
+ return json(['code' => 0, 'msg' => 'succ']);
+ }
+ return View::fetch();
+ }
+
+ public function update_date()
+ {
+ $id = input('param.id/d');
+ $drow = Db::name('domain')->where('id', $id)->find();
+ if (!$drow) {
+ return json(['code' => -1, 'msg' => '域名不存在']);
+ }
+ if (!checkPermission(0, $drow['name'])) return json(['code' => -1, 'msg' => '无权限']);
+ $result = (new ExpireNoticeService())->updateDomainDate($id, $drow['name']);
+ return json($result);
+ }
}
diff --git a/app/lib/DeployHelper.php b/app/lib/DeployHelper.php
index f07057a..4a09afc 100644
--- a/app/lib/DeployHelper.php
+++ b/app/lib/DeployHelper.php
@@ -890,7 +890,7 @@ class DeployHelper
'domain' => [
'name' => '绑定的域名',
'type' => 'input',
- 'placeholder' => '',
+ 'placeholder' => '多个域名可使用,分隔',
'show' => 'product==\'cdn\'',
'required' => true,
],
@@ -1142,6 +1142,7 @@ class DeployHelper
['value'=>'cdn', 'label'=>'内容分发网络CDN'],
['value'=>'dcdn', 'label'=>'全站加速DCDN'],
['value'=>'clb', 'label'=>'负载均衡CLB'],
+ ['value'=>'alb', 'label'=>'应用型负载均衡ALB'],
['value'=>'tos', 'label'=>'对象存储TOS'],
['value'=>'live', 'label'=>'视频直播'],
['value'=>'imagex', 'label'=>'veImageX'],
@@ -1160,14 +1161,14 @@ class DeployHelper
'name' => '绑定的域名',
'type' => 'input',
'placeholder' => '多个域名可使用,分隔',
- 'show' => 'product!=\'clb\'',
+ 'show' => 'product!=\'clb\'&&product!=\'alb\'',
'required' => true,
],
'listener_id' => [
'name' => '监听器ID',
'type' => 'input',
'placeholder' => '',
- 'show' => 'product==\'clb\'',
+ 'show' => 'product==\'clb\'||product==\'alb\'',
'required' => true,
],
],
diff --git a/app/lib/deploy/huawei.php b/app/lib/deploy/huawei.php
index 0006248..b562177 100644
--- a/app/lib/deploy/huawei.php
+++ b/app/lib/deploy/huawei.php
@@ -58,8 +58,10 @@ class huawei implements DeployInterface
],
],
];
- $client->request('PUT', '/v1.1/cdn/configuration/domains/' . $config['domain'] . '/configs', null, $param);
- $this->log('CDN域名 ' . $config['domain'] . ' 部署证书成功!');
+ foreach (explode(',', $config['domain']) as $domain) {
+ $client->request('PUT', '/v1.1/cdn/configuration/domains/' . $domain . '/configs', null, $param);
+ $this->log('CDN域名 ' . $domain . ' 部署证书成功!');
+ }
}
private function deploy_elb($fullchain, $privatekey, $config)
diff --git a/app/lib/deploy/huoshan.php b/app/lib/deploy/huoshan.php
index 5fba09b..107e64a 100644
--- a/app/lib/deploy/huoshan.php
+++ b/app/lib/deploy/huoshan.php
@@ -46,6 +46,8 @@ class huoshan implements DeployInterface
$this->deploy_imagex($cert_id, $config);
} elseif ($config['product'] == 'clb') {
$this->deploy_clb($cert_id, $config);
+ } elseif ($config['product'] == 'alb') {
+ $this->deploy_alb($cert_id, $config);
}
}
}
@@ -167,6 +169,19 @@ class huoshan implements DeployInterface
$this->log('CLB监听器 ' . $config['listener_id'] . ' 部署证书成功!');
}
+ private function deploy_alb($cert_id, $config)
+ {
+ if (empty($config['listener_id'])) throw new Exception('监听器ID不能为空');
+ $client = new Volcengine($this->AccessKeyId, $this->SecretAccessKey, 'open.volcengineapi.com', 'alb', '2020-04-01', 'cn-beijing', $this->proxy);
+ $param = [
+ 'ListenerId' => $config['listener_id'],
+ 'CertificateSource' => 'cert_center',
+ 'CertCenterCertificateId' => $cert_id,
+ ];
+ $client->request('GET', 'ModifyListenerAttributes', $param);
+ $this->log('ALB监听器 ' . $config['listener_id'] . ' 部署证书成功!');
+ }
+
private function get_cert_id($fullchain, $privatekey)
{
$certInfo = openssl_x509_parse($fullchain, true);
diff --git a/app/service/CertTaskService.php b/app/service/CertTaskService.php
index af942db..77aeb6e 100644
--- a/app/service/CertTaskService.php
+++ b/app/service/CertTaskService.php
@@ -13,6 +13,7 @@ class CertTaskService
{
$this->execute_deploy();
$this->execute_order();
+ (new ExpireNoticeService())->task();
config_set('certtask_time', date("Y-m-d H:i:s"));
echo 'done'.PHP_EOL;
}
diff --git a/app/service/ExpireNoticeService.php b/app/service/ExpireNoticeService.php
new file mode 100644
index 0000000..e5fd2e2
--- /dev/null
+++ b/app/service/ExpireNoticeService.php
@@ -0,0 +1,102 @@
+where('id', $id)->update(['regtime' => $regTime, 'expiretime' => $expireTime, 'checktime' => date('Y-m-d H:i:s'), 'checkstatus' => 1]);
+ return ['code' => 0, 'regTime' => $regTime, 'expireTime' => $expireTime, 'msg' => 'Success'];
+ } catch (Exception $e) {
+ Db::name('domain')->where('id', $id)->update(['checktime' => date('Y-m-d H:i:s'), 'checkstatus' => 2]);
+ return ['code' => -1, 'msg' => $e->getMessage()];
+ }
+ }
+
+ public function task()
+ {
+ $count = $this->refreshDomainList();
+ if ($count > 0) return;
+
+ $days = config_get('expire_noticedays');
+ $max_day = 30;
+ if (!empty($days)) {
+ $days = explode(',', $days);
+ $days = array_map('intval', $days);
+ $max_day = max($days) + 1;
+ }
+ $count = $this->refreshExpiringDomainList($max_day);
+ if ($count > 0) return;
+
+ if (!empty($days) && (config_get('expire_notice_mail') == '1' || config_get('expire_notice_wxtpl') == '1' || config_get('expire_notice_tgbot') == '1' || config_get('expire_notice_webhook') == '1') && date('H') >= 9) {
+ $this->noticeExpiringDomainList($max_day, $days);
+ }
+ }
+
+ private function refreshDomainList()
+ {
+ $domainList = Db::name('domain')->field('id,name')->where('expiretime', null)->where('checkstatus', 0)->select();
+ $count = 0;
+ foreach ($domainList as $domain) {
+ $res = $this->updateDomainDate($domain['id'], $domain['name']);
+ if ($res['code'] == 0) {
+ echo '域名: ' . $domain['name'] . ' 注册时间: ' . $res['regTime'] . ' 到期时间: ' . $res['expireTime'] . PHP_EOL;
+ } else {
+ echo '域名: ' . $domain['name'] . ' 更新失败,' . $res['msg'] . PHP_EOL;
+ }
+ $count++;
+ if ($count >= 5) break;
+ sleep(1);
+ }
+ return $count;
+ }
+
+ private function refreshExpiringDomainList($max_day)
+ {
+ $domainList = Db::name('domain')->field('id,name')->whereRaw('expiretime>=(NOW() - INTERVAL 5 DAY) AND expiretime<=(NOW() + INTERVAL ' . $max_day . ' DAY) AND checktime<=(NOW() - INTERVAL 1 DAY)')->select();
+ $count = 0;
+ foreach ($domainList as $domain) {
+ $res = $this->updateDomainDate($domain['id'], $domain['name']);
+ if ($res['code'] == 0) {
+ echo '域名: ' . $domain['name'] . ' 注册时间: ' . $res['regTime'] . ' 到期时间: ' . $res['expireTime'] . PHP_EOL;
+ } else {
+ echo '域名: ' . $domain['name'] . ' 更新失败,' . $res['msg'] . PHP_EOL;
+ }
+ $count++;
+ if ($count >= 5) break;
+ sleep(1);
+ }
+ return $count;
+ }
+
+ private function noticeExpiringDomainList($max_day, $days)
+ {
+ $domainList = Db::name('domain')->field('id,name,expiretime')->whereRaw('expiretime>=NOW() AND expiretime<=(NOW() + INTERVAL ' . $max_day . ' DAY) AND is_notice=1 AND (noticetime IS NULL OR noticetime<=(NOW() - INTERVAL 20 HOUR))')->order('expiretime', 'asc')->select();
+ $noticeList = [];
+ foreach ($domainList as $domain) {
+ $expireDay = intval((strtotime($domain['expiretime']) - time()) / 86400);
+ if (in_array($expireDay, $days)) {
+ $noticeList[$expireDay][] = ['id' => $domain['id'], 'name' => $domain['name'], 'expiretime' => $domain['expiretime']];
+ }
+ }
+ if (!empty($noticeList)) {
+ foreach ($noticeList as $day => $list) {
+ $ids = array_column($list, 'id');
+ Db::name('domain')->whereIn('id', $ids)->update(['noticetime' => date('Y-m-d H:i:s')]);
+ MsgNotice::expire_notice_send($day, $list);
+ echo '域名到期提醒: ' . $day . '天内到期的' . count($ids) . '个域名已发送' . PHP_EOL;
+ }
+ }
+ }
+}
diff --git a/app/sql/install.sql b/app/sql/install.sql
index de1fd85..cf73ed8 100644
--- a/app/sql/install.sql
+++ b/app/sql/install.sql
@@ -5,7 +5,7 @@ CREATE TABLE `dnsmgr_config` (
PRIMARY KEY (`key`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-INSERT INTO `dnsmgr_config` VALUES ('version', '1028');
+INSERT INTO `dnsmgr_config` VALUES ('version', '1033');
INSERT INTO `dnsmgr_config` VALUES ('notice_mail', '0');
INSERT INTO `dnsmgr_config` VALUES ('notice_wxtpl', '0');
INSERT INTO `dnsmgr_config` VALUES ('mail_smtp', 'smtp.qq.com');
@@ -35,6 +35,12 @@ CREATE TABLE `dnsmgr_domain` (
`is_sso` tinyint(1) NOT NULL DEFAULT '0',
`recordcount` int(1) NOT NULL DEFAULT '0',
`remark` varchar(100) DEFAULT NULL,
+ `is_notice` tinyint(1) NOT NULL DEFAULT '0',
+ `regtime` datetime DEFAULT NULL,
+ `expiretime` datetime DEFAULT NULL,
+ `checktime` datetime DEFAULT NULL,
+ `noticetime` datetime DEFAULT NULL,
+ `checkstatus` tinyint(1) NOT NULL DEFAULT '0',
PRIMARY KEY (`id`),
KEY `name` (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
diff --git a/app/sql/update.sql b/app/sql/update.sql
index a6e415c..3c9db10 100644
--- a/app/sql/update.sql
+++ b/app/sql/update.sql
@@ -155,4 +155,12 @@ ALTER TABLE `dnsmgr_account`
ADD COLUMN `proxy` tinyint(1) NOT NULL DEFAULT '0';
ALTER TABLE `dnsmgr_dmtask`
-ADD COLUMN `cdn` tinyint(1) NOT NULL DEFAULT 0;
\ No newline at end of file
+ADD COLUMN `cdn` tinyint(1) NOT NULL DEFAULT 0;
+
+ALTER TABLE `dnsmgr_domain`
+ADD COLUMN `is_notice` tinyint(1) NOT NULL DEFAULT '0',
+ADD COLUMN `regtime` datetime DEFAULT NULL,
+ADD COLUMN `expiretime` datetime DEFAULT NULL,
+ADD COLUMN `checktime` datetime DEFAULT NULL,
+ADD COLUMN `noticetime` datetime DEFAULT NULL,
+ADD COLUMN `checkstatus` tinyint(1) NOT NULL DEFAULT '0';
\ No newline at end of file
diff --git a/app/utils/MsgNotice.php b/app/utils/MsgNotice.php
index 491b541..4820924 100644
--- a/app/utils/MsgNotice.php
+++ b/app/utils/MsgNotice.php
@@ -133,6 +133,34 @@ class MsgNotice
}
}
+ public static function expire_notice_send($day, $list)
+ {
+ $mail_title = '您有'.count($list).'个域名即将在'.$day.'天后到期';
+ $mail_content = '尊敬的用户,您好:您有'.count($list).'个域名即将在'.$day.'天后到期!
域名&到期时间:
';
+ foreach ($list as $domain) {
+ $mail_content .= ''.$domain['name'].' - '.$domain['expiretime'].'
';
+ }
+ $mail_content .= '
'.self::$sitename.'
'.date('Y-m-d H:i:s').'';
+
+ if (config_get('expire_notice_mail') == 1 || config_get('expire_notice_mail') == 2) {
+ $mail_name = config_get('mail_recv') ? config_get('mail_recv') : config_get('mail_name');
+ self::send_mail($mail_name, $mail_title, $mail_content);
+ }
+ if (config_get('expire_notice_wxtpl') == 1 || config_get('expire_notice_wxtpl') == 2) {
+ $content = str_replace(['
', '', ''], ["\n\n", '**', '**'], $mail_content);
+ self::send_wechat_tplmsg($mail_title, strip_tags($content));
+ }
+ if (config_get('expire_notice_tgbot') == 1 || config_get('expire_notice_tgbot') == 2) {
+ $content = str_replace('
', "\n", $mail_content);
+ $content = "".$mail_title."\n".strip_tags($content);
+ self::send_telegram_bot($content);
+ }
+ if (config_get('expire_notice_webhook') == 1) {
+ $content = str_replace(['*', '
', '', ''], ['\*', "\n", '**', '**'], $mail_content);
+ self::send_webhook($mail_title, $content);
+ }
+ }
+
public static function send_mail($to, $sub, $msg)
{
$mail_type = config_get('mail_type');
diff --git a/app/view/common/layout.html b/app/view/common/layout.html
index fcc2257..f1f5142 100644
--- a/app/view/common/layout.html
+++ b/app/view/common/layout.html
@@ -103,7 +103,7 @@
{if request()->user['type'] eq 'user'}