PHP如何使用xlswriter进行大数据的导入导出?(详解)

 4504

PHP如何使用xlswriter进行大数据导入导出?下面本篇文章给大家介绍一下PHP大数据xlswriter导入导出(最优数据化)的方法,希望对大家有所帮助!


PHP如何使用xlswriter进行大数据的导入导出?(详解)


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

一、准备xlswriter扩展

1、windows系统:

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

加上这行

  1. extension=xlswriter

2、Linux系统:

使用命令安装

  1. pecl install xlswriter

php配置文件添加

  1. extension = xlswriter.so

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


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

  1. <?php
  2.  
  3. namespace App\Services;
  4.  
  5. use Vtiful\Kernel\Excel;
  6.  
  7. class MultiFloorXlsWriterService
  8. {
  9.     // 默认宽度
  10.     private $defaultWidth = 16;
  11.     // 默认导出格式
  12.     private $exportType = '.xlsx';
  13.     // 表头最大层级
  14.     private $maxHeight = 1;
  15.     // 文件名
  16.     private $fileName = null;
  17.  
  18.     private $xlsObj;
  19.     private $fileObject;
  20.     private $format;
  21.  
  22.     /**
  23.      * MultiFloorXlsWriterService constructor.
  24.      * @throws \App\Exceptions\ApiException
  25.      */
  26.     public function __construct()
  27.     {
  28.         // 文件默认输出地址
  29.         $path = base_path().'/public/uploads/excel';
  30.         $config = [
  31.             'path' => $path
  32.         ];
  33.  
  34.         $this->xlsObj = (new \Vtiful\Kernel\Excel($config));
  35.     }
  36.  
  37.     /**
  38.      * 设置文件名
  39.      * @param string $fileName
  40.      * @param string $sheetName
  41.      * @author LWW
  42.      */
  43.     public function setFileName(string $fileName = '', string $sheetName = 'Sheet1')
  44.     {
  45.         $fileName = empty($fileName) ? (string)time() : $fileName;
  46.         $fileName .= $this->exportType;
  47.  
  48.         $this->fileName = $fileName;
  49.  
  50.         $this->fileObject = $this->xlsObj->fileName($fileName, $sheetName);
  51.         $this->format = (new \Vtiful\Kernel\Format($this->fileObject->getHandle()));
  52.     }
  53.  
  54.     /**
  55.      * 设置表头
  56.      * @param array $header
  57.      * @param bool $filter
  58.      * @throws \Exception
  59.      * @author LWW
  60.      */
  61.     public function setHeader(array $header, bool $filter = false)
  62.     {
  63.         if (empty($header)) {
  64.             throw new \Exception('表头数据不能为空');
  65.         }
  66.  
  67.         if (is_null($this->fileName)) {
  68.             self::setFileName(time());
  69.         }
  70.  
  71.         // 获取单元格合并需要的信息
  72.         $colManage = self::setHeaderNeedManage($header);
  73.  
  74.         // 完善单元格合并信息
  75.         $colManage = self::completeColMerge($colManage);
  76.  
  77.         // 合并单元格
  78.         self::queryMergeColumn($colManage, $filter);
  79.  
  80.     }
  81.  
  82.     /**
  83.      * 填充文件数据
  84.      * @param array $data
  85.      * @author LWW
  86.      */
  87.     public function setData(array $data)
  88.     {
  89.         foreach ($data as $row => $datum) {
  90.             foreach ($datum as $column => $value) {
  91.                 $this->fileObject->insertText($row + $this->maxHeight, $column, $value);
  92.             }
  93.         }
  94.     }
  95.  
  96.     /**
  97.      * 添加Sheet
  98.      * @param string $sheetName
  99.      * @author LWW
  100.      */
  101.     public function addSheet(string $sheetName)
  102.     {
  103.         $this->fileObject->addSheet($sheetName);
  104.     }
  105.  
  106.     /**
  107.      * 保存文件至服务器
  108.      * @return mixed
  109.      * @author LWW
  110.      */
  111.     public function output()
  112.     {
  113.         return $this->fileObject->output();
  114.     }
  115.  
  116.     /**
  117.      * 输出到浏览器
  118.      * @param string $filePath
  119.      * @throws \Exception
  120.      * @author LWW
  121.      */
  122.     public function excelDownload(string $filePath)
  123.     {
  124.         $fileName = $this->fileName;
  125.         $userBrowser = $_SERVER['HTTP_USER_AGENT'];
  126.         if (preg_match('/MSIE/i', $userBrowser)) {
  127.             $fileName = urlencode($fileName);
  128.         } else {
  129.             $fileName = iconv('UTF-8', 'GBK//IGNORE', $fileName);
  130.         }
  131.  
  132.         header("Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
  133.         header('Content-Disposition: attachment;filename="' . $fileName . '"');
  134.         header('Content-Length: ' . filesize($filePath));
  135.         header('Content-Transfer-Encoding: binary');
  136.         header('Cache-Control: must-revalidate');
  137.         header('Cache-Control: max-age=0');
  138.         header('Pragma: public');
  139.  
  140.         if (ob_get_contents()) {
  141.             ob_clean();
  142.         }
  143.  
  144.         flush();
  145.  
  146.         if (copy($filePath, 'php://output') === false) {
  147.             throw new \Exception($filePath . '地址出问题了');
  148.         }
  149.  
  150.         // 删除本地文件
  151.         @unlink($filePath);
  152.  
  153.         exit();
  154.     }
  155.  
  156.     /**
  157.      * 组装单元格合并需要的信息
  158.      * @param array $header
  159.      * @param int $col
  160.      * @param int $cursor
  161.      * @param array $colManage
  162.      * @param null $parent
  163.      * @param array $parentList
  164.      * @return array
  165.      * @throws \Exception
  166.      * @author LWW
  167.      */
  168.     private function setHeaderNeedManage(array $header,int $col = 1,int &$cursor = 0,array &$colManage = [], $parent = null,array $parentList = [])
  169.     {
  170.         foreach ($header as $head) {
  171.             if (empty($head['title'])) {
  172.                 throw new \Exception('表头数据格式有误');
  173.             }
  174.  
  175.             if (is_null($parent)) {
  176.                 // 循环初始化
  177.                 $parentList = [];
  178.                 $col = 1;
  179.             } else {
  180.                 // 递归进入,高度和父级集合通过相同父级条件从已有数组中获取,避免递归增加与实际数据不符
  181.                 foreach ($colManage as $value) {
  182.                     if ($value['parent'] == $parent) {
  183.                         $parentList = $value['parentList'];
  184.                         $col = $value['height'];
  185.                         break;
  186.                     }
  187.                 }
  188.             }
  189.  
  190.             // 单元格标识
  191.             $column = $this->getColumn($cursor) . $col;
  192.  
  193.             // 组装单元格需要的各种信息
  194.             $colManage[$column] = [
  195.                 'title'      => $head['title'],      // 标题
  196.                 'cursor'     => $cursor,             // 游标
  197.                 'cursorEnd'  => $cursor,             // 结束游标
  198.                 'height'     => $col,                // 高度
  199.                 'width'      => $this->defaultWidth, // 宽度
  200.                 'mergeStart' => $column,             // 合并开始标识
  201.                 'hMergeEnd'  => $column,             // 横向合并结束标识
  202.                 'zMergeEnd'  => $column,             // 纵向合并结束标识
  203.                 'parent'     => $parent,             // 父级标识
  204.                 'parentList' => $parentList,         // 父级集合
  205.             ];
  206.  
  207.             if (isset($head['children']) && !empty($head['children']) && is_array($head['children'])) {
  208.                 // 有下级,高度加一
  209.                 $col += 1;
  210.                 // 当前标识加入父级集合
  211.                 $parentList[] = $column;
  212.  
  213.                 $this->setHeaderNeedManage($head['children'], $col, $cursor, $colManage, $column, $parentList);
  214.             } else {
  215.                 // 没有下级,游标加一
  216.                 $cursor += 1;
  217.             }
  218.         }
  219.  
  220.         return $colManage;
  221.     }
  222.  
  223.     /**
  224.      * 完善单元格合并信息
  225.      * @param array $colManage
  226.      * @return mixed
  227.      * @author LWW
  228.      */
  229.     private function completeColMerge(array $colManage)
  230.     {
  231.         $this->maxHeight = max(array_column($colManage, 'height'));
  232.         $parentManage = array_column($colManage, 'parent');
  233.  
  234.         foreach ($colManage as $index => $value) {
  235.             // 设置横向合并结束范围:存在父级集合,把所有父级的横向合并结束范围设置为当前单元格
  236.             if (!is_null($value['parent']) && !empty($value['parentList'])) {
  237.                 foreach ($value['parentList'] as $parent) {
  238.                     $colManage[$parent]['hMergeEnd'] = self::getColumn($value['cursor']) . $colManage[$parent]['height'];
  239.                     $colManage[$parent]['cursorEnd'] = $value['cursor'];
  240.                 }
  241.             }
  242.  
  243.             // 设置纵向合并结束范围:当前高度小于最大高度 且 不存在以当前单元格标识作为父级的项
  244.             $checkChildren = array_search($index, $parentManage);
  245.             if ($value['height'] < $this->maxHeight && !$checkChildren) {
  246.                 $colManage[$index]['zMergeEnd'] = self::getColumn($value['cursor']) . $this->maxHeight;
  247.             }
  248.         }
  249.  
  250.         return $colManage;
  251.     }
  252.  
  253.     /**
  254.      * 合并单元格
  255.      * @param array $colManage
  256.      * @param bool $filter
  257.      * @author LWW
  258.      */
  259.     private function queryMergeColumn(array $colManage,bool $filter)
  260.     {
  261.         foreach ($colManage as $value) {
  262.             $this->fileObject->mergeCells("{$value['mergeStart']}:{$value['zMergeEnd']}", $value['title']);
  263.             $this->fileObject->mergeCells("{$value['mergeStart']}:{$value['hMergeEnd']}", $value['title']);
  264.  
  265.             // 设置单元格需要的宽度
  266.             if ($value['cursor'] != $value['cursorEnd']) {
  267.                 $value['width'] = ($value['cursorEnd'] - $value['cursor'] + 1) * $this->defaultWidth;
  268.             }
  269.  
  270.             // 设置列单元格样式
  271.             $toColumnStart = self::getColumn($value['cursor']);
  272.             $toColumnEnd = self::getColumn($value['cursorEnd']);
  273.             $this->fileObject->setColumn("{$toColumnStart}:{$toColumnEnd}", $value['width']);
  274.         }
  275.  
  276.         // 是否开启过滤选项
  277.         if ($filter) {
  278.             // 获取最后的单元格标识
  279.             $filterEndColumn = self::getColumn(end($colManage)['cursorEnd']) . $this->maxHeight;
  280.             $this->fileObject->autoFilter("A1:{$filterEndColumn}");
  281.         }
  282.     }
  283.  
  284.     /**
  285.      * 获取单元格列标识
  286.      * @param int $num
  287.      * @return string
  288.      * @author LWW
  289.      */
  290.     private function getColumn(int $num)
  291.     {
  292.         return Excel::stringFromColumnIndex($num);
  293.     }
  294. }


三、使用示例

代码如下

  1. /**
  2.  * 导出测试
  3.  * @author LWW
  4.  */
  5. public function export()
  6. {
  7.     $header = [
  8.         [
  9.             'title' => '一级表头1',
  10.             'children' => [
  11.                 [
  12.                     'title' => '二级表头1',
  13.                 ],
  14.                 [
  15.                     'title' => '二级表头2',
  16.                 ],
  17.                 [
  18.                     'title' => '二级表头3',
  19.                 ],
  20.             ]
  21.         ],
  22.         [
  23.             'title' => '一级表头2'
  24.         ],
  25.         [
  26.             'title' => '一级表头3',
  27.             'children' => [
  28.                 [
  29.                     'title' => '二级表头1',
  30.                     'children' => [
  31.                         [
  32.                             'title' => '三级表头1',
  33.                         ],
  34.                         [
  35.                             'title' => '三级表头2',
  36.                         ],
  37.                     ]
  38.                 ],
  39.                 [
  40.                     'title' => '二级表头2',
  41.                 ],
  42.                 [
  43.                     'title' => '二级表头3',
  44.                     'children' => [
  45.                         [
  46.                             'title' => '三级表头1',
  47.                             'children' => [
  48.                                 [
  49.                                     'title' => '四级表头1',
  50.                                     'children' => [
  51.                                         [
  52.                                             'title' => '五级表头1'
  53.                                         ],
  54.                                         [
  55.                                             'title' => '五级表头2'
  56.                                         ]
  57.                                     ]
  58.                                 ],
  59.                                 [
  60.                                     'title' => '四级表头2'
  61.                                 ]
  62.                             ]
  63.                         ],
  64.                         [
  65.                             'title' => '三级表头2',
  66.                         ],
  67.                     ]
  68.                 ]
  69.             ]
  70.         ],
  71.         [
  72.             'title' => '一级表头4',
  73.         ],
  74.         [
  75.             'title' => '一级表头5',
  76.         ],
  77.     ];
  78.     $data= [];
  79.     // header头规则 title表示列标题,children表示子列,没有子列children可不写或为空
  80.     for ($i = 0; $i < 100; $i++) {
  81.         $data[] = [
  82.             '这是第'. $i .'行测试',
  83.             '这是第'. $i .'行测试',
  84.             '这是第'. $i .'行测试',
  85.             '这是第'. $i .'行测试',
  86.             '这是第'. $i .'行测试',
  87.             '这是第'. $i .'行测试',
  88.             '这是第'. $i .'行测试',
  89.             '这是第'. $i .'行测试',
  90.             '这是第'. $i .'行测试',
  91.             '这是第'. $i .'行测试',
  92.             '这是第'. $i .'行测试',
  93.             '这是第'. $i .'行测试',
  94.             '这是第'. $i .'行测试',
  95.         ];
  96.     }
  97.     $fileName = '很厉害的文件导出类';
  98.     $xlsWriterServer = new MultiFloorXlsWriterService();
  99.     $xlsWriterServer->setFileName($fileName, '这是Sheet1别名');
  100.     $xlsWriterServer->setHeader($header, true);
  101.     $xlsWriterServer->setData($data);
  102.  
  103.     $xlsWriterServer->addSheet('这是Sheet2别名');
  104.     $xlsWriterServer->setHeader($header);   //这里可以使用新的header
  105.     $xlsWriterServer->setData($data);       // 这里也可以根据新的header定义数据格式
  106.  
  107.     $filePath = $xlsWriterServer->output();     // 保存到服务器
  108.     $xlsWriterServer->excelDownload($filePath); // 输出到浏览器
  109. }

导出效果


PHP如何使用xlswriter进行大数据的导入导出?(详解)

本文网址:https://www.zztuku.com/detail-12585.html
站长图库 - PHP如何使用xlswriter进行大数据的导入导出?(详解)
申明:本文转载于《learnku》,如有侵犯,请 联系我们 删除。

评论(0)条

您还没有登录,请 登录 后发表评论!

提示:请勿发布广告垃圾评论,否则封号处理!!

    编辑推荐