configuration ?? config('business_storage', []); return ($configuration['driver'] ?? null) === 'qiniu' && $disk === config('mediable.default_disk'); } public function forPath(string $path, ?DateTimeInterface $expiration = null): string { $configuration = ($this->configuration ?? config('business_storage', []))['qiniu'] ?? []; $accessKey = (string) ($configuration['access_key'] ?? ''); $secretKey = (string) ($configuration['secret_key'] ?? ''); if ($accessKey === '' || $secretKey === '') { throw new RuntimeException('业务文件存储凭据不完整。'); } $deadline = $expiration?->getTimestamp() ?? time() + max(60, (int) ($configuration['signed_url_ttl'] ?? 300)); $urlToSign = $this->unsignedUrlForPath($path) . '?e=' . $deadline; $signature = strtr( base64_encode(hash_hmac('sha1', $urlToSign, $secretKey, true)), '+/', '-_' ); return $urlToSign . '&token=' . $accessKey . ':' . $signature; } public function unsignedUrlForPath(string $path): string { $configuration = ($this->configuration ?? config('business_storage', []))['qiniu'] ?? []; $domain = rtrim((string) ($configuration['private_domain'] ?? ''), '/'); $root = trim((string) ($configuration['root'] ?? ''), '/'); $objectPath = $this->encodePath(implode('/', array_filter([ $root, trim(str_replace('\\', '/', $path), '/'), ], static fn ($part) => $part !== ''))); if ($domain === '' || $objectPath === '') { throw new RuntimeException('业务文件路径无效。'); } return $domain . '/' . $objectPath; } private function encodePath(string $path): string { $segments = array_filter( explode('/', $path), static fn ($segment) => $segment !== '' ); foreach ($segments as $segment) { if ($segment === '.' || $segment === '..' || str_contains($segment, "\0")) { throw new RuntimeException('业务文件路径无效。'); } } return implode('/', array_map('rawurlencode', $segments)); } }