symfony 7.2 中上传文件必须先调用 uploadedfile->move(),不可直接用 flysystem->write() 处理 $_files;因 write() 接收内容而非路径,且 move() 提供 mime 校验、临时文件清理等关键保障。

直接说结论:Symfony 7.2 里上传文件后存到 Flysystem,不能跳过 UploadedFile->move() 这一步去直传;Flysystem 的 write() 接收的是字符串或资源流,不是临时文件句柄——硬塞会丢内容或报错。
为什么不能用 $filesystem->write() 直接写 $_FILES?
Flysystem 的 write() 方法只接受内容(string 或 resource),而 PHP 上传机制给你的 $_FILES 或 UploadedFile 实例只是个指向临时文件的“指针”,不是文件内容本身。你若直接传 $file->getRealPath() 给 write(),它会当成路径字符串写进去,不是读取文件内容。
-
UploadedFile->getRealPath()返回类似/tmp/phpABC123的路径,但write('path/to/file.txt', $file->getRealPath())是把这串路径文本写进文件,不是把上传的 PDF 写进去 - 想用 Flysystem 写内容,得先
file_get_contents($file->getRealPath()),但大文件会爆内存;更安全的做法是fopen($file->getRealPath(), 'r')再传 resource 给writeStream() - 但注意:
UploadedFile->move()才是 Symfony 官方支持的、带校验和清理的唯一可靠方式;绕过它等于放弃 MIME 校验、临时文件自动清理、错误码映射等保障
上传后 move() 到哪里?Flysystem 要求绝对路径
Flysystem 不管你 move 到哪,但它自己读写时认的是配置里的 directory。所以 move 目标目录必须和 Flysystem 配置的物理路径一致,否则后续 has()/read() 就找不到。
- 正确做法:先
$file->move('%kernel.project_dir%/public/uploads', $safeName),再让 Flysystem 配置指向同一目录:directory: '%kernel.project_dir%/public/uploads' - 别写
directory: 'public/uploads'—— Flysystem 不解析相对路径,它会去找当前工作目录下的public/uploads(通常是public/),而不是项目根目录 - Windows 下路径分隔符必须用
/,比如%kernel.project_dir%/var/storage,不要用\,否则has()返回 false - 确认 Web 用户(如
www-data)对目标目录有写权限:chmod -R 755 public/uploads && chown -R www-data:www-data public/uploads
怎么用 Flysystem 读写已上传的文件?
move 完之后,文件就在本地磁盘上,Flysystem 只是提供统一接口去操作它。关键点在于:别混淆 read() 和响应返回逻辑。
-
$filesystem->read('uploads/myfile.pdf')返回的是string内容,不是Response对象;直接return $filesystem->read(...)会触发 “Object of class League\Flysystem\File could not be converted to string” 错误 - 下载文件要手动构造 Response:
return new BinaryFileResponse($filesystem->readStream('uploads/myfile.pdf')),但注意readStream()返回 resource,BinaryFileResponse要求真实文件路径 —— 所以更稳妥的是用read()+Response:return new Response($filesystem->read('uploads/myfile.pdf'), 200, ['Content-Type' => 'application/pdf']) - 检查文件是否存在,必须用
$filesystem->has('uploads/myfile.pdf'),别信file_exists(),因为 Flysystem 可能挂载的是 S3,本地file_exists()永远返回 false - 删除文件用
$filesystem->delete('uploads/myfile.pdf'),它会同时清理本地文件(如果用的是本地 adapter)
FlysystemBundle 和 OneupFlysystemBundle 别混用
服务名、配置位置、自动注入规则全不同,混了就报 Cannot autowire argument 或 ServiceNotFoundException。
- FlysystemBundle(推荐):配置在
config/packages/flysystem.yaml,服务名按驼峰生成,比如default_storage→ 自动注入类型为FilesystemOperator - OneupFlysystemBundle:配置在
config/packages/oneup_flysystem.yaml或旧式config.yml,服务名固定为oneup_flysystem.default_filesystem,需手动声明类型提示 - 迁移时务必删干净旧 bundle:
composer remove oneup/flysystem-bundle,清空所有oneup_*配置项,否则容器编译失败
最易被忽略的一点:上传流程里 move() 是不可替代的中间环节,Flysystem 不是上传代理,它是存储抽象层。你得先让 Symfony 把文件安全落地,再交给 Flysystem 管理——顺序错了,后面全崩。











