作者 lyh
@@ -16,6 +16,7 @@ use App\Models\Project\CountryCustom; @@ -16,6 +16,7 @@ use App\Models\Project\CountryCustom;
16 use App\Models\Project\Project; 16 use App\Models\Project\Project;
17 use Illuminate\Console\Command; 17 use Illuminate\Console\Command;
18 use App\Models\Domain\DomainInfo as DomainInfoModel; 18 use App\Models\Domain\DomainInfo as DomainInfoModel;
  19 +use Illuminate\Support\Facades\Log;
19 use Symfony\Component\Process\Process; 20 use Symfony\Component\Process\Process;
20 21
21 class DomainInfo extends Command 22 class DomainInfo extends Command
@@ -43,6 +44,9 @@ class DomainInfo extends Command @@ -43,6 +44,9 @@ class DomainInfo extends Command
43 */ 44 */
44 public function handle() 45 public function handle()
45 { 46 {
  47 + //先更新所有域名证书有效期
  48 + $this->startUpdateSslTime();
  49 +
46 //主站证书到期更新 50 //主站证书到期更新
47 $this->startUpdateCert(); 51 $this->startUpdateCert();
48 52
@@ -56,6 +60,47 @@ class DomainInfo extends Command @@ -56,6 +60,47 @@ class DomainInfo extends Command
56 } 60 }
57 61
58 /** 62 /**
  63 + * 更新域名证书有效期
  64 + * @author Akun
  65 + * @date 2024/09/06 11:16
  66 + */
  67 + public function startUpdateSslTime()
  68 + {
  69 + $domainModel = new DomainInfoModel();
  70 + $projectModel = new Project();
  71 + $serverIpModel = new ServersIp();
  72 + $list = $domainModel->where('status', '=', 1)->get();
  73 + foreach ($list as $v) {
  74 + $project_info = $projectModel->read(['id' => $v['project_id']], ['serve_id']);
  75 + if (!$project_info) {
  76 + continue;
  77 + }
  78 +
  79 + $servers_ip_info = $serverIpModel->read(['id' => $project_info['serve_id']], ['servers_id', 'ip', 'domain']);
  80 + if (!$servers_ip_info) {
  81 + continue;
  82 + }
  83 +
  84 + //除自建站项目外,记录已解析到别的ip的域名
  85 + if ($servers_ip_info['servers_id'] != ServerConfig::SELF_SITE_ID) {
  86 + //过滤已解析到别的ip的域名
  87 + if (!$this->check_cname($v['domain'], $servers_ip_info)) {
  88 + Log::channel('analyze_other')->error('域名 [' . $v['domain'] . '] 已解析到别的IP');
  89 + continue;
  90 + }
  91 + }
  92 +
  93 + //获取证书有效期并更新
  94 + $ssl_time = $this->getDomainSslTime($v['domain']);
  95 + if ($ssl_time['from'] && $ssl_time['to']) {
  96 + $v->certificate_start_time = $ssl_time['from'];
  97 + $v->certificate_end_time = $ssl_time['to'];
  98 + $v->save();
  99 + }
  100 + }
  101 + }
  102 +
  103 + /**
59 * 主站证书到期更新 104 * 主站证书到期更新
60 * @author Akun 105 * @author Akun
61 * @date 2024/02/26 10:26 106 * @date 2024/02/26 10:26
@@ -190,6 +235,7 @@ class DomainInfo extends Command @@ -190,6 +235,7 @@ class DomainInfo extends Command
190 235
191 //过滤已解析到别的ip的域名 236 //过滤已解析到别的ip的域名
192 if (!$this->check_cname($v['custom_domain'], $servers_ip_info)) { 237 if (!$this->check_cname($v['custom_domain'], $servers_ip_info)) {
  238 + Log::channel('analyze_other')->error('自定义跳转域名 [' . $v['custom_domain'] . '] 已解析到别的IP');
193 continue; 239 continue;
194 } 240 }
195 241
@@ -207,6 +253,42 @@ class DomainInfo extends Command @@ -207,6 +253,42 @@ class DomainInfo extends Command
207 } 253 }
208 254
209 /** 255 /**
  256 + * 获取域名证书有效时间
  257 + * @param $domain
  258 + * @return string[]
  259 + * @author Akun
  260 + * @date 2024/08/29 9:59
  261 + */
  262 + public function getDomainSslTime($domain)
  263 + {
  264 + $valid_from = '';
  265 + $valid_to = '';
  266 + try {
  267 + $context = stream_context_create([
  268 + 'ssl' => [
  269 + 'capture_peer_cert' => true,
  270 + 'capture_peer_cert_chain' => false,
  271 + 'verify_peer' => false,
  272 + 'verify_peer_name' => false
  273 + ],
  274 + ]);
  275 + $stream = stream_socket_client('ssl://' . $domain . ':443', $errno, $errstr, 30, STREAM_CLIENT_CONNECT, $context);
  276 + if ($stream) {
  277 + $remote_cert = stream_context_get_params($stream)['options']['ssl']['peer_certificate'];
  278 + if ($remote_cert) {
  279 + $valid_from = date('Y-m-d H:i:s', openssl_x509_parse($remote_cert)['validFrom_time_t']);
  280 + $valid_to = date('Y-m-d H:i:s', openssl_x509_parse($remote_cert)['validTo_time_t']);
  281 + }
  282 + }
  283 + fclose($stream);
  284 + } catch (\Exception $e) {
  285 + $valid_from = '';
  286 + $valid_to = '';
  287 + }
  288 + return ['from' => $valid_from, 'to' => $valid_to];
  289 + }
  290 +
  291 + /**
210 * 验证是否cname或者A记录解析到目标服务器 292 * 验证是否cname或者A记录解析到目标服务器
211 * @param $domain 293 * @param $domain
212 * @param $server_info 294 * @param $server_info
@@ -101,6 +101,12 @@ return [ @@ -101,6 +101,12 @@ return [
101 'via' => \App\Factory\LogFormatterFactory::class, 101 'via' => \App\Factory\LogFormatterFactory::class,
102 'prefix' => 'wechatside', 102 'prefix' => 'wechatside',
103 ], 103 ],
  104 + //域名解析别处记录日志
  105 + 'analyze_other' => [
  106 + 'driver' => 'custom',
  107 + 'via' => \App\Factory\LogFormatterFactory::class,
  108 + 'prefix' => 'analyze_other',
  109 + ],
104 'stack' => [ 110 'stack' => [
105 'driver' => 'stack', 111 'driver' => 'stack',
106 'channels' => ['single'], 112 'channels' => ['single'],