当前位置: 首页 > 工具软件 > XLSWriter > 使用案例 >

php xlswriter导出

严正诚
2023-12-01

复杂xls导出

可以使用xlswriter源码类:

https://github.com/mk-j/PHP_XLSXWriter/blob/master/xlsxwriter.class.php

实现帮助类:

<?php
require_once 'web/libraries/XLSXwriter.php';
class PHPExeclCore
{
    private $headerData = array();
    private $headerWidthSize = 0;
    private $headerHeightSize = 0;


    private $colDefalutFormat = 'string';// 列默认数据格式
    private $colDefalutWidth = '10';// 列默认宽度

    private $header = array();
    private $headerWidth = array();

    // 数据字段
    private $dataFields = array();

    // 标题行默认样式
    private $headerDefalutStyle = array(
        'halign' => 'center',//水平居中
        'valign' => 'center',//竖直居中
        'font-style' => 'bold',
        'font-size' => 12,
        'border' => 'top,bottom,left,right'
        //'fill'=>'#fff'// 背景色
        // 边框有点问题不能用
        // 高度也不行 用font-size撑开);
    );
    // 标题行处理数组
    /**
     * $headerRow = array(
     * array('content' =>['Merge Cells Example','','','',''],'style'=>[['halign'=>'center'],array(),array(),array(),array()]),
     * array('content' =>['姓名', '吃饭', '', '考勤', ''],'style'=>[['halign'=>'center','valign'=>'center'],['halign'=>'center'],[],['halign'=>'center'],[]]),
     * array('content' =>['', '上午', '下午', '上午', '下午'],'style'=>[[],['halign'=>'center'],[],[],[]]),
     * );
     */
    private $headerRow = array(0 => array('content' => array(), 'style' => array()));
    private $headerMargin = array();

    // 数据行
    private $dataRow = array();
    // 现在够用了,先不做了
    private $dataStyle = array();


    public function __construct()
    {
    }

    public function __get($name)
    {
        if (isset($this->$name)) {
            return $this->$name;
        } else {
            return null;
        }
        // TODO: Implement __get() method.
    }

    /**
     * 设置表头
     * @param array $head
     */
    public function setHeader($header = array())
    {
        $this->headerData = $header;
        // 设置表头尺寸
        $this->setHeaderSize($this->headerData);
        // 生成rows 和 margin 设置样式
        $this->dealHeader($this->headerData);
    }


    public function setData($data = array())
    {
        foreach ($data as $d) {
            $row = array();
            foreach ($this->dataFields as $field) {
                $value = isset($d[$field]) ? $d[$field] : '';
                $row[] = $value;
            }
            $this->dataRow[] = $row;
        }
    }


