environment = strtolower(trim($environment)); $this->baseUrl = rtrim(trim($baseUrl), '/'); $this->appId = trim($appId); $this->appSecret = trim($appSecret); $this->notifyUrl = trim($notifyUrl); $this->callbackToleranceSeconds = max(60, $callbackToleranceSeconds); $this->timeout = max(5, $timeout); } public static function fromConfig(): self { return new self( environment: strtolower(trim((string) config('services.esign.environment', 'sandbox'))), baseUrl: rtrim(trim((string) config('services.esign.base_url')), '/'), appId: trim((string) config('services.esign.app_id')), appSecret: trim((string) config('services.esign.app_secret')), notifyUrl: trim((string) config('services.esign.notify_url')), callbackToleranceSeconds: max(60, (int) config('services.esign.callback_tolerance_seconds', 900)), timeout: max(5, (int) config('services.esign.timeout', 20)), ); } public function isConfigured(): bool { return $this->appId !== '' && $this->appSecret !== ''; } public function assertReadyForApi(): void { if (! $this->isConfigured()) { $label = $this->environment === 'production' ? '正式' : '沙箱'; throw new RuntimeException("E 签宝{$label}尚未配置 App ID 或 AppSecret。"); } if (! in_array($this->environment, ['sandbox', 'production'], true)) { throw new RuntimeException('E 签宝环境只能是 sandbox 或 production。'); } if ($this->baseUrl === '' || filter_var($this->baseUrl, FILTER_VALIDATE_URL) === false) { throw new RuntimeException('E 签宝 API 地址无效,请检查 ESIGN_BASE_URL。'); } $scheme = strtolower((string) parse_url($this->baseUrl, PHP_URL_SCHEME)); $host = strtolower((string) parse_url($this->baseUrl, PHP_URL_HOST)); if ($scheme !== 'https') { throw new RuntimeException('E 签宝 API 地址必须使用 HTTPS。'); } if ($this->environment === 'production' && $host === 'smlopenapi.esign.cn') { throw new RuntimeException('E 签宝正式环境不能使用沙箱 API 地址。'); } if ($this->environment === 'sandbox' && $host === 'openapi.esign.cn') { throw new RuntimeException('E 签宝沙箱环境不能使用正式 API 地址。'); } } public function environment(): string { return $this->environment; } public function baseUrl(): string { return $this->baseUrl; } public function appId(): string { return $this->appId; } public function appSecret(): string { return $this->appSecret; } public function notifyUrl(): string { return $this->notifyUrl; } public function callbackToleranceSeconds(): int { return $this->callbackToleranceSeconds; } public function timeout(): int { return $this->timeout; } }