使用PHP-Xlswriter导出数据库表至excel

ops/2024/10/21 22:42:31/
php">    /*** 导出测试* @author LWW*/public function export(){$header = [['title' => '一级表头1','children' => [['title' => '二级表头1',],['title' => '二级表头2',],['title' => '二级表头3',],]],['title' => '一级表头2'],['title' => '一级表头3','children' => [['title' => '二级表头1','children' => [['title' => '三级表头1',],['title' => '三级表头2',],]],['title' => '二级表头2',],['title' => '二级表头3','children' => [['title' => '三级表头1','children' => [['title' => '四级表头1','children' => [['title' => '五级表头1'],['title' => '五级表头2']]],['title' => '四级表头2']]],['title' => '三级表头2',],]]]],['title' => '一级表头4',],['title' => '一级表头5',],];$data= [];// header头规则 title表示列标题,children表示子列,没有子列children可不写或为空for ($i = 0; $i < 100; $i++) {$data[] = ['这是第'. $i .'行测试','这是第'. $i .'行测试','这是第'. $i .'行测试','这是第'. $i .'行测试','这是第'. $i .'行测试','这是第'. $i .'行测试','这是第'. $i .'行测试','这是第'. $i .'行测试','这是第'. $i .'行测试','这是第'. $i .'行测试','这是第'. $i .'行测试','这是第'. $i .'行测试','这是第'. $i .'行测试',];}$fileName = '很厉害的文件导出类';$xlsWriterServer = new MultiFloorXlsWriterService();$xlsWriterServer->setFileName($fileName, '这是Sheet1别名');$xlsWriterServer->setHeader($header, true);$xlsWriterServer->setData($data);$xlsWriterServer->addSheet('这是Sheet2别名');$xlsWriterServer->setHeader($header);   //这里可以使用新的header$xlsWriterServer->setData($data);       // 这里也可以根据新的header定义数据格式$filePath = $xlsWriterServer->output();     // 保存到服务器$xlsWriterServer->excelDownload($filePath); // 输出到浏览器}<?phpnamespace App\Services;use Vtiful\Kernel\Excel;class MultiFloorXlsWriterService
{// 默认宽度private $defaultWidth = 16;// 默认导出格式private $exportType = '.xlsx';// 表头最大层级private $maxHeight = 1;// 文件名private $fileName = null;private $xlsObj;private $fileObject;private $format;/*** MultiFloorXlsWriterService constructor.* @throws \App\Exceptions\ApiException*/public function __construct(){// 文件默认输出地址$path = base_path().'/public/uploads/excel';$config = ['path' => $path];$this->xlsObj = (new \Vtiful\Kernel\Excel($config));}/*** 设置文件名* @param string $fileName* @param string $sheetName* @author LWW*/public function setFileName(string $fileName = '', string $sheetName = 'Sheet1'){$fileName = empty($fileName) ? (string)time() : $fileName;$fileName .= $this->exportType;$this->fileName = $fileName;$this->fileObject = $this->xlsObj->fileName($fileName, $sheetName);$this->format = (new \Vtiful\Kernel\Format($this->fileObject->getHandle()));}/*** 设置表头* @param array $header* @param bool $filter* @throws \Exception* @author LWW*/public function setHeader(array $header, bool $filter = false){if (empty($header)) {throw new \Exception('表头数据不能为空');}if (is_null($this->fileName)) {self::setFileName(time());}// 获取单元格合并需要的信息$colManage = self::setHeaderNeedManage($header);// 完善单元格合并信息$colManage = self::completeColMerge($colManage);// 合并单元格self::queryMergeColumn($colManage, $filter);}/*** 填充文件数据* @param array $data* @author LWW*/public function setData(array $data){foreach ($data as $row => $datum) {foreach ($datum as $column => $value) {$this->fileObject->insertText($row + $this->maxHeight, $column, $value);}}}/*** 添加Sheet* @param string $sheetName* @author LWW*/public function addSheet(string $sheetName){$this->fileObject->addSheet($sheetName);}/*** 保存文件至服务器* @return mixed* @author LWW*/public function output(){return $this->fileObject->output();}/*** 输出到浏览器* @param string $filePath* @throws \Exception* @author LWW*/public function excelDownload(string $filePath){$fileName = $this->fileName;$userBrowser = $_SERVER['HTTP_USER_AGENT'];if (preg_match('/MSIE/i', $userBrowser)) {$fileName = urlencode($fileName);} else {$fileName = iconv('UTF-8', 'GBK//IGNORE', $fileName);}header("Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");header('Content-Disposition: attachment;filename="' . $fileName . '"');header('Content-Length: ' . filesize($filePath));header('Content-Transfer-Encoding: binary');header('Cache-Control: must-revalidate');header('Cache-Control: max-age=0');header('Pragma: public');if (ob_get_contents()) {ob_clean();}flush();if (copy($filePath, 'php://output') === false) {throw new \Exception($filePath . '地址出问题了');}// 删除本地文件@unlink($filePath);exit();}/*** 组装单元格合并需要的信息* @param array $header* @param int $col* @param int $cursor* @param array $colManage* @param null $parent* @param array $parentList* @return array* @throws \Exception* @author LWW*/private function setHeaderNeedManage(array $header,int $col = 1,int &$cursor = 0,array &$colManage = [], $parent = null,array $parentList = []){foreach ($header as $head) {if (empty($head['title'])) {throw new \Exception('表头数据格式有误');}if (is_null($parent)) {// 循环初始化$parentList = [];$col = 1;} else {// 递归进入,高度和父级集合通过相同父级条件从已有数组中获取,避免递归增加与实际数据不符foreach ($colManage as $value) {if ($value['parent'] == $parent) {$parentList = $value['parentList'];$col = $value['height'];break;}}}// 单元格标识$column = $this->getColumn($cursor) . $col;// 组装单元格需要的各种信息$colManage[$column] = ['title'      => $head['title'],      // 标题'cursor'     => $cursor,             // 游标'cursorEnd'  => $cursor,             // 结束游标'height'     => $col,                // 高度'width'      => $this->defaultWidth, // 宽度'mergeStart' => $column,             // 合并开始标识'hMergeEnd'  => $column,             // 横向合并结束标识'zMergeEnd'  => $column,             // 纵向合并结束标识'parent'     => $parent,             // 父级标识'parentList' => $parentList,         // 父级集合];if (isset($head['children']) && !empty($head['children']) && is_array($head['children'])) {// 有下级,高度加一$col += 1;// 当前标识加入父级集合$parentList[] = $column;$this->setHeaderNeedManage($head['children'], $col, $cursor, $colManage, $column, $parentList);} else {// 没有下级,游标加一$cursor += 1;}}return $colManage;}/*** 完善单元格合并信息* @param array $colManage* @return mixed* @author LWW*/private function completeColMerge(array $colManage){$this->maxHeight = max(array_column($colManage, 'height'));$parentManage = array_column($colManage, 'parent');foreach ($colManage as $index => $value) {// 设置横向合并结束范围:存在父级集合,把所有父级的横向合并结束范围设置为当前单元格if (!is_null($value['parent']) && !empty($value['parentList'])) {foreach ($value['parentList'] as $parent) {$colManage[$parent]['hMergeEnd'] = self::getColumn($value['cursor']) . $colManage[$parent]['height'];$colManage[$parent]['cursorEnd'] = $value['cursor'];}}// 设置纵向合并结束范围:当前高度小于最大高度 且 不存在以当前单元格标识作为父级的项$checkChildren = array_search($index, $parentManage);if ($value['height'] < $this->maxHeight && !$checkChildren) {$colManage[$index]['zMergeEnd'] = self::getColumn($value['cursor']) . $this->maxHeight;}}return $colManage;}/*** 合并单元格* @param array $colManage* @param bool $filter* @author LWW*/private function queryMergeColumn(array $colManage,bool $filter){foreach ($colManage as $value) {$this->fileObject->mergeCells("{$value['mergeStart']}:{$value['zMergeEnd']}", $value['title']);$this->fileObject->mergeCells("{$value['mergeStart']}:{$value['hMergeEnd']}", $value['title']);// 设置单元格需要的宽度if ($value['cursor'] != $value['cursorEnd']) {$value['width'] = ($value['cursorEnd'] - $value['cursor'] + 1) * $this->defaultWidth;}// 设置列单元格样式$toColumnStart = self::getColumn($value['cursor']);$toColumnEnd = self::getColumn($value['cursorEnd']);$this->fileObject->setColumn("{$toColumnStart}:{$toColumnEnd}", $value['width']);}// 是否开启过滤选项if ($filter) {// 获取最后的单元格标识$filterEndColumn = self::getColumn(end($colManage)['cursorEnd']) . $this->maxHeight;$this->fileObject->autoFilter("A1:{$filterEndColumn}");}}/*** 获取单元格列标识* @param int $num* @return string* @author LWW*/private function getColumn(int $num){return Excel::stringFromColumnIndex($num);}
}

