域名管理

This commit is contained in:
root
2026-06-02 00:32:05 +08:00
parent f2ec634888
commit 4aec0b4fce
20 changed files with 1879 additions and 7 deletions
@@ -0,0 +1,247 @@
<?php
declare(strict_types=1);
namespace app\admin\controller;
use app\admin\model\Domain as DomainModel;
use app\common\controller\Backend;
use app\common\service\CloudflareService;
use app\common\service\DomainDetectRateLimitService;
use think\Db;
use think\Exception;
use think\exception\PDOException;
use think\exception\ValidateException;
/**
* 域名管理
*
* @icon fa fa-globe
* @remark 域名接入Cloudflare,新增后请在详情查看NS并到注册商修改
*/
class Domain extends Backend
{
/** @var DomainModel */
protected $model = null;
protected $searchFields = 'domain';
protected $dataLimit = 'personal';
protected $modelValidate = true;
protected $modelSceneValidate = true;
public function _initialize()
{
parent::_initialize();
$this->model = new DomainModel();
$this->view->assign('zoneStatusList', $this->model->getZoneStatusList());
$this->view->assign('nsStatusList', $this->model->getNsStatusList());
$this->view->assign('dnsStatusList', $this->model->getDnsStatusList());
$this->assignconfig('zoneStatusList', $this->model->getZoneStatusList());
$this->assignconfig('nsStatusList', $this->model->getNsStatusList());
$this->assignconfig('dnsStatusList', $this->model->getDnsStatusList());
}
/**
* 禁止编辑
*/
public function edit($ids = null)
{
$this->error(__('Domain cannot be edited after creation'));
}
/**
* 禁止批量操作
*/
public function multi($ids = '')
{
$this->error(__('Invalid parameters'));
}
/**
* 添加域名并创建 Cloudflare Zone
*/
public function add()
{
if (false === $this->request->isPost()) {
return $this->view->fetch();
}
$params = $this->request->post('row/a', []);
if ($params === []) {
$this->error(__('Parameter %s can not be empty', ''));
}
$params = $this->preExcludeFields($params);
$domain = DomainModel::normalizeDomain((string)($params['domain'] ?? ''));
$params['domain'] = $domain;
if ($this->dataLimit && $this->dataLimitFieldAutoFill) {
$params[$this->dataLimitField] = $this->auth->id;
}
$result = false;
Db::startTrans();
try {
if ($this->modelValidate) {
$name = str_replace('\\model\\', '\\validate\\', get_class($this->model));
$validate = $this->modelSceneValidate ? $name . '.add' : $name;
$this->model->validateFailException()->validate($validate, $params);
}
if (DomainModel::where('domain', $domain)->find()) {
throw new ValidateException(__('Domain already exists'));
}
$cloudflare = new CloudflareService();
$zone = $cloudflare->createZone($domain);
$params['full_url'] = 'https://' . $domain;
$params['zone_id'] = $zone['zone_id'];
$params['nameservers'] = $zone['name_servers'];
$params['zone_status'] = DomainModel::mapCloudflareZoneStatus($zone['status']);
$params['ns_status'] = 'pending';
$params['dns_status'] = 'pending';
$params['check_result'] = '';
$result = $this->model->allowField(true)->save($params);
Db::commit();
} catch (ValidateException $e) {
Db::rollback();
$this->error($e->getMessage());
} catch (PDOException|Exception $e) {
Db::rollback();
$this->error($e->getMessage());
}
if ($result === false) {
$this->error(__('No rows were inserted'));
}
$this->success(__('Domain submitted, please check NS in detail page and update at registrar'));
}
/**
* 域名详情
*/
public function detail($ids = null)
{
$row = $this->model->get($ids);
if (!$row) {
$this->error(__('No Results were found'));
}
if (!$this->checkDataLimit($row)) {
$this->error(__('You have no permission'));
}
$data = $row->toArray();
$data['nameservers_list'] = $row->getNameserversArray();
$this->view->assign('row', $data);
return $this->view->fetch();
}
/**
* 检测域名状态
*/
public function detect($ids = null)
{
if (!$this->request->isPost()) {
$this->error(__('Invalid parameters'));
}
$row = $this->model->get($ids);
if (!$row) {
$this->error(__('No Results were found'));
}
if (!$this->checkDataLimit($row)) {
$this->error(__('You have no permission'));
}
try {
(new DomainDetectRateLimitService())->assertCanDetect((int)$this->auth->id, (int)$row['id']);
} catch (Exception $e) {
$this->error($e->getMessage());
}
try {
$cloudflare = new CloudflareService();
$detect = $cloudflare->detectDomain($row->toArray());
$row->save([
'zone_status' => $detect['zone_status'],
'ns_status' => $detect['ns_status'],
'dns_status' => $detect['dns_status'],
'check_time' => time(),
'check_result' => $detect['check_result'],
]);
} catch (Exception $e) {
$this->error($e->getMessage());
}
$this->success(__('Detection completed'), null, $row->toArray());
}
/**
* 删除(需输入完整域名二次确认)
*/
public function del($ids = '')
{
if (!$this->request->isPost()) {
$this->error(__('Invalid parameters'));
}
$ids = $ids ?: $this->request->post('ids', '');
$confirmDomain = trim((string)$this->request->post('confirm_domain', ''));
if ($ids === '' || $confirmDomain === '') {
$this->error(__('Please enter the full domain to confirm deletion'));
}
$pk = $this->model->getPk();
$list = $this->model->where($pk, 'in', $ids)->select();
if (!$list || count($list) === 0) {
$this->error(__('No Results were found'));
}
$count = 0;
Db::startTrans();
try {
foreach ($list as $item) {
if (!$this->checkDataLimit($item)) {
throw new Exception(__('You have no permission'));
}
if (DomainModel::normalizeDomain($confirmDomain) !== DomainModel::normalizeDomain((string)$item['domain'])) {
throw new Exception(__('Domain confirmation does not match'));
}
if (!empty($item['zone_id'])) {
$cloudflare = new CloudflareService();
$cloudflare->deleteZone((string)$item['zone_id']);
}
$count += $item->delete();
}
Db::commit();
} catch (PDOException|Exception $e) {
Db::rollback();
$this->error($e->getMessage());
}
if ($count > 0) {
$this->success();
}
$this->error(__('No rows were deleted'));
}
/**
* @param DomainModel $row
*/
protected function checkDataLimit($row): bool
{
if (!$this->dataLimit) {
return true;
}
$adminIds = $this->getDataLimitAdminIds();
if (!is_array($adminIds)) {
return true;
}
return in_array((int)$row[$this->dataLimitField], $adminIds, true);
}
}