PHP-CodeIgniter实现临时Excel生成及批量打包Zip下载方案问询
实现可行性及操作指南
可行性结论
该需求完全可以基于PHP + CodeIgniter技术栈实现,核心依赖PHP原生ZipArchive扩展和Excel生成类库即可完成,无需接入额外外部服务。
前置准备
- 确保PHP环境已开启
ZipArchive扩展(绝大多数PHP集成环境默认已开启,可通过phpinfo()确认) - 引入
PhpSpreadsheet作为Excel生成工具(性能优于老旧的PHPExcel,支持大文件写入优化,可通过Composer直接安装到CodeIgniter项目中) - 在CodeIgniter项目根目录创建两个权限为755的可写目录:
temp_excel/用于存储临时分片Excel文件,temp_zip/用于存储最终打包的Zip压缩包
核心实现步骤
步骤1:分批查询数据库,避免一次性读取全量数据
通过CodeIgniter查询构造器的分页能力,按预设的单文件行数分批拉取数据,避免内存溢出:
// 先统计总数据量 $totalRows = $this->db->count_all('你的业务数据表名'); // 单Excel文件存储行数,可根据服务器配置调整,示例为5万行 $perPage = 50000; $totalShard = ceil($totalRows / $perPage); // 存储所有生成的临时Excel路径 $excelShardList = [];
步骤2:循环生成分片Excel临时文件
每拉取一批数据就生成一个独立的Excel文件,生成完成后立即清理内存,避免内存占用持续升高:
// 加载PhpSpreadsheet自动加载文件(Composer安装场景) require_once APPPATH . 'vendor/autoload.php'; use PhpOffice\PhpSpreadsheet\Spreadsheet; use PhpOffice\PhpSpreadsheet\Writer\Xlsx; for ($i = 0; $i < $totalShard; $i++) { // 分页拉取数据 $offset = $i * $perPage; $currentData = $this->db->limit($perPage, $offset)->get('你的业务数据表名')->result_array(); $spreadsheet = new Spreadsheet(); $activeSheet = $spreadsheet->getActiveSheet(); $startRow = 1; // 仅第一个分片写入表头,不需要的话可以去掉该逻辑 if ($i == 0) { $activeSheet->setCellValue('A1', '字段1名称'); $activeSheet->setCellValue('B1', '字段2名称'); // 补充其余表头字段 $startRow = 2; } // 写入当前分片数据 foreach ($currentData as $index => $row) { $currentRow = $startRow + $index; $activeSheet->setCellValue('A'.$currentRow, $row['字段1']); $activeSheet->setCellValue('B'.$currentRow, $row['字段2']); // 补充其余字段写入逻辑 } // 保存临时Excel文件 $tempExcelPath = FCPATH . 'temp_excel/数据分片_'.($i+1).'.xlsx'; $writer = new Xlsx($spreadsheet); $writer->save($tempExcelPath); $excelShardList[] = $tempExcelPath; // 手动清理当前分片的内存占用 $spreadsheet->disconnectWorksheets(); unset($spreadsheet, $currentData, $writer); }
步骤3:打包所有分片Excel为Zip压缩包
所有分片生成完成后,将所有临时Excel文件打包为一个Zip压缩包:
$zipFileName = '全量数据导出_'.date('YmdHis').'.zip'; $zipFilePath = FCPATH . 'temp_zip/'.$zipFileName; $zip = new \ZipArchive(); if ($zip->open($zipFilePath, \ZipArchive::CREATE | \ZipArchive::OVERWRITE) === true) { foreach ($excelShardList as $excelPath) { $zip->addFile($excelPath, basename($excelPath)); } $zip->close(); }
步骤4:触发用户下载并清理临时文件
输出压缩包给用户下载,完成后删除所有临时文件,避免占用服务器存储空间:
// 设置下载响应头 header('Content-Type: application/zip'); header('Content-Disposition: attachment; filename='.$zipFileName); header('Content-Length: '.filesize($zipFilePath)); readfile($zipFilePath); // 清理所有临时文件 foreach ($excelShardList as $excelPath) { unlink($excelPath); } unlink($zipFilePath); exit;
优化建议
- 如果数据量超过千万级,建议将导出任务改为异步队列处理:用户触发导出后先返回待处理提示,后台静默生成压缩包后再通知用户下载,避免前端请求超时
- 可根据服务器配置调整单Excel的存储行数,配置较低的服务器可将
$perPage调整为20000-30000,进一步降低单批次处理压力 - 查询数据库时可使用
unbuffered_row遍历结果集,进一步降低内存开销 - 导出逻辑中避免加载CodeIgniter不必要的类库,减少额外内存占用
内容的提问来源于stack exchange,提问作者Parikshit Bharadwaj
相关产品推荐
相关产品推荐