http://www.ppmy.cn/ops/127394.html

相关文章

用户的访问行为是否影响网站在搜索引擎上的排名呢?

用户访问数据是否影响网站在搜索引擎上的排名呢&#xff1f; 大家好&#xff0c;我是SEO专家&#xff08;林汉文&#xff09;&#xff0c;在搜索引擎优化&#xff08;SEO&#xff09;的讨论中&#xff0c;用户访问数据是否会直接影响网站在搜索引擎结果页面&#xff08;SERP&a…

JVM篇(学习预热 - JVM正式展开 - (实战课程学习总结))(持续更新迭代)

目录 感觉也看了这么多&#xff0c;说一些乱七八糟的内容&#xff0c;完全没有实质的收获&#xff0c;那么现在让我们正式来预热下JVM 吧&#xff1f; 一、程序的执行方式 二、为什么使用 JVM 三、字节码和机器码的区别 四、JDK、JRE与JVM的关系 五、OracleJDK和OpenJDK …

typescript 中封装一个 class 来解析接口响应数据

在TypeScript中&#xff0c;封装一个类来解析接口响应数据是一个常见的做法&#xff0c;它允许你将与接口响应相关的逻辑封装在一个可复用的单元中。下面是一个示例&#xff0c;展示了如何定义一个TypeScript类来解析一个假设的API接口响应数据。 首先&#xff0c;我们定义一个…

