You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将Laravel Excel导出文件打包为ZIP后实现定时下载

定时Excel导出打包ZIP实现方案

原有逻辑说明

原有定时任务类exportExcelBasedOnID运行流程:

  • 任务启动时更新任务状态为处理中
  • 读取任务参数生成对应xlsx格式Excel文件
  • 将xlsx存入指定存储目录,更新任务状态为完成,记录xlsx文件名供后续下载

改造后完整实现代码

1. 修改定时任务导出类,集成ZIP打包逻辑

核心改动点:

  • 生成xlsx文件后,先将文件存入students子目录
  • 初始化ZipArchive创建ZIP包,将xlsx文件加入包内的students目录
  • 打包完成后更新任务记录的产出文件为ZIP包,不再返回xlsx路径
<?php

use ZipArchive;
use Carbon\Carbon;

class exportExcelBasedOnID {
    public function __construct(ScheduleJob $scheduleJob) {
        $scheduleJob->processed_at = Carbon::now();
        $scheduleJob->processing = true;
        $scheduleJob->exception = null;
        $scheduleJob->save();

        $this->exportExcels($scheduleJob);
    }

    private function exportExcels(ScheduleJob $scheduleJob) {
        $school = $scheduleJob->school;
        $payload = unserialize($scheduleJob->payload);
        $id = $payload['id'];
        $requestUser = User::where('id', $scheduleJob->user_id)->first();
        $students = Excels::where('id', $id);
        $locale = array_key_exists('locale', $payload) ? $payload['locale'] : \App::getLocale();

        // 原有生成$final Excel对象的逻辑保持不变
        // a bunch of code to create the file with format called $final

        // 定义存储根路径
        $storageBase = storage_path('app/public/EXCEL/'.$school->school_code);
        // 定义xlsx存放的students目录,不存在则递归创建
        $excelDir = $storageBase.'/students/';
        if (!is_dir($excelDir)) {
            mkdir($excelDir, 0755, true);
        }
        // 保存xlsx到students目录
        $excelFileName = $name.'.xlsx';
        $final->store('xlsx', $excelDir);
        $excelFullPath = $excelDir.$excelFileName;

        // 初始化ZIP打包
        $zip = new ZipArchive;
        // ZIP包拼接任务ID避免重名覆盖
        $zipFileName = 'students_'.$scheduleJob->id.'.zip';
        $zipFullPath = $storageBase.'/'.$zipFileName;
        // 创建并覆盖同名ZIP文件
        if ($zip->open($zipFullPath, ZipArchive::CREATE | ZipArchive::OVERWRITE) === true) {
            // 在ZIP内创建students文件夹
            $zip->addEmptyDir('students');
            // 将生成的xlsx加入ZIP内的students目录
            $zip->addFile($excelFullPath, 'students/'.$excelFileName);
            // 关闭ZIP句柄完成写入
            $zip->close();

            // 可选:ZIP生成成功后删除原始xlsx节省存储空间
            // unlink($excelFullPath);

            // 更新任务状态与产出文件
            $payload['payload'] = $zipFileName;
            $scheduleJob->payload = serialize($payload);
            $scheduleJob->processed_at = Carbon::now();
            $scheduleJob->exception = null;
            $scheduleJob->processing = false;
            $scheduleJob->save();
        } else {
            // 打包失败记录异常
            $scheduleJob->processing = false;
            $scheduleJob->exception = 'ZIP压缩包创建失败';
            $scheduleJob->save();
            throw new \Exception('ZIP压缩包创建失败,路径:'.$zipFullPath);
        }
    }
}

2. 调整下载接口逻辑,适配ZIP包下载

原有export_schedule_zip方法不需要在定时任务中调用,仅作为用户触发下载的接口使用,修改为读取对应任务生成的ZIP包返回即可:

<?php

public function export_schedule_zip(School $school, Request $request)
{
    // 根据自身业务逻辑获取对应定时任务记录,拿到存储的ZIP文件名
    $scheduleJob = ScheduleJob::where('id', $request->job_id)->firstOrFail();
    $payload = unserialize($scheduleJob->payload);
    $zipFileName = $payload['payload'];
    $zipFullPath = storage_path('app/public/EXCEL/'.$school->school_code.'/'.$zipFileName);

    if (!file_exists($zipFullPath)) {
        abort(404, '导出文件不存在');
    }

    return response()->download($zipFullPath);
}

注意事项

  • 提前确保storage/app/public/EXCEL/目录权限为0755,运行PHP进程的用户有读写权限,避免创建目录、写入文件失败
  • 如果需要在ZIP中放入多个Excel文件,只需重复调用$zip->addFile()将文件加入ZIP内的students目录即可
  • 定时任务运行在CLI环境下,不要使用相对路径读写文件,统一用storage_path()、public_path()等助手函数获取绝对路径

内容的提问来源于stack exchange,提问作者apkr x

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 23:12:31