phpexcel导出文档

2020-06-03
<?php
use PHPExcel;
class PhpOperateExcel
{
    public $excel;
    public $excel_sheet;
    public $file_type;
    public function __construsct($optaer = 'create',$file_type ='Excel2007',$path = null)
    {
        if ($optaer == 'load') {
            $path = iconv('UTF-8','GB2312',$path);
            if (!empty($path) && file_exists($path)) {
                $file_type = \PHPExcel_IOFactory::identify($path);//获取文本类型
                if ($file_type) {
                    $excel_io = \PHPExcel_IOFactory::createReader($file_type);
                    $this->excel = $excel_io->load($path);
                } else {
                    throw '请上传正确的excel文件';
                }
                $this->file_type = $file_type;
            } else {
                throw '请输入正确的文件路径';
            }
        } else {
            $this->excel = new PHPExcel();
            $this->file_type = $file_type;
        }
    }

    /**
     * @description: 在表格中插入数据
     * @param xls_contents array 表数据数组 [0 => ['xu'=>'1','val1'=>'123'],1 => ['xu'=>'2','val1'=>'456']]
     * @param content_column 数据插入的初始行
     * @param xls_header array 表头数据数组 [['xu','序号'],['val','值1']]
     * @param header_colmun 表头插入的初始行 默认为第一行
     * @return: 
     */    
    public function set_excel_header($xls_contents,$content_column,$xls_header,$header_colmun = 1)
    {
        $this->set_default_width_height();
        foreach ($xls_header as $key => $header) {
            $index = $this->int_index_conver($key,$header_colmun);
            $this->set_cell_value($index,$header[1]);
        }
        $header_count = count($xls_header);
        foreach ($xls_contents as $content) {
            for ($i = 0;$i < $header_count;$i++) {
                $index = $this->int_index_conver($i,$content_column);
                $value = $content[$xls_header[$i][0]];
                if (is_array($value)) {
                    if ($value['type'] == 'url') { // url
                        $this->set_cell_url($index, $value['url'], $value['text'] ?? $value['url']);
                    } elseif ($value['type'] == 'img') { // 图片
                        $this->set_cell_img($index, $value['path'], $value['width'], $value['height'], $value['title'] ?? '', $value['descript'] ?? '');
                    } elseif ($value['type'] == 'shhet') { // sheet
                        $this->set_cell_sheet($index, $value['value'], $value['sheet_name'], $value['cell_index']);
                    }
                } else {
                    $this->set_cell_value($index, $value);
                }
            }
            $content_column++;
        }
    }

    /**
     * @description: 设置单元格的内容
     * @param index string 设置的位置 
     * @param index string 设置的内容
     * @param cell_style string 单元格格式 默认为false
     * @return: 
     */    
    public function set_cell_value($index, $value)
    {
        if (is_numeric($value) && strlen($value) >= 11) { // 超长数字
            $this->excel_sheet->setCellValueExplicit($index, $value, $this->get_cell_style('text'));
        } else {
            $this->excel_sheet->setCellValue($index, $value);
        }
    }

    /**
     * @description: 单元格内容设置为url
     * @param cell_index string 设置的单元格索引 A1
     * @param url_text string 设置的单元格内容
     * @param url string 内容跳转的url
     * @return: 
     */
    public function set_cell_url($cell_index, $url_text, $url)
    {
        $this->set_cell_value($cell_index,$url_text);
        $this->excel_sheet->getCell($cell_index)->getHyperlink()->setUrl($url);
    }