如何使用Rancher管理K8S集群

目录 1 Rancher介绍 1.1 Rancher简介 1.2 Rancher和k8s的区别 1.3 Rancher使用案例 2安装rancher 2.1 初始化实验环境 2.2 安装Rancher 2.3 登录Rancher平台 3 通过Rancher管理已存在的k8s集群 4 通过Rancher仪表盘管理k8s集群&#xff1a;部署tomcat服务 文档中…

【React】在 React 项目中引入图片

import import React from react; import myImage from ./path/to/image.jpg;function MyComponent() {return <img src{myImage} alt"description" />; }require&#xff08;虽然现在比较少用&#xff09; import React from react;function MyComponent() …

生成式人工智能如何帮助我们更有效地传达信息

来源&#xff1a;Graves, C. (2023, February 16). Generative AI can help you tailor messaging to specific audiences. Harvard Business Review. https://hbr.org/2023/02/generative-ai-can-help-you-tailor-messaging-to-specific-audiences 想象一下&#xff0c;你是一…

编辑器资源管理器

解释 EditorResMgr 是一个用于在 Unity 编辑器中加载资源的管理器。它通过 Unity 编辑器的 API (AssetDatabase) 进行资源加载&#xff0c;但仅在开发和编辑模式下可用&#xff0c;不能在最终发布的游戏中使用。这种工具通常用来在开发过程中快速加载编辑器中的资源&#xff0…

Tauri(读音:踹你)开发简介:1.创建和运行第一个app

桌面app与web app之间的界限越来越模糊&#xff0c;以前可能说基于web编写的app性能不好&#xff0c;但是现在我们来看&#xff0c;不管钉钉还是vscode&#xff0c;都是采用了Electron框架&#xff0c;以web模式开发出来的。 提到Electron相信许多程序员都不陌生&#xff0c;它…