config = $config; $this->storage = $this->createStorage($config); } public static function getInstance(array $config = []): self { if (self::$instance === null) { self::$instance = new self($config); } return self::$instance; } private function createStorage(array $config): StorageInterface { $type = $config['type'] ?? 'local'; switch ($type) { case 'local': $root = $config['root'] ?? runtime_path('storage'); $urlPrefix = $config['url_prefix'] ?? ''; return new LocalStorage($root, $urlPrefix); default: throw new BusinessException(500, 'Unsupported storage type: ' . $type); } } public function put(string $path, string $content, array $options = []): bool { return $this->storage->put($path, $content, $options); } public function putFile(string $path, string $localPath, array $options = []): bool { return $this->storage->putFile($path, $localPath, $options); } public function get(string $path): ?string { return $this->storage->get($path); } public function exists(string $path): bool { return $this->storage->exists($path); } public function delete(string $path): bool { return $this->storage->delete($path); } public function copy(string $from, string $to): bool { return $this->storage->copy($from, $to); } public function move(string $from, string $to): bool { return $this->storage->move($from, $to); } public function size(string $path): ?int { return $this->storage->size($path); } public function lastModified(string $path): ?int { return $this->storage->lastModified($path); } public function url(string $path): ?string { return $this->storage->url($path); } public function list(string $directory): array { return $this->storage->list($directory); } public function allFiles(string $directory): array { return $this->storage->allFiles($directory); } public function deleteDirectory(string $directory): bool { return $this->storage->deleteDirectory($directory); } public function upload(string $key, array $options = []): ?string { if (!isset($_FILES[$key]) || $_FILES[$key]['error'] !== UPLOAD_ERR_OK) { return null; } $file = $_FILES[$key]; $originalName = $file['name']; $extension = pathinfo($originalName, PATHINFO_EXTENSION); // 生成唯一文件名 $filename = uniqid() . '.' . $extension; // 支持自定义目录 $directory = $options['directory'] ?? 'uploads/' . date('Y/m/d'); $path = $directory . '/' . $filename; if ($this->putFile($path, $file['tmp_name'], $options)) { return $path; } return null; } public function uploadMultiple(string $key, array $options = []): array { if (!isset($_FILES[$key])) { return []; } $files = $_FILES[$key]; $paths = []; // 处理多个文件上传 if (is_array($files['name'])) { $count = count($files['name']); for ($i = 0; $i < $count; $i++) { if ($files['error'][$i] !== UPLOAD_ERR_OK) { continue; } $tmpName = $files['tmp_name'][$i]; $originalName = $files['name'][$i]; $extension = pathinfo($originalName, PATHINFO_EXTENSION); $filename = uniqid() . '.' . $extension; $directory = $options['directory'] ?? 'uploads/' . date('Y/m/d'); $path = $directory . '/' . $filename; if ($this->putFile($path, $tmpName, $options)) { $paths[] = $path; } } } else { // 单个文件 if ($files['error'] === UPLOAD_ERR_OK) { $path = $this->upload($key, $options); if ($path) { $paths[] = $path; } } } return $paths; } public function setStorage(StorageInterface $storage): void { $this->storage = $storage; } public function getStorage(): StorageInterface { return $this->storage; } public function getConfig(): array { return $this->config; } } if (!function_exists('runtime_path')) { function runtime_path(string $path = ''): string { return dirname(__DIR__, 4) . '/runtime/' . ltrim($path, '/'); } }