    /**
     * @description: 在单元格插入图片
     * @param cel_index string 单元格的索引,图片所有的位置要设置高度,否则可能图片不显示
     * @param img_path string 图片的全路径
     * @param img_weight string 图片的宽度
     * @param img_height string 图片的高度
     * @param img_title string 图片名字,不传显示空
     * @param $img_descript string 图片描述,不传显示空
     * @return: 
     */
    public function set_cell_img($cel_index, $img_path, $img_weight, $img_height, $img_title = ' ', $img_descript = '')
    {
        $draw = new \PHPExcel_Worksheet_Drawing();
        $draw->setName($img_title);
        $draw->setDescription($img_descript);
        $draw->setPath($img_path);
        $draw->setWidth($img_weight);
        $draw->setHeight($img_height);
        $draw->setCoordinates($cel_index);
        $draw->setWorksheet($this->excel_sheet);
    }

    /**
     * @description: 单元格内容跳转到另一个sheet
     * @param cell_index string 设置的单元格索引 A1
     * @param sheet_text string 设置的单元格内容
     * @param sheet_name string 内容跳转的sheet的名字
     * @param sheet_cell_index string 内容跳转的sheet的的单元格位置
     * @return: 
     */
    public function set_cell_sheet($cell_index, $sheet_text, $sheet_name, $sheet_cell_index)
    {
        $sheet = "sheet://'$sheet_name'!$sheet_cell_index";
        $this->set_cell_url($cell_index, $sheet_text, $sheet);
    }

    /**
     * @description: 合并指定单元格
     * @param start string 起始单元格 A1
     * @param end string 结束单元格 G1
     * @return: 
     */
    public function merge_cell($start, $end)
    {
        $this->excel_sheet->mergeCells($start.':'.$end);
    }

    /**
     * @description: 拆分指定单元格
     * @param start string 起始单元格 A1
     * @param end string 结束单元格 G1
     * @return: 
     */
    public function unmerge_cell($start, $end)
    {
        $this->excel_sheet->unmergeCells($start.':'.$end);
    }

    /**
     * @description: 判断指定单元格是否为合并的单元格
     * @param cell_index string 单元格 A1
     * @return: 
     */
    public function merge_cell_judge($cell_index)
    {
        $cell = $this->excel_sheet->getCell($cell_index); 
        $merges = $this->excel_sheet->getMergeCells();
        foreach ($merges as $cells) {
            if ($cell->isInRange($cells)) {
                return true;
            }
        }
        return false;
    }

    /**
     * @description: 设置表格默认宽高
     * @param int $column_width 列宽
     * @param int $row_height 行高 默认为-1 自适应高度
     * @return {*}
     */
    public function set_default_width_height($column_width = 10, $row_height = -1)
    {
        $this->excel_sheet->getDefaultRowDimension()->setRowHeight($row_height);
        $this->excel_sheet->getDefaultColumnDimension()->setWidth($column_width);
    }

    /**
     * @description: 设置指定列单元格宽度或高度
     * @param column_index string 指定列 A
     * @param width int 宽度
     * @return: 
     */    
    public function set_column_width($column_index, $width)
    {
        $this->excel_sheet->getColumnDimension($column_index)->setWidth($width);
    }

    /**
     * @description: 设置行高
     * @param int $row 行数 从1开始
     * @param int $width 
     * @return {*}
     */
    public function set_row_height($row, $width)
    {
        $this->excel_sheet->getRowDimension($row)->setRowHeight($width);
    }
 
    /**
     * @description: 设置单元格内容自动换行
     * @param start string 开始的位置 A1
     * @param end string 结束的位置 Z100
     * @return: 
     */    
    public function set_word_wrap($start,$end)
    {
        $this->excel_sheet->getStyle($start.':'.$end)->getAlignment()->setWrapText(true);
    }

    /**
     * @description: 设置单元格内容垂直样式
     * @param start string 开始的位置 A1
     * @param end string 结束的位置 Z100
     * @param vertical_style string 垂直样式 center:垂直居中
     * @return: 
     */    
    public function set_vertical_style($start, $end, $vertical_style)
    {
        $style = $this->get_cell_style('vertical_'.$vertical_style);
        $this->excel_sheet->getstyle($start.":".$end)->getAlignment()->setVertical($style);
    }

