url = rtrim($config['url'], '/'); $this->username = $config['username']; $this->password = $config['password']; $this->version = $config['version']; $this->proxy = $config['proxy'] == 1; } public function check() { if (empty($this->url) || empty($this->username) || empty($this->password)) throw new Exception('必填内容不能为空'); $this->login(); } private function login() { $url = $this->url . '/webapi/' . ($this->version == '1' ? 'auth.cgi' : 'entry.cgi'); $params = [ 'api' => 'SYNO.API.Auth', 'version' => 6, 'method' => 'login', 'session' => 'webui', 'account' => $this->username, 'passwd' => $this->password, 'format' => 'sid', 'enable_syno_token' => 'yes', ]; $response = http_request($url, http_build_query($params), null, null, null, $this->proxy); $result = json_decode($response['body'], true); if (isset($result['success']) && $result['success']) { $this->token = $result['data']; } elseif (isset($result['error'])) { throw new Exception('登录失败:' . $result['error']); } else { throw new Exception('请求失败(httpCode=' . $response['code'] . ')'); } } public function deploy($fullchain, $privatekey, $config, &$info) { $this->login(); $certInfo = openssl_x509_parse($fullchain, true); $certInfo['validFrom_time_t']; if (!$certInfo) throw new Exception('证书解析失败'); $url = $this->url . '/webapi/entry.cgi'; $params = [ 'api' => 'SYNO.Core.Certificate.CRT', 'version' => 1, 'method' => 'list', '_sid' => $this->token['sid'], 'SynoToken' => $this->token['synotoken'], ]; $response = http_request($url . '?' . http_build_query($params), null, null, $this->proxy); $result = json_decode($response['body'], true); if (isset($result['success']) && $result['success']) { $this->log('获取证书列表成功'); } elseif (isset($result['error'])) { throw new Exception('获取证书列表失败:' . json_encode($result['error'])); } else { throw new Exception('获取证书列表失败(httpCode=' . $response['code'] . ')'); } $id = null; $validFrom = 0; foreach ($result['data']['certificates'] as $certificate) { if ($certificate['subject']['common_name'] == $certInfo['subject']['CN'] || $certificate['desc'] == $config['desc']) { $id = $certificate['id']; $validFrom = \DateTime::createFromFormat('M d H:i:s Y T', $certificate['valid_from'])->getTimestamp(); break; } } if ($id) { if ($validFrom == $certInfo['validFrom_time_t']) { $this->log('证书ID:' . $id . '已存在,无需更新'); return; } $this->import($fullchain, $privatekey, $config, $id); } else { $this->import($fullchain, $privatekey, $config); } } private function import($fullchain, $privatekey, $config, $id = null) { $url = $this->url . '/webapi/entry.cgi'; $params = [ 'api' => 'SYNO.Core.Certificate', 'version' => 1, 'method' => 'import', '_sid' => $this->token['sid'], 'SynoToken' => $this->token['synotoken'], ]; $headers = [ 'Content-Type' => 'multipart/form-data' ]; $post = [ [ 'name' => 'key', 'filename' => 'key.pem', 'contents' => $privatekey ], [ 'name' => 'cert', 'filename' => 'cert.pem', 'contents' => $fullchain ], [ 'name' => 'id', 'contents' => $id ], [ 'name' => 'desc', 'contents' => $config['desc'] ] ]; $response = http_request($url . '?' . http_build_query($params), $post, null, null, $headers, $this->proxy, null, 15); $result = json_decode($response['body'], true); if ($id) { if (isset($result['success']) && $result['success']) { $this->log('证书ID:' . $id . '更新成功!'); } elseif (isset($result['error'])) { throw new Exception('证书ID:' . $id . '更新失败:' . json_encode($result['error'])); } else { throw new Exception('证书ID:' . $id . '更新失败(httpCode=' . $response['code'] . ')'); } } else { if (isset($result['success']) && $result['success']) { $this->log('证书上传成功!'); } elseif (isset($result['error'])) { throw new Exception('证书上传失败:' . json_encode($result['error'])); } else { throw new Exception('证书上传失败(httpCode=' . $response['code'] . ')'); } } } public function setLogger($func) { $this->logger = $func; } private function log($txt) { if ($this->logger) { call_user_func($this->logger, $txt); } } }