1. 程式人生 > >使用PhpSpreadsheet匯入&匯出Excel(適用各種Excel操作場景)

使用PhpSpreadsheet匯入&匯出Excel(適用各種Excel操作場景)

PHP對Excel匯入&匯出操作

最近公司要做報表功能,各種財務報表、工資報表、考勤報表等,複雜程度讓人頭大,於是特地封裝適用各大場景的匯入&匯出操作,希望各界大神支出不足之處,以便小弟繼續完善。

phpspreadsheet 引入

由於PHPExcel早就停止更新維護,所以適用phpspreadsheet。不知道如何通過composer拉取專案包的同學,可以檢視Composer學習一文。引入方法:

composer require phpoffice/phpspreadsheet

引入名稱空間

由於本人專案中需要居中、背景、單元格格式等各種操作,所以引入較多,大家使用的時候,可以根據自己實際需要引入。

use PhpOffice\PhpSpreadsheet\Reader\Xlsx;
use PhpOffice\PhpSpreadsheet\Reader\Xls;
use PhpOffice\PhpSpreadsheet\IOFactory;
use PhpOffice\PhpSpreadsheet\Cell\Coordinate;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Worksheet\PageSetup;
use PhpOffice\PhpSpreadsheet\Cell\DataType
; use PhpOffice\PhpSpreadsheet\Style\Fill; use PhpOffice\PhpSpreadsheet\Style\Color; use PhpOffice\PhpSpreadsheet\Style\Alignment; use PhpOffice\PhpSpreadsheet\Style\Border; use PhpOffice\PhpSpreadsheet\Style\NumberFormat;

Excel匯入操作(importExcel)

除了單純的處理Excel資料外,還可以將Excel中的合併項、公式項、單元格格式提取,提取後可根據業務需求做對應處理後儲存起來,以便後續的各種操作。

/**
 * 使用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
 */
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做各種不同的配置,例如列印樣式、鎖定行、背景色、寬度等。

Excel匯出操作(exportExcel)

/**
 * Excel匯出,TODO 可繼續優化
 *
 * @param array  $datas      匯出資料,格式['A1' => 'XXXX公司報表', 'B1' => '序號']
 * @param string $fileName   匯出檔名稱
 * @param array  $options    操作選項,例如:
 *                           bool   print       設定列印格式
 *                           string freezePane  鎖定行數,例如表頭為第一行,則鎖定表頭輸入A2
 *                           array  setARGB     設定背景色,例如['A1', 'C1']
 *                           array  setWidth    設定寬度,例如['A' => 30, 'C' => 20]
 *                           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    儲存路徑,設定後則檔案儲存到伺服器,不通過瀏覽器下載
 */
function exportExcel(array $datas, string $fileName = '', array $options = []): bool
{
    try {
        if (empty($datas)) {
            return false;
        }

        set_time_limit(0);
        /** @var Spreadsheet $objSpreadsheet */
        $objSpreadsheet = app(Spreadsheet::class);
        /* 設定預設文字居左,上下居中 */
        $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) {
                $activeSheet->getColumnDimension($swKey)->setWidth($swItem);
            }

            unset($options['setWidth']);
        }

        /* 設定背景色 */
        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);
            }

            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
            
           

相關推薦

使用PhpSpreadsheet匯入&匯出Excel適用各種Excel操作場景

PHP對Excel匯入&匯出操作 最近公司要做報表功能,各種財務報表、工資報表、考勤報表等,複雜程度讓人頭大,於是特地封裝適用各大場景的匯入&匯出操作,希望各界大神支出不足之處,以便小弟繼續完善。 phpspreadsheet 引入 由於PH

MySQL根據select語句匯入匯出資料含解決中文亂碼方式

所有都親測,不廢話,上程式碼: 匯出 select count(1) from table  into outfile '/tmp/test.xls' character set gbk; 匯入

java poi 匯入匯出多個sheet 的excel資料

