'', 'secret_key' => '', 'bucket' => '', 'domain' => '', 'path_prefix' => '', ]; /** * 注入解密后的运行时配置 */ public function withConfig(array $config): static { $this->config = array_merge($this->config, $config); return $this; } public function uploadImage($filePath, string $key): bool|array { return $this->uploadFile($filePath, $key); } public function uploadVideo($filePath, string $key): bool|array { return $this->uploadFile($filePath, $key); } public function deleteImage($key): bool { return $this->deleteFile($key); } public function deleteVideo($key): bool { return $this->deleteFile($key); } /** * 列举空间对象(BucketManager::listFiles,marker 分页) * * 七牛只在还有下一页时才回 marker,所以 marker 为空即等于列完了。 */ public function listObjects(string $prefix = '', string $marker = '', int $limit = 100): array { $bucketMgr = $this->bucketManager(); $bucket = (string) ($this->config['bucket'] ?? ''); [$ret, $err] = $bucketMgr->listFiles( $bucket, $this->scopedListPrefix($prefix), $marker !== '' ? $marker : null, $this->boundedLimit($limit) ); if ($err !== null) { UtilsService::getInstance()->errorThrow('七牛云列举对象失败:' . $this->errorText($err)); } $items = []; foreach ((array) ($ret['items'] ?? []) as $row) { $key = $this->normalizeObjectKey((string) ($row['key'] ?? '')); if ($key === '' || str_ends_with($key, '/')) { continue; } $items[] = [ 'key' => $key, 'size' => (int) ($row['fsize'] ?? 0), 'hash' => (string) ($row['hash'] ?? ''), // putTime 的单位是 100 纳秒,当秒用会得到五亿年后的时间戳 'last_modified' => intdiv((int) ($row['putTime'] ?? 0), 10000000), 'url' => $this->publicUrlOf($key, $key), ]; } $next = (string) ($ret['marker'] ?? ''); return [ 'items' => $items, 'next_marker' => $next, 'finished' => $next === '', ]; } public function deleteObject(string $key): bool { return $this->deleteFile($this->normalizeObjectKey($key)); } /** * 上传到七牛;无 SDK 时抛业务异常引导安装或改本地 */ private function uploadFile($filePath, string $key): bool|array { if (!class_exists(\Qiniu\Auth::class)) { UtilsService::getInstance()->errorThrow('未安装 qiniu/php-sdk,请改用本地存储或安装依赖'); } $accessKey = (string) ($this->config['access_key'] ?? ''); $secretKey = (string) ($this->config['secret_key'] ?? ''); $bucket = (string) ($this->config['bucket'] ?? ''); $domain = rtrim((string) ($this->config['domain'] ?? ''), '/'); if ($accessKey === '' || $secretKey === '' || $bucket === '') { UtilsService::getInstance()->errorThrow('七牛云配置不完整'); } $prefix = trim((string) ($this->config['path_prefix'] ?? ''), '/'); if ($prefix !== '' && !str_starts_with($key, $prefix . '/')) { $key = $prefix . '/' . ltrim($key, '/'); } $path = is_object($filePath) && method_exists($filePath, 'getRealPath') ? $filePath->getRealPath() : (string) $filePath; $auth = new \Qiniu\Auth($accessKey, $secretKey); $token = $auth->uploadToken($bucket); $uploadMgr = new \Qiniu\Storage\UploadManager(); list($ret, $err) = $uploadMgr->putFile($token, $key, $path); if ($err !== null) { return false; } return [ 'key' => $ret['key'], 'url' => $domain . '/' . $ret['key'], ]; } private function deleteFile(string $key): bool { if (!class_exists(\Qiniu\Auth::class)) { return false; } $auth = new \Qiniu\Auth($this->config['access_key'], $this->config['secret_key']); $bucketMgr = new \Qiniu\Storage\BucketManager($auth); $err = $bucketMgr->delete($this->config['bucket'], $key); return $err === null; } /** * 构造 BucketManager,顺手把「没装 SDK / 没填配置」两种情况前置拦掉 */ private function bucketManager(): \Qiniu\Storage\BucketManager { if (!class_exists(\Qiniu\Auth::class)) { UtilsService::getInstance()->errorThrow('未安装 qiniu/php-sdk,请改用本地存储或安装依赖'); } $accessKey = (string) ($this->config['access_key'] ?? ''); $secretKey = (string) ($this->config['secret_key'] ?? ''); $bucket = (string) ($this->config['bucket'] ?? ''); if ($accessKey === '' || $secretKey === '' || $bucket === '') { UtilsService::getInstance()->errorThrow('七牛云配置不完整'); } return new \Qiniu\Storage\BucketManager(new \Qiniu\Auth($accessKey, $secretKey)); } /** * SDK 的错误对象没有统一契约,转成人能看懂的一行字 */ private function errorText(mixed $err): string { if (is_object($err) && method_exists($err, 'message')) { return (string) $err->message(); } if (is_object($err) || is_array($err)) { return (string) json_encode($err, JSON_UNESCAPED_UNICODE); } return (string) $err; } }