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操作场景)
来源:CSDN
作者:丁丁丁梦涛
链接:https://blog.csdn.net/dmt742055597/article/details/102368306