文章详情

短信预约信息系统项目管理师 报名、考试、查分时间动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

PHP大数据xlswriter导入导出(最优数据化)

admin

admin

2022-05-31 11:08

关注

本文介绍基于PHP扩展xlswriter的Vtiful\Kernel\Excel类可以支持无限层级的复杂表头导出!后续也可能会持续更新优化

一、准备xlswriter扩展

1、windows系统:

到PECL网站下载符合自己本地PHP环境的ddl文件下载地址https://pecl.php.net/package/xlswriter,并复制到PHP的扩展目录ext文件夹下,修改php.ini文件,

加上这行

extension=xlswriter


2、Linux系统:

使用命令安装

pecl install xlswriter


php配置文件添加

extension = xlswriter.so


重启:php nginx  查看PHP安装xlswriter拓展

二、封装导出类文件(重点来了)

<?php

namespace 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;        public function __construct()    {        // 文件默认输出地址
        $path = base_path().'/public/uploads/excel';
        $config = [            'path' => $path        ];

        $this->xlsObj = (new \Vtiful\Kernel\Excel($config));    }        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()));    }        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);    }        public function setData(array $data)    {        foreach ($data as $row => $datum) {            foreach ($datum as $column => $value) {
                $this->fileObject->insertText($row + $this->maxHeight, $column, $value);            }        }    }        public function addSheet(string $sheetName)    {
        $this->fileObject->addSheet($sheetName);    }        public function output()    {        return $this->fileObject->output();    }        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();    }        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;    }        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;    }        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}");        }    }        private function getColumn(int $num)    {        return Excel::stringFromColumnIndex($num);    }}


三、使用示例

代码如下

        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); // 输出到浏览器    }


导出效果


阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