You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Laravel 8项目中Zip文件SFTP上传失败且无法下载的问题排查及解决方案

Laravel 8 SFTP上传Zip失败+下载功能失效问题分析与解决方案

我来帮你梳理下问题根源,以及对应的修复方案:

原代码的核心问题

  1. 上传时机错误:你把SFTP上传代码放在了unlink($filename)之后,这时候本地Zip文件已经被删除了,自然无法上传;同时$disk->put($filename, $zip)传递的是ZipArchive对象,而非文件的实际内容,这也会导致上传失败。
  2. 权限配置不足:原SFTP配置中的permPublic设为0766,可能导致服务器端没有足够权限写入文件。
  3. 重复构建存储配置:每次用Storage::build重新创建SFTP连接,不如直接复用filesystems.php中已配置好的sftp磁盘,更简洁可靠。

修复步骤

步骤1:调整SFTP权限配置

修改config/filesystems.php中的sftp配置,将permPublic改为0775,确保服务器端有足够的读写权限:

'sftp' => [
    'driver' => 'sftp',
    'host' => 'myserver.it',
    'port' => 2222,
    'username' => 'myusername',
    'password' => 'mypassword',
    'privateKey' => 'myprivateRSAKey',
    'root' => '/',
    'timeout' => 10,
    'visibility' => 'public',
    'permPublic' => 0775, // 调整为775权限
]

步骤2:重构业务逻辑与SFTP上传方法

修改后的creaSpedizione方法

核心调整:把SFTP上传移到文件删除之前,确保文件存在时执行上传;同时传递文件内容而非Zip对象。

public function creaSpedizione(Request $request) {
    try {
        set_time_limit(-1);
        
        if ($request->input('sap') != 'all') {
            $today = date("Y-m-d");
            $date = Carbon::createFromFormat('Y-m-d', $today)->addDays(1);
            $sap = Sap::select('id', 'sap')->find($request->input('sap'));
            
            // 从数据库获取待处理数据
            $racc = Raccomandata::select('*')
                ->where([
                    ['isGenerated', '=', '0'],
                    ['idCliente', '=', $request->input('sap')]
                ])
                ->whereDate('daSpedire', '=', $date)
                ->get()
                ->groupBy(['idCommessa', 'lotto'])
                ->toArray();
            
            // 生成Zip文件
            $zip = new \ZipArchive();
            $data = date("Ymd");
            $sapMercurio = 'char10';
            $filename = $sapMercurio . '_' . $sap->sap . '_' . $data . '_001.cpx';
            $xmlname = $sapMercurio . '_' . $sap->sap . '_' . $data . '_001_I.xml';
            
            $this->prenota($filename, $sap->id);
            
            if ($zip->open($filename, \ZipArchive::CREATE) !== TRUE) {
                exit("无法打开文件 <$filename>\n");
            }
            
            // 将生成的XML添加到Zip包
            $zip->addFromString($xmlname, \App::call('App\Http\Controllers\ExportFileController@exportXML', ['racc' => $racc]));
            $zip->close();
            
            // 先执行SFTP上传(文件存在时操作)
            if (file_exists($filename)) {
                $this->storeSFTP($filename);
                
                // 执行用户下载逻辑
                header('Content-Type: application/zip');
                header('Content-Length: ' . filesize($filename));
                header('Content-disposition: attachment; filename=' . $filename);
                readfile($filename);
                
                // 下载完成后删除本地文件
                unlink($filename);
            }
        }
    } catch (\Exception $e) {
        Log::channel('custom_log')->info('用户 ' . Auth::user() . ' 无法创建发货单 COD:' . $request->input('codice_prenotazione') . ' 错误:' . $e);
        return redirect()->back()->with('error', '无法创建发货单号: ' . $request->input('codice_prenotazione'));
    }
}

新增私有SFTP上传方法

抽离上传逻辑,提升代码复用性和可维护性:

private function storeSFTP($filename) {
    try {
        // 读取本地Zip文件的实际内容
        $fileContent = file_get_contents($filename);
        // 上传到SFTP服务器的指定目录(对应服务器路径:/folder1/folder2/subfolder1)
        Storage::disk('sftp')->put('folder1/folder2/subfolder1/' . $filename, $fileContent);
        
        Log::channel('custom_log')->info('SFTP 成功: 用户 ' . Auth::user() . ' 已成功上传文件: ' . $filename . ' via SFTP!');
    } catch (\Exception $e) {
        Log::channel('custom_log')->info('SFTP 错误: 用户 ' . Auth::user() . ' 无法上传文件: ' . $filename . ' via SFTP! 错误信息:' . $e);
        return redirect()->back()->with('error', 'SFTP通信错误,若问题持续请联系管理员');
    }
}

关键修复点说明

  • 上传时机:确保在本地文件未被删除前执行SFTP上传,保证文件存在可读取
  • 文件内容传递:使用file_get_contents读取文件二进制内容,而非直接传递ZipArchive对象,符合Laravel Storage的put方法要求
  • 复用配置磁盘:直接调用Storage::disk('sftp')使用已配置的SFTP连接,避免重复构建配置的冗余和潜在错误
  • 权限调整0775权限确保SFTP服务器端能正常写入和访问上传的文件

内容的提问来源于stack exchange,提问作者64Bit1990

火山引擎 最新活动