首先要使用java poi要匯入相應的jar。匯入:pulic class excelUtil{/**     * 資料匯入到excel     */     public static void importData(filePath){        HSSFWorkbo

Java Excel基於POI利用反射匯入匯出、基於jxls的Excel模板匯出

自述:專案中一直沒有一個好用的Excel匯入匯出功能。所以簡單實現了匯入匯出功能供大家參考匯入功能:基於poi匯入做了一層封裝、支援註解方式標識屬性對應Excel列、並支援簡單規則校驗、具體規則校驗可以根據自己需求自定義兩種匯出功能:一種基於poi的匯出,一種基於jxls模板

ASP.NET 開源匯入匯出庫Magicodes.IE 完成Excel圖片匯入匯出

# Magicodes.IE Excel圖片匯入匯出 為了更好的根據實際功能來迭代,從2.2的里程碑規劃開始,我們將結合社群的建議和意見來進行迭代,您可以點此連結來提交您的意見和建議: https://github.com/dotnetcore/Magicodes.IE/issues/46 ![](htt

讀取超大Excel39萬行數據

display dll rate splay es2017 bsp exce 利用 必須 有個學長需要處理Excel數據,Excel數據共有39W,將數據讀取後處理並導出數據。最開始嘗試了 NPOI ,發現NPOI 並不能完成該項任務,隨後嘗試引用的com組件:M

匯入匯出thunderbird雷鳥中的郵件

作為一名外企的員工,在平時工作中主要使用開源軟體,其中郵件客戶端用的是thunderbird(直譯為雷鳥)。 因為近期要換工作的緣故,所以在離職前遇到一個問題:怎麼把thunderbird中的郵件都給export出來?仁者見仁,這個問題可能有很多種解決辦法,但我在這裡介紹一

Docker之匯入匯出映象第十二篇

   前幾篇文章我們已經學會了怎麼使用第三方線上倉庫和docker提供的倉庫去拉取映象,也學會了自己去製作映象,那怎麼將自己製作的映象匯出來,在別的機器也能執行呢?   首先我們還是使用前幾篇的例子繼續操作,如果還沒有看過的,這裡有一個傳送門《我的Docker啟動jpress

Cassandra 3.0 匯入匯出文字cqlsh+copy

官網資料: 資料檔案 可以是任意分隔符檔案,帶表頭不帶表頭均可,這裡帶表頭了 test.file: c1|c2|c3|value 1|1|1|a 2|2|2|a 建表 建立表空間 CREATE KEYSPACE myks WI

oracle11g 使用資料泵匯入/匯出資料expdp/impdp

目標:使用oracle資料泵,將A電腦上的資料庫databaseA匯出後,再匯入到B電腦上的資料庫databaseB中。 A電腦上的操作(expdp資料匯出): 執行cmd; 登入資料庫,輸入

redis 匯入匯出資料通過redis-cli

針對工作中可能用到 將某臺伺服器中的redis資料 匯出然後匯入到新的伺服器中,一種方法是redis-dump工具,但是 他需要安裝ruby環境,安裝環境的過程中還可能出現意想不到的錯誤。所以不得不選用其他方法了。一下 是幾點思路 供參考。在此謝謝我的同事(yaoer)的

redis樂觀鎖適用於秒殺系統

修改 導致 代碼 -a 通知 解決 redis服務器 font 變化 redis事務中的WATCH命令和基於CAS的樂觀鎖 在Redis的事務中,WATCH命令可用於提供CAS(check-and-set)功能。假設我們通過WATCH命令在事務執行之前監控了多個Keys,

一個成功的 Git 分支模型適用於商業應用開發

還原 如果 功能 角度 想要 允許 chang lai ive 在這篇文章中,我將推廣一下大約一年前我介紹過的一些項目(公私皆有)中使用的開發模型,它們的結果都非常成功。有段時間我非常想寫出來分享一下,但是我至今才抽出時間來。我不會言及任何項目細節,僅討論分支策略和發布管

安卓圓角、背景遮罩。覆蓋實現方式適用於所有控制元件

1.工具類直接用(已經改好) package com.etwod.yulin.t4.unit; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Bitmap;

java根據模板匯出pdf動態增加模板頁數

這兩天碰到了一個根據模板匯出pdf的需求,研究了幾天以後,發現網上的資料不太齊全,主要是沒找到既根據模板匯出,又可以動態增加頁數的例子。只能通過各種資料結合來實現這個需求了(其實是懶得看iText英文文件,這個以後得改過來)。 下面先來說下pdf匯出主要的兩種方

在excl中加入一列並批量匯入mysql資料庫先轉化成Dataframe格式

  現將不含檔案轉成資料幀格式,因為這個格式的檔案蟒中有大量的函式可以對其進行操作。 from datetime import datetime import numpy as np import pandas as pd import pymysql from sqlalchemy

命令列下進入當前目錄的技巧適用於中文Win2000/XP

        使用Windows 系統自帶的“命令提示符”有兩個不便,一是每次進入的都是同一個目錄,還需要用CD 命令進行切換,如果遇到很長的目錄名,輸入起來非常麻 煩。另外,如果目錄名包含中文,輸入起來就是一件比較痛苦的事情了。 如果能在執行“命令提示符”的同時進入指定

Java獲取訪問使用者的客戶端IP地址適用於公網與區域網

  /** * 獲取Ip地址,多級反向代理 * @param request * @return */ public static String getIpaddr(HttpServletRequest request){ String ipAddress = request.ge

【ACM】spfa演算法適用於存在負權

一:演算法描述 求單源最短路的SPFA演算法,是一種可以處理負權邊的演算法。對於存在負權邊,迪傑斯特拉演算法不能使用,但是bellman-ford時間複雜度較高。 簡潔起見,我們約定有向加權圖G不存

一個完整的BDC程式,僅供參考!包括各種引數的配置

BDC的引數我們都比較熟悉了:可能有一個opt我們用得比較少,而且經常有問題的時候我們還需要F1去檢視是否有辦法可以解決。(例如由於commit work導致沒有返回message的) LOOP AT IT_BDC.     PERFORM bdc_dynpro U