Laravel SFTP驱动下载大文件报错Error reading channel data (7)
问题描述
使用Laravel + Flysystem SFTP驱动下载大文件(耗时超1分钟)时,抛出错误:Error reading channel data (7)。已尝试以下操作但无效:
- 调整SFTP配置中的
timeout和useAgent参数 - 提前初始化流对象、改用
get()方法加载文件到内存 - 在Sail容器中挂载添加
ServerAliveInterval的ssh_config
使用scp或FileZilla可正常下载目标文件,依赖版本如下:
laravel/framework@v11.2.0laravel/sail@v1.29.1league/filesystem@3.27.0league/flysystem-sftp-v3@3.26.0
核心代码:
Storage::disk('local')->writeStream( "sftp/{$localFilename}", Storage::disk('sftp')->readStream($remoteFilePath) );
解决方案
1. 在SFTP配置中添加SSH存活保活参数
PHP的ssh2扩展默认不读取系统ssh_config,需在Laravel的文件系统配置中直接指定SSH会话的保活选项:
修改config/filesystems.php的sftp磁盘配置:
'sftp' => [ 'driver' => 'sftp', 'host' => env('SFTP_HOST'), 'username' => env('SFTP_USERNAME'), 'password' => env('SFTP_PASSWORD'), 'timeout' => 300, // 整体超时设为5分钟(根据文件大小调整) 'connectTimeout' => 60, // 连接超时设为1分钟 'config' => [ 'ssh2.server_alive_interval' => 30, // 每30秒发送一次保活包 'ssh2.server_alive_count_max' => 10, // 连续10次无响应才断开连接 ], ],
2. 分块处理流读写
避免直接传递完整流导致连接长时间无交互,手动分块读取写入:
$remoteStream = Storage::disk('sftp')->readStream($remoteFilePath); $localPath = "sftp/{$localFilename}"; $localStream = Storage::disk('local')->writeStream($localPath, fopen('php://temp', 'w+b')); $chunkSize = 8192; // 每次读取8KB块,可根据服务器带宽调整 while (!feof($remoteStream)) { $chunk = fread($remoteStream, $chunkSize); fwrite($localStream, $chunk); fflush($localStream); // 立即写入磁盘,避免缓冲区积压 } // 关闭流释放资源 fclose($remoteStream); fclose($localStream);
3. 手动创建SSH会话并配置参数
如果上述配置仍不生效,可手动创建SSH会话并传入Flysystem适配器,精准控制连接参数:
在AppServiceProvider的boot方法中添加自定义磁盘扩展:
use Illuminate\Support\Facades\Storage; use League\Flysystem\Filesystem; use League\Flysystem\PhpseclibV3\SftpAdapter; use League\Flysystem\PhpseclibV3\SftpConnectionProvider; use Illuminate\Filesystem\FilesystemAdapter; public function boot() { Storage::extend('sftp_custom', function ($app, $config) { // 创建SSH连接并设置保活参数 $session = ssh2_connect( $config['host'], $config['port'] ?? 22, [ 'timeout' => 300, 'ssh2.server_alive_interval' => 30, 'ssh2.server_alive_count_max' => 10, ] ); ssh2_auth_password($session, $config['username'], $config['password']); // 创建SFTP适配器 $adapter = new SftpAdapter( new SftpConnectionProvider(fn () => $session), $config['root'] ?? '' ); return new FilesystemAdapter( new Filesystem($adapter), $adapter ); }); }
然后在.env中配置sftp_custom的参数,代码中使用Storage::disk('sftp_custom')进行文件操作。
4. 升级PHP ssh2扩展版本
旧版本的ssh2扩展可能存在大文件传输的bug,在Sail容器中执行以下命令升级:
pecl install ssh2-1.4.1 # 安装最新稳定版
内容的提问来源于stack exchange,提问作者Winter
相关产品推荐
相关产品推荐

