基于codeigniter3框架使用PHPspreadsheet包实现excel导入导出功能

文章目录

  • codeigniter3+PHPspreadsheet实现excel导入导出功能
    • 引入composer依赖包PHPspreadsheet
    • 添加类库并use相关类
    • 添加导入导出方法
    • 实战应用

codeigniter3+PHPspreadsheet实现excel导入导出功能

引入composer依赖包PHPspreadsheet

  • 根目录composer.json文件的require节点加入如下内容,注意json格式规则:
    "phpoffice/phpspreadsheet": "*"
    
  • 之后需执行 composer update 下载PHPspreadsheet依赖包

添加类库并use相关类

  • 在 application\libraries 目录下添加名为 Php_spread_sheet_lib.php 的文件(名称随意,注意不要使用PHPspreadsheet,避免不必要的冲突,ci3无命名空间)
  • use必要类
    use PhpOffice\PhpSpreadsheet\Cell\Coordinate;
    use PhpOffice\PhpSpreadsheet\Cell\DataType;
    use PhpOffice\PhpSpreadsheet\IOFactory;
    use PhpOffice\PhpSpreadsheet\Spreadsheet;
    use PhpOffice\PhpSpreadsheet\Style\Alignment;
    use PhpOffice\PhpSpreadsheet\Style\Border;
    use PhpOffice\PhpSpreadsheet\Style\Color;
    use PhpOffice\PhpSpreadsheet\Style\Fill;
    use PhpOffice\PhpSpreadsheet\Style\NumberFormat;
    use PhpOffice\PhpSpreadsheet\Worksheet\PageSetup;
    use PhpOffice\PhpSpreadsheet\Reader\Xlsx;
    use PhpOffice\PhpSpreadsheet\Reader\Xls;
    

