Symfony 3.4+Gaufrette处理谷歌存储EPUB文件的读写与上传问题
解决EPUB文件上传到谷歌存储的问题(Symfony 3.4 + Gaufrette 0.3.0)
首先得说,你给出的UploadedFile信息里,error = 1是核心问题——这对应PHP的UPLOAD_ERR_INI_SIZE常量,意思是上传的EPUB文件超过了PHP配置的大小限制,这才导致文件没有路径、大小为0,后续的file_get_contents自然会报错。咱们先把本地上传的坑填上,再一步步处理谷歌存储的上传和读取。
第一步:修复本地文件上传的大小限制问题
你需要调整几个关键配置项:
- 打开
php.ini,找到upload_max_filesize,把它改成比你的EPUB文件大的值,比如20M(根据实际文件大小调整) - 同时把
post_max_size设得比upload_max_filesize大一点,比如25M,因为POST请求的总大小不能超过这个值 - 如果用的是Nginx服务器,还要检查
nginx.conf里的client_max_body_size,同样设成大于文件大小的值
改完之后重启你的Web服务器(Apache/Nginx)和PHP-FPM(如果用的话),这样文件才能正常传到服务器的临时目录。
第二步:用Gaufrette把EPUB传到谷歌存储
当文件能正常上传到本地后,咱们再用Gaufrette的谷歌存储适配器处理云端上传。
1. 配置Gaufrette的谷歌存储适配器
在config.yml里添加如下配置:
knp_gaufrette: adapters: google_cloud_storage: google_cloud_storage: project_id: '你的谷歌云项目ID' key_file: '%kernel.root_dir%/config/google-service-account-key.json' # 替换成你的服务账号密钥文件路径 bucket_name: '你的存储桶名称' filesystems: gcs_media: adapter: google_cloud_storage
2. 编写控制器的上传逻辑
这里给你一个包含验证和上传的完整示例:
use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\File\UploadedFile; use Knp\Bundle\GaufretteBundle\FilesystemMap; use Symfony\Component\HttpFoundation\JsonResponse; class EpubUploadController extends Controller { public function uploadAction(Request $request, FilesystemMap $filesystemMap) { /** @var UploadedFile $epubFile */ $epubFile = $request->files->get('epub_file'); // 对应你表单里的文件字段名 // 先检查文件是否有效上传 if (!$epubFile || $epubFile->getError() !== UPLOAD_ERR_OK) { return new JsonResponse(['error' => '文件上传失败,请检查文件大小是否超出限制'], 400); } // 可选:验证文件类型,确保是EPUB if ($epubFile->getMimeType() !== 'application/epub+zip') { return new JsonResponse(['error' => '请上传有效的EPUB文件'], 400); } // 获取Gaufrette的谷歌存储文件系统实例 $gcsFilesystem = $filesystemMap->get('gcs_media'); // 生成唯一存储文件名(避免重名覆盖) $storageFileName = uniqid('epub_') . '.' . $epubFile->guessExtension(); // 上传文件到谷歌存储——大文件建议用流式上传(见下方提示) $fileContent = file_get_contents($epubFile->getRealPath()); $gcsFilesystem->write($storageFileName, $fileContent); // 如果存储桶允许公开访问,生成公开URL $publicUrl = sprintf('https://storage.googleapis.com/%s/%s', '你的存储桶名称', $storageFileName); return new JsonResponse([ 'status' => 'success', 'storage_filename' => $storageFileName, 'public_url' => $publicUrl ]); } }
提示:如果EPUB文件很大(比如超过100M),用
file_get_contents可能占满内存,改用流式上传更稳妥:$fileStream = $epubFile->openFile('r'); $gcsFilesystem->writeStream($storageFileName, $fileStream);
第三步:从谷歌存储读取EPUB文件
读取方式分两种,按需选择:
1. 通过Gaufrette读取并返回下载响应
适合需要权限验证的场景:
use Knp\Bundle\GaufretteBundle\FilesystemMap; use Symfony\Component\HttpFoundation\Response; class EpubDownloadController extends Controller { public function downloadAction(FilesystemMap $filesystemMap, $fileName) { $gcsFilesystem = $filesystemMap->get('gcs_media'); if (!$gcsFilesystem->has($fileName)) { throw $this->createNotFoundException('该EPUB文件不存在'); } // 获取文件内容 $epubContent = $gcsFilesystem->read($fileName); // 返回下载响应 return new Response( $epubContent, 200, [ 'Content-Type' => 'application/epub+zip', 'Content-Disposition' => sprintf('attachment; filename="%s"', $fileName) ] ); } }
2. 直接通过公开URL访问
如果存储桶设置了对象公开可读权限,用户可以直接用之前生成的publicUrl访问或下载文件。如果需要私有访问,可以用谷歌云的签名URL功能,Gaufrette的谷歌适配器也支持生成签名URL,你可以查阅相关文档实现。
最后几个注意点
- 确保你的谷歌服务账号拥有存储桶的读写权限,不然上传下载都会失败
- 表单提交时一定要加
enctype="multipart/form-data",否则文件根本传不上去 - 如果遇到权限问题,检查谷歌云控制台里存储桶的权限设置,确认服务账号的角色配置正确
内容的提问来源于stack exchange,提问作者shuba.ivan
相关产品推荐
相关产品推荐