    /**
     * @description: 设置单元格内容水平样式
     * @param start string 开始的位置 A1
     * @param end string 结束的位置 Z100
     * @param horizontal_style string 水平样式 center:水平居中 top:水平居上
     * @return: 
     */    
    public function set_horizontal_style($start, $end, $horizontal_style)
    {
        $style = $this->get_cell_style('horizontal_'.$horizontal_style);
        $this->excel_sheet->getstyle($start.":".$end)->getAlignment()->setHorizontal($style);
    }

    /**
     * @description: 获取单元格格式
     * @param type string 要获取的格式类型
     * @return: 
     */    
    public function get_cell_style($type)
    {
        $styles = [
            'text'              => \PHPExcel_Cell_DataType::TYPE_STRING, //单元格设置为文本格式
            'vertical_center'   => \PHPExcel_Style_Alignment::VERTICAL_CENTER, //单元格内容垂直居中
            'horizontal_center' => \PHPExcel_Style_Alignment::HORIZONTAL_CENTER, //单元格内容水平居中
            'vertical_top'      => \PHPExcel_Style_Alignment::VERTICAL_TOP, //单元格内容垂直居上
        ];
        return $styles[$type];
    }

    /**
     * @description: 设置单元格背景颜色
     * @param start string 起始单元格 A1
     * @param end string 结束单元格 G2
     * @param color string ARGB颜色 A代表透明度 FF表示不透明(FF808080)00表示透明
     * @return: 
     */
    public function set_cell_back_color($start,$end,$color)
    {
        $cell_index = $start . ':' . $end;
        $this->excel_sheet->getStyle($cell_index)->getFill()->setFillType(PHPExcel_Style_Fill::FILL_SOLID);
        $this->excel_sheet->getStyle($cell_index)->getFill()->getStartColor()->setARGB($color);
    }

    /**
     * @description: 设置单元格的边框
     * @param start string 开始的位置 A1
     * @param end string 结束的位置 Z100
     * @return: 
     */    
    public function set_border_style($start, $end)
    {
        $style_array = [
            'borders' => [
                'allborders' => [
                    'style' => \PHPExcel_Style_Border::BORDER_THIN
                ]
            ]
        ];
        $this->excel_sheet->getStyle($start.':'.$end)->applyFromArray($style_array);
    }

    /**
     * @description: 设置字体
     * @param string $cell_index 单元格索引 A1
     * @param string $font 字体
     * @param int $size 字体大小
     * @param string $color 字体颜色 ARGB颜色 A代表透明度 FF表示不透明(FF808080)00表示透明;\PHPExcel_Style_Color类中有颜色常量
     * @param bool $bold 字体加粗
     * @param bool $unline 字体下划线
     * @return {*}
     */
    public function set_font($cell_index, $font = '', $size = '', $color = '', $bold = false, $unline = false)
    {
        $sheet_font = $this->excel_sheet->getStyle($cell_index)->getFont();
        if ($font) {
            $sheet_font->setName($font);
        }
        if ($size) {
            $sheet_font->setSize($size);
        }
        if ($color) {
            $sheet_font->getColor()->setARGB(\PHPExcel_Style_Color::COLOR_WHITE);
        }
        if ($bold) {
            $sheet_font->setBold(true);
        }
        if ($unline) {
            $sheet_font->setUnderline(\PHPExcel_Style_Font::UNDERLINE_SINGLE);
        }
    }

    /**
     * @description: 设置sheet 获取sheet对象
     * @param index int sheet的索引 默认为0 第一个sheet
     * @return: 
     */    
    public function set_sheet_index($index = 0)
    {
        try {
            $this->excel->setActiveSheetIndex($index);
        } catch (\Exception $e) {
            $this->excel->createSheet($index); //创建sheet
            $this->excel->setActiveSheetIndex($index);
        }
        $this->excel_sheet = $this->excel->getActiveSheet();
    }

