youvision / think-excel
基于 PhpSpreadsheet 的 ThinkPHP 8 数据库导出 Excel 组件
v1.0.0
2026-11-07 09:09 UTC
Requires
- php: >=8.1
- phpoffice/phpspreadsheet: ^2.0 || ^3.0 || ^4.0
- topthink/framework: ^8.0
Requires (Dev)
- phpunit/phpunit: ^10.0 || ^11.0
Suggests
None
Provides
None
Conflicts
None
Replaces
None
README
面向 ThinkPHP 的开源工程索引:组件、框架、服务与发布工具,按能力组织,持续整理。 仓库地址:https://github.com/indiboy-create/ThinkPHP-PanGu/ 在线站点:https://indiboy-create.github.io/ThinkPHP-PanGu/
youvision/think-excel
基于 PhpSpreadsheet 的 ThinkPHP 8 数据库导出 Excel 组件。
- 仅支持 ThinkPHP 8
- 支持 Model、查询构造器、数组、生成器和回调作为数据源
- 数据库按块读取,避免一次性加载全部数据
- 支持表头样式、列宽、冻结表头、自动筛选、字段映射、日期格式化
- 支持 Xlsx、Xls、Csv、Ods、Html 写入器
- 支持浏览器直接下载
安装
composer require youvision/think-excel
安装后执行服务发现命令(可选,用于注册 app('excel') 和合并配置):
php think service:discover
不执行服务发现也可以直接使用
Excel入口类,项目中的config/excel.php会被 ThinkPHP 正常加载。
快速开始
Model 导出(推荐)
use app\model\User; use Youvision\ThinkExcel\Excel; public function export() { return Excel::model(User::class, function ($query) { $query->where('status', 1)->order('id', 'desc'); }) ->columns([ 'id' => ['title' => '编号', 'width' => 10, 'align' => 'center'], 'username' => '用户名', 'email' => ['title' => '邮箱', 'width' => 30], 'status' => ['title' => '状态', 'map' => [0 => '禁用', 1 => '正常']], 'balance' => ['title' => '余额', 'type' => 'number', 'number_format' => '#,##0.00'], 'created_at' => ['title' => '创建时间', 'type' => 'datetime'], ]) ->sheet('用户列表') ->download('用户列表.xlsx'); }
导出到文件
$path = Excel::model(User::class) ->columns(['id' => '编号', 'username' => '用户名']) ->toFile('export/user.xlsx'); // 或 Excel::model(User::class)->columns([...])->save('export/user.xlsx');
查询构造器
use think\facade\Db; $query = Db::name('user')->where('status', 1); return Excel::query($query) ->columns(['id' => '编号', 'username' => '用户名']) ->download('user.xlsx');
数组或生成器
Excel::data([ ['id' => 1, 'name' => '张三'], ['id' => 2, 'name' => '李四'], ])->columns(['id' => '编号', 'name' => '姓名'])->toFile('export/data.xlsx'); // 生成器同样支持,适合自定义大数据源 $generator = (function () { foreach ($rows as $row) { yield $row; } })(); Excel::data($generator)->toFile('export/data.xlsx');
自动推断列
不调用 columns() 时,组件会使用第一行数据的键名作为表头和字段名:
Excel::data($data)->toFile('export/data.xlsx');
自动推断依赖第一行数据;如果字段需要改名、映射或固定类型,请显式调用
columns()。
列定义
->columns([ // 简单写法:字段 => 标题 'username' => '用户名', // 完整写法 'id' => [ 'title' => '编号', 'type' => 'number', // text、number、date、datetime、time、bool、json 'width' => 12, // 固定列宽,不设置则自动计算 'align' => 'center', // left、center、right 'wrap' => true, // 自动换行 'number_format' => '0.00', // Excel 数字格式 'date_format' => 'Y-m-d', // date、datetime、time 类型使用 'map' => [1 => '是', 0 => '否'], 'value' => fn ($row, $rowIndex) => '自定义值', ], // 数组列表形式 ['field' => 'profile.avatar', 'title' => '头像'], // 关联字段:Model 中请先 with 预加载,避免 N+1 查询 'profile.nickname' => '昵称', ])
字段取值
- 普通字段直接写字段名,如
username - 关联字段使用
profile.nickname value回调参数为($row, $rowIndex),$row是当前 Model 或数组map用于状态、字典值转换type = text会强制按文本写入,适合手机号、身份证号、带前导零的编号- 超长数字字符串会自动按文本写入,避免 Excel 精度丢失
分批导出
数据库数据源默认按 chunk_size 分块读取:
Excel::make(['chunk_size' => 2000]) ->model(User::class) ->columns([...]) ->toFile('export/user.xlsx');
默认使用主键排序分块。如果查询包含自定义排序、分组或去重,组件会自动切换为分页模式。也可以显式指定分块字段:
Excel::model(User::class) ->chunkColumn('id') ->columns([...]) ->toFile('export/user.xlsx');
写入器
Excel::model(User::class) ->writer('Csv') ->columns([...]) ->toFile('export/user.csv');
支持:
| 写入器 | 后缀 | 说明 |
|---|---|---|
Xlsx |
xlsx | 默认,推荐 |
Xls |
xls | 旧版 Excel,单表最多 65536 行 |
Csv |
csv | UTF-8 BOM,默认防止公式注入 |
Ods |
ods | OpenDocument 表格 |
Html |
html | HTML 表格 |
配置
组件默认配置位于 config/excel.php,包含完整中文注释。需要覆盖默认值时,在项目中创建 config/excel.php:
<?php return [ 'chunk_size' => 2000, 'freeze_header' => true, 'auto_filter' => true, 'csv' => [ 'bom' => true, ], ];
配置会与组件默认值递归合并,只需填写需要修改的项。
主要配置项:
| 配置项 | 默认值 | 说明 |
|---|---|---|
writer |
Xlsx |
默认写入器 |
sheet_title |
Sheet1 |
默认工作表名称 |
filename |
export |
默认下载文件名 |
chunk_size |
1000 |
数据库分块读取条数 |
chunk_column |
null |
分块排序字段 |
freeze_header |
true |
是否冻结表头 |
auto_filter |
true |
是否启用自动筛选 |
header |
见配置文件 | 表头样式 |
body |
见配置文件 | 数据行样式 |
column |
见配置文件 | 列宽计算 |
text_digits |
15 |
纯数字字符串强制文本的长度阈值 |
max_text_length |
32767 |
单元格最大字符数 |
escape_formula |
true |
CSV 公式注入防护 |
temp_path |
runtime_path('excel') |
下载临时目录 |
直接下载
return Excel::model(User::class) ->columns([...]) ->download('用户列表.xlsx');
download() 返回 ThinkPHP 的 think\response\File 响应,可直接在控制器中返回。
注意事项
- PhpSpreadsheet 会将工作簿保存在内存中,导出超大数据时请适当调大
memory_limit,并优先使用chunk_size控制单次数据库读取量。 - CSV 默认对
=、+、-、@开头的文本添加单引号,防止公式注入;如确实需要原始内容,可设置escape_formula为false。 - Excel 单元格最多 32767 个字符,超出部分会按
max_text_length截断。 - Model 关联字段会触发关联查询,建议在查询回调中使用
with()预加载。
测试
php -d extension=pdo_sqlite -d extension=sqlite3 vendor/phpunit/phpunit/phpunit --configuration phpunit.xml
License
MIT