Laravel FTP功能本地运行正常 部署到服务器后无法读取文件
对接FTP服务器实现获取文件列表并转换为CSV格式的功能,本地localhost环境可按预期运行,项目迁移部署到线上服务器后该功能失效。
现有配置
config/filesystem.php中FTP配置如下:
'ftp' => [ 'driver' => 'ftp', 'host' => 'my.host.address.is', 'username' => 'ftpuser', 'password' => 'Ftppassword', 'passive' => false, // Optional FTP Settings... // 'port' => 21, // 'root' => '', // 'passive' => true, // 'ssl' => true, // 'timeout' => 30, ],
已尝试将配置项
passive修改为true,运行结果无变化。
业务代码
控制器代码如下:
namespace App\Http\Controllers; use Illuminate\Http\Request; use Illuminate\Support\Facades\Storage; use File; class CsvController extends Controller { public function index() { echo "atleast I am here right-/okayioio-12:26"; $fi=Storage::disk('ftp')->files('hello/xml/'); dd($fi); } }
运行表现
- 本地localhost环境:可正常返回文件列表

- 线上服务器环境:仅显示echo输出的调试内容,无文件列表返回

备注:两次执行的echo调试内容存在差异,但FTP文件读取部分的异常表现一致。
按优先级从高到低逐一验证:
验证线上服务器到FTP服务端的网络连通性
先登录线上服务器,用命令行直接测试FTP连接:# 测试21控制端口是否能通 telnet my.host.address.is 21 # 端口通的话直接用命令行ftp客户端登录测试 ftp my.host.address.is绝大多数云服务器默认会限制出方向端口,或者安全组、系统防火墙未放通FTP相关端口,本地网络无限制可以正常连接,服务器出网被拦截时,请求会卡在FTP连接阶段直到进程超时中断,就会出现只输出前面echo内容、后续无返回的现象。
确认PHP环境已安装FTP扩展
在线上服务器执行以下命令检查扩展:php -m | grep ftp无任何输出则说明未安装FTP扩展。Laravel的FTP驱动依赖PHP原生ftp扩展,本地环境默认安装、线上环境漏装的话,调用FTP相关方法时会直接抛出致命错误,如果线上环境关闭了debug、错误回显,就会出现请求中断、无后续输出的情况。
被动模式端口范围放通+增加超时配置
改passive=true仍无效的话,基本是被动模式的数据传输端口被拦截:FTP被动模式下,控制连接(21端口)建立后,数据传输会使用服务端分配的1024以上随机高端口,线上服务器出方向如果未放通对应端口范围,就会卡在文件列表读取阶段。
先修改配置增加超时时间,让错误能正常暴露:'ftp' => [ 'driver' => 'ftp', 'host' => 'my.host.address.is', 'username' => 'ftpuser', 'password' => 'Ftppassword', 'passive' => true, 'port' => 21, 'timeout' => 10, // 配置10秒超时,避免请求无限挂死 ],同时联系FTP服务端管理员确认被动模式端口范围,在线上服务器安全组、防火墙中放通对应出方向规则。
检查SELinux拦截规则
CentOS等默认开启SELinux的系统,会默认禁止Web进程(php-fpm/Apache)主动发起对外网络连接,可临时关闭SELinux验证:setenforce 0关闭后功能恢复正常的话,执行以下命令给Web进程分配网络访问权限即可,不要长期关闭SELinux:
setsebool -P httpd_can_network_connect 1校验路径大小写
本地如果是Windows、macOS环境,文件路径大小写不敏感;线上如果是Linux环境,路径严格区分大小写,确认FTP上的路径hello/xml/大小写完全匹配,不要出现Hello/XML这类大小写不一致的情况。
内容的提问来源于stack exchange,提问作者pyrogrammer

