SecretId = $config['SecretId']; $this->SecretKey = $config['SecretKey']; $this->proxy = isset($config['proxy']) ? $config['proxy'] == 1 : false; $this->client = new TencentCloud($this->SecretId, $this->SecretKey, $this->endpoint, $this->service, $this->version, null, $this->proxy); $this->email = $config['email']; } public function register() { if (empty($this->SecretId) || empty($this->SecretKey) || empty($this->email)) throw new Exception('必填参数不能为空'); $this->request('DescribeCertificates', []); return true; } public function buyCert($domainList, &$order) {} public function createOrder($domainList, &$order, $keytype, $keysize) { if (empty($domainList)) throw new Exception('域名列表不能为空'); $domain = $domainList[0]; $param = [ 'DvAuthMethod' => 'DNS', 'DomainName' => $domain, 'ContactEmail' => $this->email, 'CsrEncryptAlgo' => $keytype, 'CsrKeyParameter' => $keytype == 'ECC' ? 'prime256v1' : '2048', ]; $data = $this->request('ApplyCertificate', $param); if (empty($data['CertificateId'])) throw new Exception('证书申请失败,CertificateId为空'); $order['CertificateId'] = $data['CertificateId']; $param = [ 'CertificateId' => $order['CertificateId'], ]; $data = $this->request('DescribeCertificate', $param); $order['OrderId'] = $data['OrderId']; $dnsList = []; if (!empty($data['DvAuthDetail']['DvAuths'])) { foreach ($data['DvAuthDetail']['DvAuths'] as $opts) { $mainDomain = getMainDomain($opts['DvAuthKey']); $name = substr($opts['DvAuthKey'], 0, -(strlen($mainDomain) + 1)); $dnsList[$mainDomain][] = ['name' => $name, 'type' => $opts['DvAuthVerifyType'] ?? 'CNAME', 'value' => $opts['DvAuthValue']]; } } return $dnsList; } public function authOrder($domainList, $order) { $param = [ 'CertificateId' => $order['CertificateId'], ]; $data = $this->request('DescribeCertificate', $param); if ($data['Status'] == 0 || $data['Status'] == 4) { $this->request('CompleteCertificate', $param); sleep(3); } } public function getAuthStatus($domainList, $order) { $param = [ 'CertificateId' => $order['CertificateId'], ]; $data = $this->request('DescribeCertificate', $param); if ($data['Status'] == 1) { return true; } elseif ($data['Status'] == 2) { throw new Exception('证书审核失败' . (empty($data['StatusMsg'] ? '' : ':' . $data['StatusMsg']))); } else { return false; } } public function finalizeOrder($domainList, $order, $keytype, $keysize) { $param = [ 'CertificateIds' => [$order['CertificateId']], 'SwitchStatus' => 1, ]; $this->request('ModifyCertificatesExpiringNotificationSwitch', $param); if (!is_dir(app()->getRuntimePath() . 'cert')) mkdir(app()->getRuntimePath() . 'cert'); $param = [ 'CertificateId' => $order['CertificateId'], 'ServiceType' => 'nginx', ]; $data = $this->request('DescribeDownloadCertificateUrl', $param); $file_data = http_request($data['DownloadCertificateUrl'], null, null, null, null, $this->proxy); $file_data = $file_data['body'] ?? null; if (empty($file_data)) throw new Exception('下载证书失败'); $file_path = app()->getRuntimePath() . 'cert/' . $data['DownloadFilename']; $file_name = substr($data['DownloadFilename'], 0, -4); file_put_contents($file_path, $file_data); $zip = new \ZipArchive; if ($zip->open($file_path) === true) { $zip->extractTo(app()->getRuntimePath() . 'cert/'); $zip->close(); } else { throw new Exception('解压证书失败'); } $cert_dir = app()->getRuntimePath() . 'cert/' . $file_name; $items = scandir($cert_dir); if ($items === false) throw new Exception('解压后的证书文件夹不存在'); $private_key = null; $fullchain = null; foreach ($items as $item) { if (substr($item, -4) == '.key') { $private_key = file_get_contents($cert_dir . '/' . $item); } elseif (substr($item, -4) == '.crt') { $fullchain = file_get_contents($cert_dir . '/' . $item); } } if (empty($private_key) || empty($fullchain)) throw new Exception('解压后的证书文件夹内未找到证书文件'); clearDirectory($cert_dir); rmdir($cert_dir); unlink($file_path); $certInfo = openssl_x509_parse($fullchain, true); if (!$certInfo) throw new Exception('证书解析失败'); return ['private_key' => $private_key, 'fullchain' => $fullchain, 'issuer' => $certInfo['issuer']['CN'], 'subject' => $certInfo['subject']['CN'], 'validFrom' => $certInfo['validFrom_time_t'], 'validTo' => $certInfo['validTo_time_t']]; } public function revoke($order, $pem) { $param = [ 'CertificateId' => $order['CertificateId'], ]; $action = 'RevokeCertificate'; $data = $this->request($action, $param); if (!empty($data['RevokeDomainValidateAuths'])) { $dnsList = []; foreach ($data['RevokeDomainValidateAuths'] as $opts) { $mainDomain = getMainDomain($opts['DomainValidateAuthKey']); $name = substr($opts['DomainValidateAuthKey'], 0, -(strlen($mainDomain) + 1)); $dnsList[$mainDomain][] = ['name' => $name, 'type' => 'TXT', 'value' => $opts['DomainValidateAuthValue']]; } \app\utils\CertDnsUtils::addDns($dnsList, function ($txt) { $this->log($txt); }); } } public function cancel($order) { $param = [ 'CertificateId' => $order['CertificateId'], ]; $action = 'CancelAuditCertificate'; $this->request($action, $param); } public function setLogger($func) { $this->logger = $func; } private function log($txt) { if ($this->logger) { call_user_func($this->logger, $txt); } } private function request($action, $param) { $this->log('Action:' . $action . PHP_EOL . 'Request:' . json_encode($param, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES)); $result = $this->client->request($action, $param); $this->log('Response:' . json_encode($result, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES)); return $result; } }