    /**
     * @description: 设置/获取sheet的名字
     * @param sheet_name string sheet的名字
     * @return: 
     */
    public function sheet_name($sheet_name = '')
    {
        if ($sheet_name) {
            $this->excel_sheet->setTitle($sheet_name);
        } else {
            return $this->excel_sheet->getTitle();
        }
    }

    /**
     * @description: 获取sheet数
     * @return: 
     */
    public function get_sheet_count()
    {
        return $this->excel->getSheetCount();
    }

    /**
     * @description: 设置sheet的颜色
     * @param color string sheet的颜色, ARGB颜色 A代表透明度 FF表示不透明(FF808080)00表示透明;\PHPExcel_Style_Color类中有颜色常量
     * @return: 
     */
    public function set_sheet_color($color)
    {
        $this->excel_sheet->getTabColor()->setARGB($color);
    }

    /**
     * @description: 复制sheet到另一个excel对象;
     * 复制sheet时,如果被复制的excel对象还需要使用,则需要clone原excel对象和sheet对象,
     * 否则复制后,原对象会被修改,导致原excel对象发生变化,之后对于原对象的数据获取可能发生错误
     * @param path string 文件的路径
     * @param sheet_title string 复制后的sheet的名字,同一个excel对象中sheet名称重复会报错
     * @param index int 要复制到的索引位置
     * @return: 
     */
    public function copy_sheet_to_other($path,$sheet_title,$index = 0)
    {
        /* 克隆sheet对象
        $excel1 = clone $this->excel;
        $sheet1 =  clone $excel1->getSheet($sheet_index);*/
        $sheet = (new self)->sheet;
        $sheet->setTitle($sheet_title);
        if ($index) {
            $this->excel->addExternalSheet($sheet,$index);
        } else {
            $this->excel->addExternalSheet($sheet);
        }
    }

    /**
     * @description: 删除sheet
     * @param index int sheet索引,默认0
     * @return: 
     */
    public function del_sheet($index = 0)
    {
        $this->excel->removeSheetByIndex($index);
    }

    /**
     * @description: 行/列的添加与删除
     * @param int $start 起始行/列
     * @param int $number 行/列数
     * @param int $type 1、行/列前添加 2、行/列后删除
     * @param int $row_column 1、行 2、列
     * @return {*}
     */
    public function insert_del_row_column($start, $number, $type, $row_column)
    {
        if ($type == 1) {
            $func = $row_column == 1 ? 'insertNewRowBefore' : 'insertNewColumnBefore';
        } else if ($type == 2) {
            $func = $row_column == 1 ? 'removeRow' : 'removeColumn';
        }
        $this->excel_sheet->$func($start, $number);
    }

    /**
     * @description: 获取表格列数
     * @return: string A
     */
    public function get_height_column()
    {
        return $this->excel_sheet->getHighestColumn();
    }

    /**
     * @description: 获取表格行数
     * @return: 
     */
    public function get_height_row()
    {
        return $this->excel_sheet->getHighestRow();
    }

    /**
     * @description: 数字转列索引(字母),获取单元格位置
     * @param key excel的表头位置 第一个是0(A)
     * @param column 要获取的excel的行数,默认为第一行
     * @return: 
     */    
    public function int_index_conver($key, $column = 1)
    {
        return \PHPExcel_Cell::stringFromColumnIndex($key) . $column;
    }

    /**
     * @description: 将列索引转换为数字
     * @param str string 列 A
     * @return: 
     */
    public function index_conver_int($str)
    {
        return \PHPExcel_Cell::columnIndexFromString($str);
    }

    /**
     * @description: 设置单元格显示与隐藏
     * @param column_index string 列索引 A
     * @param show bool false:隐藏 true:显示
     * @return: 
     */    
    public function column_visible_show($column_index,$show = false)
    {
        if ($show == false) {
            $this->excel_sheet->getColumnDimension($column_index)->setVisible(false);
        } else if ($show == true) {
            $this->excel_sheet->getColumnDimension($column_index)->setOutlineLevel(1);
        }
    }