添加导入导出方法

  • 类文件主要内容如下
    class Php_spread_sheet_lib
    {
        /**
         * 使用PHPEXECL导入
         *
         * @param string $file      文件地址
         * @param int    $sheet     工作表sheet(传0则获取第一个sheet)
         * @param int    $columnCnt 列数(传0则自动获取最大列)
         * @param array  $options   操作选项
         *                  array mergeCells 合并单元格数组
         *                  array formula    公式数组
         *                  array format     单元格格式数组
         *
         * @return array
         * @throws Exception
         */
        public function importExecl(string $file = '', int $sheet = 0, int $columnCnt = 0, &$options = [])
        {
            try {
                /* 转码 */
                $file = iconv("utf-8", "gb2312", $file);
    
                if (empty($file) OR !file_exists($file)) {
                    throw new \Exception('文件不存在!');
                }
    
                /** @var Xlsx $objRead */
                $objRead = IOFactory::createReader('Xlsx');
    
                if (!$objRead->canRead($file)) {
                    /** @var Xls $objRead */
                    $objRead = IOFactory::createReader('Xls');
    
                    if (!$objRead->canRead($file)) {
                        throw new \Exception('只支持导入Excel文件!');
                    }
                }
    
                /* 如果不需要获取特殊操作,则只读内容,可以大幅度提升读取Excel效率 */
                empty($options) && $objRead->setReadDataOnly(true);
                /* 建立excel对象 */
                $obj = $objRead->load($file);
                /* 获取指定的sheet表 */
                $currSheet = $obj->getSheet($sheet);
    
                if (isset($options['mergeCells'])) {
                    /* 读取合并行列 */
                    $options['mergeCells'] = $currSheet->getMergeCells();
                }
    
                if (0 == $columnCnt) {
                    /* 取得最大的列号 */
                    $columnH = $currSheet->getHighestColumn();
                    /* 兼容原逻辑,循环时使用的是小于等于 */
                    $columnCnt = Coordinate::columnIndexFromString($columnH);
                }
    
                /* 获取总行数 */
                $rowCnt = $currSheet->getHighestRow();
                $data   = [];
    
                /* 读取内容 */
                for ($_row = 1; $_row <= $rowCnt; $_row++) {
                    $isNull = true;
    
                    for ($_column = 1; $_column <= $columnCnt; $_column++) {
                        $cellName = Coordinate::stringFromColumnIndex($_column);
                        $cellId   = $cellName . $_row;
                        $cell     = $currSheet->getCell($cellId);
    
                        if (isset($options['format'])) {
                            /* 获取格式 */
                            $format = $cell->getStyle()->getNumberFormat()->getFormatCode();
                            /* 记录格式 */
                            $options['format'][$_row][$cellName] = $format;
                        }
    
                        if (isset($options['formula'])) {
                            /* 获取公式,公式均为=号开头数据 */
                            $formula = $currSheet->getCell($cellId)->getValue();
    
                            if (0 === strpos($formula, '=')) {
                                $options['formula'][$cellName . $_row] = $formula;
                            }
                        }
    
                        if (isset($format) && 'm/d/yyyy' == $format) {
                            /* 日期格式翻转处理 */
                            $cell->getStyle()->getNumberFormat()->setFormatCode('yyyy/mm/dd');
                        }
    
                        $data[$_row][$cellName] = trim($currSheet->getCell($cellId)->getFormattedValue());
    
                        if (!empty($data[$_row][$cellName])) {
                            $isNull = false;
                        }
                    }
    
                    /* 判断是否整行数据为空,是的话删除该行数据 */
                    if ($isNull) {
                        unset($data[$_row]);
                    }
                }
    
                return $data;
            } catch (\Exception $e) {
                throw $e;
            }
        }
    
        /**
         * Excel导出,TODO 可继续优化
         *
         * @param array  $datas      导出数据,格式['A1' => 'XXXX公司报表', 'B1' => '序号']
         * @param string $fileName   导出文件名称
         * @param array  $options    操作选项,例如:
         *                  bool   print       设置打印格式
         *                  string freezePane  锁定行数,例如表头为第一行,则锁定表头输入A2
         *                  array  setARGB     设置背景色,例如['FFc0c0c0'=>'A1', 'FF000000'=>['C1', 'C2']]
                                               键为FF开头的颜色值,值为单元格可以为单个字符串或多个组成的数组,说明多个单元格都适用同一种颜色背景
         *                  array  setWidth    设置宽度,例如['A' => 30, 'C' => 20]
         *                  array  setHeight   设置高度,例如['1' => 300, '10' => 200]//键为行号,值为行高
         *                  array  setWrap     设置换行,例如['A1', 'C2']
         *                                     要实现单元格换行,包括两部分:首先,需要换行的内容之间必需包括换行符,可以用PHP_EOL或者\r\n;其次,必需激活单元格的“自动换行”属性
         *                  bool   setBorder   设置单元格边框
         *                  array  mergeCells  设置合并单元格,例如['A1:J1' => 'A1:J1']
         *                  array  formula     设置公式,例如['F2' => '=IF(D2>0,E42/D2,0)']
         *                  array  format      设置格式,整列设置,例如['A' => 'General']
         *                  array  alignCenter 设置居中样式,例如['A1', 'A2']
         *                  array  bold        设置加粗样式,例如['A1', 'A2']
         *                  string savePath    保存路径,设置后则文件保存到服务器,不通过浏览器下载
         * @param string $excelType   导出文件格式类型,默认xlsx,可选xls和xlsx
         *
         * @return bool 成返回true,失败返回false
         * @throws Exception
         */
        function exportExcel(array $datas, string $fileName = '', array $options = [], string $excelType='xlsx'): bool
        {
            try {
                if (empty($datas)) {
                    return false;
                }
    
                set_time_limit(0);
                /** @var Spreadsheet $objSpreadsheet */
                //$objSpreadsheet = app(Spreadsheet::class);//laravel写法
                $objSpreadsheet = new Spreadsheet();
                /* 设置默认文字居左,上下居中 */
                $styleArray = [
                    'alignment' => [
                        'horizontal' => Alignment::HORIZONTAL_LEFT,
                        'vertical'   => Alignment::VERTICAL_CENTER,
                    ],
                ];
                $objSpreadsheet->getDefaultStyle()->applyFromArray($styleArray);
                /* 设置Excel Sheet */
                $activeSheet = $objSpreadsheet->setActiveSheetIndex(0);
    
                /* 打印设置 */
                if (isset($options['print']) && $options['print']) {
                    /* 设置打印为A4效果 */
                    $activeSheet->getPageSetup()->setPaperSize(PageSetup:: PAPERSIZE_A4);
                    /* 设置打印时边距 */
                    $pValue = 1 / 2.54;
                    $activeSheet->getPageMargins()->setTop($pValue / 2);
                    $activeSheet->getPageMargins()->setBottom($pValue * 2);
                    $activeSheet->getPageMargins()->setLeft($pValue / 2);
                    $activeSheet->getPageMargins()->setRight($pValue / 2);
                }
    
                /* 行数据处理 */
                foreach ($datas as $sKey => $sItem) {
                    /* 默认文本格式 */
                    $pDataType = DataType::TYPE_STRING;
    
                    /* 设置单元格格式 */
                    if (isset($options['format']) && !empty($options['format'])) {
                        $colRow = Coordinate::coordinateFromString($sKey);
    
                        /* 存在该列格式并且有特殊格式 */
                        if (isset($options['format'][$colRow[0]]) &&
                            NumberFormat::FORMAT_GENERAL != $options['format'][$colRow[0]]) {
                            $activeSheet->getStyle($sKey)->getNumberFormat()
                                ->setFormatCode($options['format'][$colRow[0]]);
    
                            if (false !== strpos($options['format'][$colRow[0]], '0.00') &&
                                is_numeric(str_replace(['¥', ','], '', $sItem))) {
                                /* 数字格式转换为数字单元格 */
                                $pDataType = DataType::TYPE_NUMERIC;
                                $sItem     = str_replace(['¥', ','], '', $sItem);
                            }
                        } elseif (is_int($sItem)) {
                            $pDataType = DataType::TYPE_NUMERIC;
                        }
                    }
    
                    $activeSheet->setCellValueExplicit($sKey, $sItem, $pDataType);
    
                    /* 存在:形式的合并行列,列入A1:B2,则对应合并 */
                    if (false !== strstr($sKey, ":")) {
                        $options['mergeCells'][$sKey] = $sKey;
                    }
                }
    
                unset($datas);
    
                /* 设置锁定行 */
                if (isset($options['freezePane']) && !empty($options['freezePane'])) {
                    $activeSheet->freezePane($options['freezePane']);
                    unset($options['freezePane']);
                }
    
                /* 设置宽度 */
                if (isset($options['setWidth']) && !empty($options['setWidth'])) {
                    foreach ($options['setWidth'] as $swKey => $swItem) {
                        if(is_numeric($swItem)){//设置宽度
                            $activeSheet->getColumnDimension($swKey)->setWidth($swItem);
                        }else{//自动宽度
                            $activeSheet->getColumnDimension($swKey)->setAutoSize($swItem);
                        }
                    }
    
                    unset($options['setWidth']);
                }
    
                /* 设置行高度 */
                if (isset($options['setHeight']) && !empty($options['setHeight'])) {
                    foreach ($options['setHeight'] as $shKey => $shItem) {
                        if(is_numeric($shItem)){//设置宽度
                            $activeSheet->getRowDimension($shKey)->setRowHeight($shItem);
                        }else{//默认高度15
                            $activeSheet->getDefaultRowDimension()->setRowHeight(15);
                        }
                    }
    
                    unset($options['setHeight']);
                }
    
                /* 设置换行 */
                if (isset($options['setWrap']) && !empty($options['setWrap'])) {
                    foreach ($options['setWrap'] as $swItem) {
                        $activeSheet->getStyle($swItem)->getAlignment()->setWrapText(true);
                    }
    
                    unset($options['setWrap']);
                }
    
                /* 设置背景色 */
                if (isset($options['setARGB']) && !empty($options['setARGB'])) {
                    /*foreach ($options['setARGB'] as $sItem) {
                        $activeSheet->getStyle($sItem)
                            ->getFill()->setFillType(Fill::FILL_SOLID)
                            ->getStartColor()->setARGB(Color::COLOR_YELLOW);
                    }*/
                    foreach ($options['setARGB'] as $sKey => $sItem) {
                        if(!is_array($sItem)){//不是数组
                            $activeSheet->getStyle($sItem)
                                ->getFill()->setFillType(Fill::FILL_SOLID)
                                ->getStartColor()->setARGB($sKey);
                        }else{//是数组
                            foreach($sItem as $item){
                                $activeSheet->getStyle($item)
                                    ->getFill()->setFillType(Fill::FILL_SOLID)
                                    ->getStartColor()->setARGB($sKey);
                            }
                        }
                    }
    
                    unset($options['setARGB']);
                }
    
                /* 设置公式 */
                if (isset($options['formula']) && !empty($options['formula'])) {
                    foreach ($options['formula'] as $fKey => $fItem) {
                        $activeSheet->setCellValue($fKey, $fItem);
                    }
    
                    unset($options['formula']);
                }
    
                /* 合并行列处理 */
                if (isset($options['mergeCells']) && !empty($options['mergeCells'])) {
                    $activeSheet->setMergeCells($options['mergeCells']);
                    unset($options['mergeCells']);
                }
    
                /* 设置居中 */
                if (isset($options['alignCenter']) && !empty($options['alignCenter'])) {
                    $styleArray = [
                        'alignment' => [
                            'horizontal' => Alignment::HORIZONTAL_CENTER,
                            'vertical'   => Alignment::VERTICAL_CENTER,
                        ],
                    ];
    
                    foreach ($options['alignCenter'] as $acItem) {
                        $activeSheet->getStyle($acItem)->applyFromArray($styleArray);
                    }
    
                    unset($options['alignCenter']);
                }
    
                /* 设置加粗 */
                if (isset($options['bold']) && !empty($options['bold'])) {
                    foreach ($options['bold'] as $bItem) {
                        $activeSheet->getStyle($bItem)->getFont()->setBold(true);
                    }
    
                    unset($options['bold']);
                }
    
                /* 设置单元格边框,整个表格设置即可,必须在数据填充后才可以获取到最大行列 */
                if (isset($options['setBorder']) && $options['setBorder']) {
                    $border    = [
                        'borders' => [
                            'allBorders' => [
                                'borderStyle' => Border::BORDER_THIN, // 设置border样式
                                'color'       => ['argb' => 'FF000000'], // 设置border颜色
                            ],
                        ],
                    ];
                    $setBorder = 'A1:' . $activeSheet->getHighestColumn() . $activeSheet->getHighestRow();
                    $activeSheet->getStyle($setBorder)->applyFromArray($border);
                    unset($options['setBorder']);
                }
    
                $fileName = !empty($fileName) ? $fileName.'.'.strtolower($excelType) : (date('YmdHis').'.'.strtolower($excelType));
    
                if (!isset($options['savePath'])) {
                    if($excelType == 'xlsx'){
                        /* 直接导出Excel,无需保存到本地,输出07Excel文件 */
                        header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
                    }else{
                        header('Content-Type: application/vnd.ms-excel');
                    }
                    header(
                        "Content-Disposition:attachment;filename=" . iconv(
                            "utf-8", "GB2312//TRANSLIT", $fileName
                        )
                    );
                    header('Cache-Control: max-age=0');//禁止缓存
                    $savePath = 'php://output';
                } else {
                    $savePath = $options['savePath'].$fileName;
                }
    
                ob_clean();
                ob_start();
                $objWriter = IOFactory::createWriter($objSpreadsheet, ucfirst($excelType));
                $objWriter->save($savePath);
                /* 释放内存 */
                $objSpreadsheet->disconnectWorksheets();
                unset($objSpreadsheet);
                ob_end_flush();
    
                return true;
            } catch (Exception $e) {
                return false;
            }
        }
    
    }
    
  • 下载完整类库文件传送门

