Laravel原生支持FTP存储但需league/flysystem-ftp适配器,常见错误源于config/filesystems.php中driver键未写死为'ftp'字符串、环境变量未加载或未清配置缓存;共享主机需设ignorePassiveAddress=>true;路径为root相对路径,上传前应验证凭证与目录权限。

直接说结论:Laravel 原生支持 FTP 存储,但必须用 league/flysystem-ftp 适配器,且配置稍有不慎就会报 ValueError: Path cannot be empty 或 Driver [] is not supported —— 这两类错误几乎都源于 config/filesystems.php 里 driver 键写错,或环境变量未加载成功。
FTP 磁盘配置必须写死 'ftp' 字符串,不能 env('DRIVER')
常见错误是把 driver 设成 env('FTP_DRIVER') 或漏写引号变成 ftp(PHP 会当常量解析,未定义就为空)。Laravel 内部靠这个字符串匹配驱动类,空值或非法值会导致整个磁盘初始化失败。
-
driver的值必须是字面量字符串'ftp',不是变量、不是常量、不能带空格 - 确保
env('FTP_HOST')等调用返回非空字符串——可在 tinker 中执行dd(env('FTP_HOST'))验证 - 修改完
config/filesystems.php后,一定要运行php artisan config:clear,否则缓存旧配置,改了也白改
ignorePassiveAddress => true 是共享主机上传失败的救命配置
在 cPanel、SiteGround、Bluehost 等托管环境上传文件时,大概率卡在连接或超时。根本原因是 FTP 服务器返回的被动模式地址(PASV response)和客户端实际访问的 IP 不一致,导致数据通道建立失败。
- 显式设置
'passive' => false强制主动模式(需服务端开放 port 20) - 更通用的解法是加
'ignorePassiveAddress' => true,让 Flysystem 忽略 PASV 返回的 IP,复用控制连接的地址 - 如果仍失败,检查 vsftpd 配置中是否禁用了
pasv_promiscuous=YES或开了chroot_local_user=YES却没配好chroot_list
Storage::disk('ftp')->put() 的路径是相对于 root 的,不是绝对路径
root 配置项(如 public_html/storage/app/public/uploads)是 FTP 登录后的基准目录;put('avatar.jpg', $content) 实际写入位置是 root/avatar.jpg,不是服务器根目录下的 /avatar.jpg。
- 路径开头不要加
/,否则可能被解释为绝对路径,触发权限拒绝或静默失败 - 确保
root目录存在且用户有写权限——可先用 FTP 客户端手动创建并上传测试文件验证 - 上传二进制内容时,避免用
file_get_contents($request->file->path())读取再传,直接用$request->file->storeAs('subdir', 'name.jpg', 'ftp')更稳妥
最容易被忽略的是:FTP 驱动不校验凭证有效性,直到第一次 put() 或 exists() 才真正发起连接。所以 .env 里密码少打一个字符,或者 root 目录拼错,错误信息永远只显示 “Path cannot be empty” —— 实际上是连接失败后 getAdapter() 返回 null,后续路径操作自然为空。











