记录一次使用thinkphp使用PhpSpreadsheet扩展导出数据,解决身份证号码等信息科学计数法问题处理
PhpSpreadsheet官网
PhpSpreadsheet安装
composer require phpoffice/phpspreadsheet
使用composer安装时一定要下载php对应的版本,下载之前使用php -v检查当前php版本
简单使用
<?php
require 'vendor/autoload.php';use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
use PhpOffice\PhpSpreadsheet\Style\NumberFormat;// 创建Spreadsheet对象
$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();// 动态表头
$headers = ['ID', '姓名', '性别', '职业', '新增字段', '新增字段2', '新增字段3', '新增字段4', '新增字段5', '新增字段6', '新增字段7', '新增字段8', '新增字段9', '新增字段10', '新增字段11', '新增字段12', '新增字段13', '新增字段14', '新增字段15', '新增字段16', '新增字段17', '新增字段18', '新增字段19', '新增字段20', '新增字段21', '新增字段22', '新增字段23', '新增字段24', '新增字段25', '新增字段26', '新增字段27', '新增字段28', '新增字段29', '新增字段30'];// 动态数据
$data = [[1, '李云龙', '男', '军人', '1427141544485854854485', '字段1', '字段2', '字段3', '字段4', '字段5', '字段6', '字段7', '字段8', '字段9', '字段10', '字段11', '字段12', '字段13', '字段14', '字段15', '字段16', '字段17', '字段18', '字段19', '字段20', '字段21', '字段22', '字段23', '字段24', '字段25', '字段26', '字段27', '字段28', '字段29', '字段30'],[2, '苏乞儿', '男', '乞丐', '值2', '字段1', '字段2', '字段3', '字段4', '字段5', '字段6', '字段7', '字段8', '字段9', '字段10', '字段11', '字段12', '字段13', '字段14', '字段15', '字段16', '字段17', '字段18', '字段19', '字段20', '字段21', '字段22', '字段23', '字段24', '字段25', '字段26', '字段27', '字段28', '字段29', '字段30'],[3, '周星驰', '男', '导演', '值3', '字段1', '字段2', '字段3', '字段4', '字段5', '字段6', '字段7', '字段8', '字段9', '字段10', '字段11', '字段12', '字段13', '字段14', '字段15', '字段16', '字段17', '字段18', '字段19', '字段20', '字段21', '字段22', '字段23', '字段24', '字段25', '字段26', '字段27', '字段28', '字段29', '字段30'],[4, '林允儿', '女', '演员', '值4', '字段1', '字段2', '字段3', '字段4', '字段5', '字段6', '字段7', '字段8', '字段9', '字段10', '字段11', '字段12', '字段13', '字段14', '字段15', '字段16', '字段17', '字段18', '字段19', '字段20', '字段21', '字段22', '字段23', '字段24', '字段25', '字段26', '字段27', '字段28', '字段29', '字段30'],
];// 设置表头和数据
$allData = array_merge([$headers], $data);
$sheet->fromArray($allData, null, 'A1');// 设置表头样式
$styleArray = ['alignment' => ['horizontal' => 'center','vertical' => 'center',],'font' => ['name' => '宋体',// 'bold' => true,// 'size' => 22]
];$headerRange = 'A1:' . chr(ord('A') + count($headers) - 1) . '1';
$sheet->getStyle($headerRange)->getNumberFormat() // 先获取NumberFormat对象->setFormatCode(NumberFormat::FORMAT_TEXT)->applyFromArray($styleArray);// 保存文件
$writer = new Xlsx($spreadsheet);
$writer->save('dynamic_example.xlsx');?>
在thinkphp项目中使用
// 如果将该扩展直接安装到thinkphp6项目中提示找不到Class 'PhpOffice\\PhpSpreadsheet\\Spreadsheet' not found,将该扩展放置项目根目录的extend文件夹中(参考下图),随后打开下行代码
// require_once app()->getRootPath() . 'extend/PhpSpreadsheet/autoload.php';
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
use PhpOffice\PhpSpreadsheet\Style\NumberFormat;
use PhpOffice\PhpSpreadsheet\IOFactory;
use PhpOffice\PhpSpreadsheet\Cell\Coordinate;
use PhpOffice\PhpSpreadsheet\Cell\DataType;public function export_data($data){// 获取所有要查询的字段和名称$header_arr = [];$fields_arr = [];foreach($data['export_data'] as $key=>$val){array_push($header_arr, $val['label']);array_push($fields_arr, $val['field']);} // 文件存储目录$public = app()->getRootPath().'public/';$path = 'uploads/export_data/';if(!file_exists($path)){mkdir($path, 0777);}// 文件名$res_file = $file_name . '_all.xlsx';$finalFile = $public . $path . $res_file;$currentRow = 1; // 当前写入行$spreadsheet = new Spreadsheet();$sheet = $spreadsheet->getActiveSheet();// 3. 计算列范围 - 安全方法$lastColumn = Coordinate::stringFromColumnIndex(count($header_arr));$headerRange = 'A:' . $lastColumn;// $sheet->setTitle('Sheet1');// 如果是第一次运行,创建新文件并写入头部if (!file_exists($finalFile)) {$spreadsheet = new Spreadsheet();$sheet = $spreadsheet->getActiveSheet();$sheet->getStyle($headerRange)->getNumberFormat()->setFormatCode(NumberFormat::FORMAT_TEXT);// 写入头部$sheet->fromArray([$header_arr], null, 'A1');$currentRow = 2;// 设置表头样式$styleArray = ['alignment' => ['horizontal' => 'center','vertical' => 'center',],// 'font' => [// 'name' => '宋体',// 'bold' => true,// 'size' => 22// ]];// $headerRange = 'A1:' . chr(ord('A') + count($header_arr) - 1) . '1';$sheet->getStyle($headerRange)->applyFromArray($styleArray);// 保存文件$writer = new Xlsx($spreadsheet);$writer->save($finalFile);// echo "创建新文件并写入头部\n";}// 分批导出并追加数据$totalBatches = 3; // 假设总共3批for ($batch = 1; $batch <= $totalBatches; $batch++) {// 加载现有文件$reader = IOFactory::createReader('Xlsx');$spreadsheet = $reader->load($finalFile);$sheet = $spreadsheet->getActiveSheet();// 获取当前最后一行$currentRow = $sheet->getHighestRow() + 1;// 生成测试数据 - 实际应用中从数据库获取$data = [];$perBatch = 10000;$start = ($batch - 1) * $perBatch + 1;$end = $batch * $perBatch;for ($i = $start; $i <= $end; $i++) {$data[] = [$i,"姓名{$i}",($i % 2) ? '男' : '女',"职业{$i}"];}// 追加数据$stringContent = array_map(function($row) use ($sheet, $currentRow) {return array_map(function($cell) {return (string)$cell; // 只返回值,不返回类型}, $row);}, $data);// 先设置数据$sheet->fromArray($stringContent, null, "A{$currentRow}");// 部分列强制文本格式$forceTextColumns = ['CI', 'AQ', 'AH']; // 需要强制文本的列for ($row = $currentRow; $row <= $highestRow; $row++) {foreach ($forceTextColumns as $col) {$cell = $sheet->getCell($col.$row);$cell->setValueExplicit($cell->getValue(),DataType::TYPE_STRING);$sheet->getStyle($col.$row)->getNumberFormat()->setFormatCode('@');}}// 保存文件$writer = new Xlsx($spreadsheet);$writer->save($finalFile);echo "批次 {$batch} 数据已追加到 {$finalFile} (行 {$currentRow}-" . ($currentRow + count($data) - 1) . ")\n";}echo "所有数据已导出到 {$finalFile}\n";
}