    /**
     * 导出
     * @param string $filename
     * @param string $sheet
     */
    public function writeToStdOut($filename = 'test', $sheet = 'Sheet1')
    {
        //$header = ['字段','标题','宽度','类型']
        $filename .= '.xlsx';
        $writer = new \XLSXWriter();
        $writer->writeSheetHeader($sheet, $this->header, $col_options = array('suppress_row' => true, 'widths' => $this->headerWidth));
        foreach ($this->headerRow as $row)
            $writer->writeSheetRow($sheet, $row['content'], $row['style']);
        foreach ($this->headerMargin as $margin) {
            $writer->markMergedCell($sheet, $margin['startRow'], $margin['startCol'], $margin['endRow'], $margin['endCol']);
        }
        foreach ($this->dataRow as $data)
            $writer->writeSheetRow($sheet, $data);
        header('Content-disposition: attachment; filename="' . \XLSXWriter::sanitize_filename($filename));
        header("Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        header('Content-Transfer-Encoding: binary');
        header('Cache-Control: must-revalidate');
        header('Pragma: public');
        $writer->writeToStdOut();
    }


    /**
     *  生成rows 和 margin 设置样式
     * @param $headerData
     */
    private function dealHeader($headerData)
    {

        $this->recursionSetHeaderRowsAndMargin($headerData, 0, 0, $this->headerDefalutStyle);
    }

    /**
     * 递归设置表头行数据,和合并表格数据源
     * @param $headerData
     * @param $row
     * @param $startCol
     * // 换个思路,填坑赋值
     */
    private function recursionSetHeaderRowsAndMargin($headerData, $row, $col, $defStyle = array())
    {
        $heightSize = $this->headerHeightSize;

        $startRow = $row;
        $startCol = $col;
        $content = array();//标题
        $style = array();//样式

        foreach ($headerData as $single) {
            $marginCol = isset($single['marginCol']) ? $single['marginCol'] : 1;
            // 合并
            // 是否有子节点
            $hasChildren = (isset($single['children']) && !empty($single['children'])) ? true : false;
            // 有子节点合并一行,没有子节点直接把剩下行都算上
            if ($hasChildren) {
                $marginRow = 1;
            } else {
                // 一共3行 当前第1行需要合并1,2两行
                $marginRow = $heightSize - $startRow;
            }


            $style = isset($single['style']) ? array_merge($defStyle, $single['style']) : $defStyle;
            // 如果不是合并一行一列就加入合并单元格的数组,同时每个合并的单元格都加样式(主要是方便边框)
            if ($marginCol != 1 || $marginRow != 1) {
                //0+2-1=1 合并了0,1两个单元格 end是1
                $endCol = $startCol + $marginCol - 1;
                // 当前第1行需要合并2两行,目标单元格行号1+2-1
                $endRow = $startRow + $marginRow - 1;
                $this->headerMargin[] = array(
                    'startRow' => $startRow,
                    'startCol' => $startCol,
                    'endRow' => $endRow,
                    'endCol' => $endCol);

                if (isset($style['border'])) {
                    $s = array('border' => $style['border']);
                    for ($r = 0; $r < $marginRow; $r++) {
                        $row = $startRow + $r;
                        for ($c = 0; $c < $marginCol; $c++) {
                            $col = $startCol + $c;
                            $this->setHeaderRowCell($row, $col, 'style', $s);
                        }
                    }
                }

            }
            $this->setHeaderRowCell($startRow, $startCol, 'style', $style);


            $content = isset($single['title']) ? $single['title'] : '';
            $this->setHeaderRowCell($startRow, $startCol, 'content', $content);


            //处理子节点
            if ($hasChildren) {
                $this->recursionSetHeaderRowsAndMargin($single['children'], $startRow + 1, $startCol, $style);
            }
            $startCol += $marginCol;

        }


    }

    //
    //
    /**
     * 设置表头单元格尺寸
     * 同事设置列的数据类型和宽度
     * @param $header
     */
    private function setHeaderSize(&$headerData)
    {

        list($w, $h) = $this->recursionCalSize($headerData);
        $this->headerWidthSize = $w;
        $this->headerHeightSize = $h;
        $this->setHeaderRow($w, $h);


    }

    /**
     * 初始化表头行,占坑
     * @param $w
     * @param $h
     */
    private function setHeaderRow($w, $h)
    {
        $data = array();
        $content = array();
        $style = array();
        while (true) {
            $w--;
            $content[] = '';
            $style[] = array();
            if ($w <= 0) break;
        }

        while (true) {
            $h--;
            $data[] = array('content' => $content, 'style' => $style);

            if ($h <= 0)
                break;
        }

        $this->headerRow = $data;
        unset($content);
        unset($style);
        unset($data);

    }

    /**
     * 修改表头行的数据
     * @param $col
     * @param $row
     * @param $filed
     * @param $value
     */
    private function setHeaderRowCell($row, $col, $key, $value)
    {

        if (isset($this->headerRow[$row][$key][$col])) {
            $this->headerRow[$row][$key][$col] = $value;
        } else {
            return false;
        }
    }

    /**
     *
     * @param $headerData
     * @return array
     */
    private function recursionCalSize(&$headerData)
    {
        $w = 0; // 根节点++
        $h = 0; // 是子类高度的最大值
        $childHeightArr = array();
        foreach ($headerData as &$single) {
            $singleH = 1;
            // 没有子节点设置为空数组

            if ((isset($single['children']) && !empty($single['children']))) {
                list($cw, $ch) = $this->recursionCalSize($single['children'], $h);
                $w += $cw;
                $singleH += $ch;
                $single['marginCol'] = $cw;

            } else {

                //设置表头需要要参数
                //字段类型
                $type = isset($single['format']) ? $single['format'] : $this->colDefalutFormat;
                // 字段宽度
                $width = isset($single['width']) ? $single['width'] : $this->colDefalutWidth;
                $this->header[] = $type;
                $this->headerWidth[] = $width;
                // data的键
                $field = isset($single['field']) ? $single['field'] : '';
                $this->dataFields[] = $field;

                $w++;
                $singleH = 1;
            }
            $childHeightArr[] = $singleH;
        }
        $h = max($childHeightArr);
        return array($w, $h);
    }
}

调用:

$headerConfig = [
    [
        'title' => 'test',
        'children' => [
            ['title' => '日期', 'field' => '日期'],
            ['title' => '总内购', 'field' => '总内购'],
        ]
    ],
];
$exportData = [
    ['日期' => '2021-08-08', '总内购' => '923'],
    ['日期' => '2021-08-08', '总内购' => '924'],
];

$tool = new PHPExeclCore();
$tool->setHeader($headerConfig);
$tool->setData($exportData);
$filename = date('_YmdHis');
$tool->writeToStdOut($filename);
exit();

参考:

https://www.jianshu.com/p/aba213453525

其他:https://blog.csdn.net/qq_41049126/article/details/89532403

 类似资料: