dcat-x/laravel-xlswriter-export
Composer 安装命令:
composer require dcat-x/laravel-xlswriter-export
包简介
A high-performance Excel export package for Laravel based on xlswriter extension, supporting large datasets with low memory usage.
README 文档
README
Laravel Xlswriter Export
基于 xlswriter 扩展的 Laravel 高性能 Excel 导出工具
目录
特性
- 高性能 - 基于 C 扩展 xlswriter,导出速度快,内存占用低
- 大数据支持 - 支持 50 万+ 行数据导出,分块处理避免内存溢出
- 多数据源 - 支持 Query Builder、Collection、Array 等多种数据源
- 样式定制 - 支持单元格合并、自定义样式、冻结窗格等
- Swoole 兼容 - 完美支持 Swoole 协程环境
- 链式调用 - 优雅的 API 设计,支持链式配置
环境要求
- PHP >= 8.2
- Laravel >= 12.0
- xlswriter PHP 扩展
安装
1. 安装 xlswriter 扩展
在安装此包之前,需要先安装 xlswriter PHP 扩展。
Linux (推荐)
# 使用 PECL 安装 pecl install xlswriter # 或者从源码编译 git clone https://github.com/viest/php-ext-xlswriter.git cd php-ext-xlswriter phpize ./configure make && make install
添加到 php.ini:
extension=xlswriter.so
macOS
pecl install xlswriter
如果使用 Homebrew 安装的 PHP:
# 确保 pecl 可用
brew install php
pecl install xlswriter
Windows
- 访问 xlswriter releases
- 下载对应 PHP 版本的 DLL 文件
- 将 DLL 放入 PHP 的
ext目录 - 在
php.ini添加:extension=xlswriter
Docker
FROM php:8.2-fpm RUN pecl install xlswriter \ && docker-php-ext-enable xlswriter
安装后运行 php -m | grep xlswriter 或查看 phpinfo() 确认扩展已启用。
2. 安装扩展包
composer require dcat-x/laravel-xlswriter-export
快速开始
基础导出
创建一个继承 BaseExport 的导出类:
<?php namespace App\Exports; use Aoding9\Laravel\Xlswriter\Export\BaseExport; class UserExport extends BaseExport { public $header = [ ['column' => 'a', 'width' => 8, 'name' => 'ID'], ['column' => 'b', 'width' => 15, 'name' => '姓名'], ['column' => 'c', 'width' => 10, 'name' => '性别'], ['column' => 'd', 'width' => 20, 'name' => '创建时间'], ]; public $fileName = '用户导出'; public $tableTitle = '用户导出表'; public function eachRow($row) { return [ $row->id, $row->name, $row->gender, $row->created_at->toDateTimeString(), ]; } }
在控制器中使用:
use App\Exports\UserExport; use App\Models\User; public function export() { $query = User::query(); return UserExport::make($query)->export(); }
从 Collection/Array 导出
$data = [ ['id' => 1, 'name' => '张三', 'created_at' => now()->toDateString()], ['id' => 2, 'name' => '李四', 'created_at' => now()->toDateString()], ]; UserExport::make($data)->export();
或者重写 buildData() 方法实现分块处理:
public function buildData(?int $page = null, ?int $perPage = null) { // 从 API 或其他数据源获取数据 return collect($this->fetchDataFromApi($page, $perPage)); }
链式配置
UserExport::make($query) ->setMax(100000) // 最大导出 10 万行 ->setChunkSize(2000) // 每块 2000 条 ->useFreezePanes(true) // 启用冻结窗格 ->setFontFamily('宋体') // 设置字体 ->export();
配置选项
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
$fileName |
string | '文件名' | 导出文件名(不含扩展名) |
$tableTitle |
string | '表名' | 首行合并标题 |
$sheetName |
string | 'Sheet1' | 工作表名称 |
$useTitle |
bool | true | 是否显示首行标题 |
$useFreezePanes |
bool | false | 是否启用冻结窗格 |
$useGlobalStyle |
bool | true | 使用全局样式(末尾无边框) |
$fontFamily |
string | '微软雅黑' | 默认字体 |
$rowHeight |
int | 40 | 数据行高 |
$headerRowHeight |
int | 40 | 表头行高 |
$titleRowHeight |
int | 50 | 标题行高 |
$max |
int | 500000 | 最大导出行数 |
$chunkSize |
int | 5000 | 每块数据量 |
$debug |
bool | false | 启用调试日志 |
$useSwoole |
bool | false | Swoole 模式 |
$shouldDelete |
bool | true | 下载后删除临时文件 |
高级用法
单元格合并
行级合并(在每行插入后)
public function afterInsertEachRowInEachChunk($row) { // 每两行合并一次 B 列 if ($this->index % 2 === 1 && $this->getCurrentLine() < $this->completed + $this->startDataRow) { $range = "B{$this->getCurrentLine()}:B" . ($this->getCurrentLine() + 1); $nextRow = $this->getRowInChunkByIndex($this->index + 1); $value = $row->id . '---' . ($nextRow ? $nextRow->id : ''); $this->excel->mergeCells($range, $value, $this->getNormalStyle()); } }
静态合并(所有数据插入后)
public function mergeCellsAfterInsertData() { return [ ['range' => "A1:{$this->end}1", 'value' => $this->getTableTitle(), 'formatHandle' => $this->titleStyle], ['range' => "A2:A3", 'value' => '序号', 'formatHandle' => $this->headerStyle], ['range' => "B2:B3", 'value' => 'ID', 'formatHandle' => $this->headerStyle], ['range' => "C2:E2", 'value' => '基本信息', 'formatHandle' => $this->headerStyle], ]; }
自定义单元格样式
use Vtiful\Kernel\Format; public function insertCellHandle($currentLine, $column, $data, $format, $formatHandle) { // 为特定列设置高亮样式 if ($this->getColumn($column) === 'E' && $data instanceof Carbon) { if ($data->isToday()) { $formatHandle = $this->getHighlightStyle(); } $data = $data->toDateTimeString(); } return $this->excel->insertText($currentLine, $column, $data, $format, $formatHandle); } protected function getHighlightStyle() { return (new Format($this->fileHandle)) ->background(Format::COLOR_YELLOW) ->fontSize(10) ->bold() ->align(Format::FORMAT_ALIGN_CENTER, Format::FORMAT_ALIGN_VERTICAL_CENTER) ->border(Format::BORDER_THIN) ->toResource(); }
Swoole 支持
在 Swoole 环境中,不能使用 exit() 终止请求:
class UserExport extends BaseExport { public $useSwoole = true; // ... } // 控制器中必须 return public function export() { return UserExport::make($query)->export(); }
自定义数据源
class ApiExport extends BaseExport { protected string $apiUrl; public function __construct($apiUrl) { $this->apiUrl = $apiUrl; parent::__construct(null); // 传入 null,使用 buildDataFromOther } public function buildDataFromOther(?int $page = null, ?int $perPage = null) { $response = Http::get($this->apiUrl, [ 'page' => $page, 'per_page' => $perPage, ]); return collect($response->json('data')); } }
性能基准
导出 4 列数据表,使用分块查询的测试结果:
| 行数 | 分块大小 | 耗时 | 内存占用 |
|---|---|---|---|
| 10,000 | 2,000 | ~2s | ~15MB |
| 100,000 | 5,000 | ~10s | ~25MB |
| 500,000 | 50,000 | ~45s | ~50MB |
测试环境: PHP 8.2, Laravel 12, MySQL 8.0, 8GB RAM
性能优化建议
- 合理设置 chunkSize - 根据服务器内存调整,一般 2000-10000 为宜
- 使用 Query Builder - 避免一次性加载全部数据到内存
- 禁用不必要的样式 - 设置
$useGlobalStyle = false可略微提升性能 - 关联数据预加载 - 使用
with()预加载避免 N+1 查询
API 参考
构造方法
| 方法 | 说明 |
|---|---|
make($dataSource, $time = null) |
静态构造函数 |
__construct($dataSource, $time = null) |
构造函数,$time 用于调试计时 |
导出方法
| 方法 | 说明 |
|---|---|
export() |
执行导出并触发下载 |
store() |
仅保存文件,不触发下载 |
download($filePath = null) |
下载指定文件 |
配置方法
| 方法 | 说明 |
|---|---|
setMax(int $max) |
设置最大导出行数 |
setChunkSize(int $size) |
设置分块大小 |
setDebug(bool $debug) |
启用/禁用调试模式 |
setFontFamily(string $font) |
设置默认字体 |
setUseTitle(bool $use) |
是否显示首行标题 |
useFreezePanes(bool $use) |
启用/禁用冻结窗格 |
shouldDelete(bool $delete) |
下载后是否删除文件 |
setSheet(string $name) |
设置工作表名称 |
属性
| 属性 | 类型 | 说明 |
|---|---|---|
$index |
int | 当前数据行索引(从 1 开始) |
$currentLine |
int | 当前 Excel 行(从 0 开始) |
$completed |
int | 已导出的总行数 |
$chunkData |
Collection | 当前分块数据 |
$excel |
Excel | xlswriter 实例 |
$fileHandle |
resource | 文件句柄 |
$filePath |
string | 导出文件路径 |
辅助方法
| 方法 | 说明 |
|---|---|
getCurrentLine() |
获取当前 Excel 行号(从 1 开始) |
getIndex() |
获取当前数据索引 |
getColumn(int $index) |
列索引转字母(0 → A) |
getColumnIndexByName(string $name) |
字母转列索引(A → 0) |
getCellName(int $line, int $col) |
获取单元格名称(如 A1) |
getRowInChunkByIndex(int $index) |
从当前分块获取指定索引的行数据 |
生命周期钩子
| 方法 | 调用时机 |
|---|---|
beforeInsertData() |
数据插入前 |
afterInsertEachRowInEachChunk($row) |
每行插入后 |
afterInsertData() |
所有数据插入后 |
beforeOutput() |
文件输出前 |
afterStore() |
文件保存后 |
常见问题
Q: 大数字显示为科学计数法怎么办?
A: 将数字转为字符串:
public function eachRow($row) { return [ $row->id, (string) $row->phone, // 转为字符串 (string) $row->id_card, // 身份证号等长数字 ]; }
Q: 如何导出带公式的单元格?
A: 使用 xlswriter 的 insertFormula 方法:
public function insertCellHandle($currentLine, $column, $data, $format, $formatHandle) { if ($this->getColumn($column) === 'F') { return $this->excel->insertFormula($currentLine, $column, '=SUM(D' . ($currentLine + 1) . ':E' . ($currentLine + 1) . ')'); } return parent::insertCellHandle($currentLine, $column, $data, $format, $formatHandle); }
Q: 如何设置列宽自适应?
A: xlswriter 不支持真正的自适应,需要预估宽度:
public $header = [ ['column' => 'a', 'width' => 10, 'name' => 'ID'], // 短内容 ['column' => 'b', 'width' => 30, 'name' => '描述'], // 长内容 ['column' => 'c', 'width' => 20, 'name' => '创建时间'], // 日期时间 ];
Q: 导出时内存不足怎么办?
A:
- 减小
$chunkSize值 - 确保使用 Query Builder 而非 Collection
- 增加 PHP 内存限制(临时方案)
UserExport::make($query) ->setChunkSize(1000) // 减小分块 ->setMax(100000) // 限制最大行数 ->export();
Q: 如何导出多个 Sheet?
A: 当前版本暂不支持多 Sheet,可以考虑导出多个文件后合并。
故障排查
扩展未加载
Class 'Vtiful\Kernel\Excel' not found
解决: 检查 xlswriter 扩展是否正确安装:
php -m | grep xlswriter
文件无法写入
Unable to open file for writing
解决: 检查临时目录权限:
// 查看临时目录 echo sys_get_temp_dir(); // 确保目录可写 chmod 777 /tmp
内存溢出
Allowed memory size of xxx bytes exhausted
解决:
- 减小
$chunkSize - 使用 Query Builder 替代 Collection
- 临时增加内存限制:
ini_set('memory_limit', '512M')
Swoole 环境报错
exit() not allowed in Swoole
解决: 设置 $useSwoole = true 并在控制器中 return 导出结果。
贡献指南
欢迎贡献代码!请查看 CONTRIBUTING.md 了解详情。
本地开发
# 克隆仓库 git clone https://github.com/dcat-x/laravel-xlswriter-export.git cd laravel-xlswriter-export # 安装依赖 composer install # 运行测试 composer test # 代码格式化 composer format # 静态分析 composer analyse # 运行所有检查 composer check
许可证
MIT 许可证。详情请参阅 LICENSE 文件。
dcat-x/laravel-xlswriter-export 适用场景与选型建议
dcat-x/laravel-xlswriter-export 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 9 次下载、GitHub Stars 达 0, 最近一次更新时间为 2026 年 01 月 13 日, 在 PHP 生态内属于活跃度较高的组件。
它主要适用于以下技术方向: 「excel」 「spreadsheet」 「xlsx」 「export」 「laravel」 「swoole」 等业务场景。在实际项目中,围绕这些方向常见需要落地的问题包括:接口对接、性能调优、并发安全、与既有框架(Laravel / ThinkPHP / Yii / Webman 等)的兼容适配,以及生产环境的日志埋点与稳定性保障。
我们在过去多个企业项目中使用过 dcat-x/laravel-xlswriter-export 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。
基于 dcat-x/laravel-xlswriter-export 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。
线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。
承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。
与 dcat-x/laravel-xlswriter-export 相关的其它包
同方向 / 同关键字的高下载量 PHP Composer 包推荐,方便对比选型:
This Symfony bundle integrates PhpSpreadsheet into Symfony using Twig.
PHPExcel - OpenXML - Read, Create and Write Spreadsheet documents in PHP - Spreadsheet engine
PHPExcel - OpenXML - Read, Create and Write Spreadsheet documents in PHP - Spreadsheet engine
Yii2 export extension
PHP Excel Library
PHPExcel - OpenXML - Read, Create and Write Spreadsheet documents in PHP - Spreadsheet engine
统计信息
- 总下载量: 9
- 月度下载量: 0
- 日度下载量: 0
- 收藏数: 0
- 点击次数: 26
- 依赖项目数: 0
- 推荐数: 0
其他信息
- 授权协议: MIT
- 更新时间: 2026-01-13