基於codeigniter3框架使用PHPspreadsheet包實現excel導入導出功能

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操作場景)

支付寶
在這裏插入圖片描述

********************只要思想不滑坡,辦法總比困難多********************
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章