实战应用

  • 这里把我项目中的调用方法展现出来,读着只需看与excel相关的有用的(宽高、样式、合并单元格等)即可,看懂类库文件就能会用,我这里也是对它的运用
    /**
     * 方法 export_project_apply_detail_as_excel_serv,导出项目抽检申请详情数据到excel
     *
     * @param array $params 参数数组
     *
     * @return mixed 成功返回true,失败返回false
     */
    public function export_project_apply_detail_as_excel_serv(array $params){
        //获取项目抽检申请详情(包含项目地址所属公司等信息)
        $project_apply_department = $this->get_project_apply_department_detail_serv($params);
        //获取项目抽检申请检查项列表
        $resolve_item_list = $this->deal_get_project_apply_item_list_serv($params);
        //处理成可写入excel的数据格式
        $data = [
            'A1' => '公司名称', 'B1' => '项目名称', 'C1' => '立项时间', 'D1' => '项目地址', 'E1' => '技术负责人', 'F1' => '手机号',
            'A2' => $project_apply_department['company_name'], 'B2' => $project_apply_department['project_name'],
            'C2' => $project_apply_department['create_time'], 'D2' => $project_apply_department['address'],
            'E2' => $project_apply_department['tec_leader_name'], 'F2' => $project_apply_department['tec_leader_phone'],
            'A4' => '项目状态', 'B4' => '抽签时间', 'C4' => '预计抽检时间', 'D4' => '抽检人员', 'E4' => '职务', 'F4' => '手机号',
            'A5' => $project_apply_department['status_name'], 'B5' => $project_apply_department['draw_date'],
            'C5' => $project_apply_department['plan_samp_date'], 'D5' => $project_apply_department['samp_user_name'],
            'E5' => $project_apply_department['samp_user_job'], 'F5' => $project_apply_department['samp_user_phone'],
            'A7' => '分数', 'B7' => '检查时间',
            'A8' => $project_apply_department['score'], 'B8' => $project_apply_department['samp_date'] ?? '暂无',
            'A10' => '检查项', 'B10' => '检查楼层',
        ];
        //处理抽检的检查项楼层数据
        static $row = 11;
        foreach($project_apply_department['project_apply_wbs_item'] as $k => $v){
            if($v['plaster']){
                $tmp = ['A'.$row => $v['plaster_name'], 'B'.$row => $v['build_name'].$v['floor_name'].'层',];
                $data = array_merge($data, $tmp);
                $row ++;
                continue;
            }
            if($v['concrete']){
                $tmp = ['A'.$row => $v['concrete_name'], 'B'.$row => $v['build_name'].$v['floor_name'].'层',];
                $data = array_merge($data, $tmp);
                $row ++;
            }
            if($v['masonry']){
                $tmp = ['A'.$row => $v['masonry_name'], 'B'.$row => $v['build_name'].$v['floor_name'].'层',];
                $data = array_merge($data, $tmp);
                $row ++;
            }
        }
        //处理检查项楼层列表数据
        $row ++;
        $bold_row2 = $row;//设置加粗的行号
        $tmp2 = ['A'.$row => '楼号', 'B'.$row => '层号', 'C'.$row => '形象进度', 'D'.$row => '检查项', 'E'.$row => '检查项', 'F'.$row => '检查项'];
        $data = array_merge($data, $tmp2);
        $row ++;
        foreach($resolve_item_list as $r_i_l_k => $r_i_l_v){
            /*if($r_i_l_v['plaster']){
                unset($r_i_l_v['concrete_name'], $r_i_l_v['masonry_name']);
            }else{
                unset($r_i_l_v['plaster_name']);
            }*/
            $tmp3 = [
                'A'.$row => $r_i_l_v['build_name'], 'B'.$row => $r_i_l_v['floor_name'], 'C'.$row => $project_apply_department['appearance_name'],
                'D'.$row => $r_i_l_v['concrete_name'] ?? '', 'E'.$row => $r_i_l_v['plaster_name'] ?? '', 'F'.$row => $r_i_l_v['masonry_name'] ?? '',
            ];
            $data = array_merge($data, $tmp3);
            $row ++;
        }
        //设置导出excel单元格格式(居中、加粗等)
        $oss_path = 's_c_s_l/excel/';
        $save_path = getcwd().'/'.$oss_path;
        $file_name = $project_apply_department['project_name'].'-项目抽检申请详情资料';
        $file_ext = 'xls';
        $options = [
            'print' => true,//打印格式
            'alignCenter' => array_keys($data),//居中
            'setWidth' => ['A'=>true, 'B'=>true, 'C'=>true, 'D'=>true, 'E'=>true, 'F'=>true],
            'bold' => [
                'A1', 'B1', 'C1', 'D1', 'E1', 'F1', 'A4', 'B4', 'C4', 'D4', 'E4', 'F4', 'A7', 'B7', 'C7', 'D7', 'E7', 'F7', 'A10', 'B10',
                'A'.$bold_row2, 'B'.$bold_row2, 'C'.$bold_row2, 'D'.$bold_row2, 'E'.$bold_row2, 'F'.$bold_row2,
            ],//加粗
            'savePath' => $save_path,//存储路径
        ];
        //导出,在浏览器输出二进制流主动生成excel文件
        $this->load->library('php_spread_sheet_lib');
        $export_res = $this->php_spread_sheet_lib->exportExcel($data, $file_name, $options, $file_ext);
        if($export_res){
            $export_res = [
                'oss_path' => $oss_path.$file_name.'.'.$file_ext,
                'local_full_path' => $save_path.$file_name.'.'.$file_ext,
            ];
        }
        return $export_res;
    }
    

参考(基于并扩展导出excel的方法):使用PhpSpreadsheet导入&导出Excel(适用各种Excel操作场景)

基于codeigniter3框架使用PHPspreadsheet包实现excel导入导出功能_第1张图片
基于codeigniter3框架使用PHPspreadsheet包实现excel导入导出功能_第2张图片

********************只要思想不滑坡,办法总比困难多********************

你可能感兴趣的:(php,excel)