    /**
     * @description: 固定表格指定行
     * @param cell_index string 行索引 B2
     * @return: 
     */    
    public function fixed_row($cell_index)
    {
        $this->excel_sheet->freezePane($cell_index);
    }

    /**
     * @description: 设置密码保护表格
     * @param password string 密码
     * @return: 
     */    
    public function set_excel_pass($password)
    {
        $this->excel_sheet->getProtection()->setPassword($password);
        $this->excel_sheet->getProtection()->setSheet(true);
        $this->excel_sheet->getProtection()->setSort(true);
        $this->excel_sheet->getProtection()->setInsertRows(true);
        $this->excel_sheet->getProtection()->setFormatCells(true);
    }

    /**
     * @description: 设置单选的下拉选项
     * @param spectials array 需要加下拉框的单元格信息 [['column'=>'A','select_options'=>['是','否']]]
     * @param colummn int 要设置的行数
     * @return: 
     */    
    public function set_excel_radio($spectials,$colummn)
    {
        foreach($spectials as $spectial)
        {
            $optionsString = implode(',', $spectial['select_options']);
            $n = 0;
            while($n < $colummn) {
                //这一句为要设置数据有效性的单元格
                $objValidation = $this->excel_sheet->getCell($spectial['column'].(string)$n)->getDataValidation();
                $objValidation->setType(\PHPExcel_Cell_DataValidation::TYPE_LIST)
                            ->setErrorStyle(\PHPExcel_Cell_DataValidation::STYLE_STOP)
                            ->setAllowBlank(true)
                            ->setShowInputMessage(true)
                            ->setShowErrorMessage(true)
                            ->setShowDropDown(true)
                            ->setErrorTitle('输入的值有误')
                            ->setError('您输入的值不在下拉框列表内.')
                            ->setPromptTitle('')
                            ->setPrompt('')
                            ->setOperator(\PHPExcel_Cell_DataValidation::OPERATOR_BETWEEN)
                            ->setFormula1('"'.$optionsString.'"');
                $n++;
            }
        }
    }

    /**
     * @description:保存excel
     * @param filename string 直接下载时文件名
     * @param type string 保存类型 默认为xls或xlxs(根据文件类型保存);PDF、HTML、CSV、
     * @param save_path string 保存excel的路径,默认为直接下载 
     * @return: 
     */    
    public function save_excel($filename,$type='',$save_path = 'php://output')
    {
        $type = strtolower($type);
        if ($type == '') {
            $save_object = \PHPExcel_IOFactory::createWriter($this->excel, $this->file_type);
        } else if ($type == 'pdf') {
            $save_object = new \PHPExcel_Writer_PDF($this->excel);
        } else if ($type == 'html') {
            $save_object = new \PHPExcel_Writer_HTML($this->excel);
        } else if ($type == 'csv') {
            $save_object = new \PHPExcel_Writer_CSV($this->excel);
        } else {
            throw '请导出正确的文件类型';
        }
        if ($save_path == 'php://output') {
	        $filename = str_replace("+", "%20", urlencode($filename));
            ob_clean();
            header("Pragma: public");
            header("Expires: 0");
            header("Cache-Control:must-revalidate, post-check=0, pre-check=0");
            header("Content-Type:application/force-download");
            header("Content-Type:application/vnd.ms-execl");
            header("Content-Type:application/octet-stream");
            header("Content-Type:application/download");;
            header('Content-Disposition:attachment;filename='.$filename);
            header("Content-Transfer-Encoding:binary");
        }
        $save_object->save($save_path);
    }
}

单选来源于方法:https://blog.csdn.net/qq_41277856/article/details/103634056
部分方法来源于:https://blog.csdn.net/lampsunny/article/details/79012173

{/if}