需求:Excel表格是學校的很多信息,包括基本信息,專業信息等,有多個sheet;需以此表格爲依據導入到數據庫生成一個學校;或者更新一個學校的信息;
難點: Excel表格中 學校的logo 是圖片;是jpg,png,等格式;png格式是 如何正確獲取到這張圖片。
使用的第三方處理excel表格的庫爲:
\PhpOffice\PhpSpreadsheet
代碼:
public static function importExcelWithImage($filePath, $startRow = 1)
{
$reader = new \PhpOffice\PhpSpreadsheet\Reader\Xlsx();
if (!$reader->canRead($filePath))
{
$reader = new \PhpOffice\PhpSpreadsheet\Reader\Xls();
// setReadDataOnly Set read data only 只讀單元格的數據,不格式化 e.g. 讀時間會變成一個數據等
if (!$reader->canRead($filePath))
{
throw new NotFoundHttpException('不能讀取Excel');
}
}
$spreadsheet = $reader->load($filePath);
$sheetCount = $spreadsheet->getSheetCount();// 獲取sheet的數量
// 獲取所有的sheet表格數據
$images = [];
$excleDatas = [];
$emptyRowNum = 0;
for ($i = 0; $i < $sheetCount; $i++)
{
$currentSheet = $spreadsheet->getSheet($i); // 讀取excel文件中的第一個工作表
$allColumn = $currentSheet->getHighestColumn(); // 取得最大的列號
$allColumn = Coordinate::columnIndexFromString($allColumn); // 由列名轉爲列數('AB'->28)
$allRow = $currentSheet->getHighestRow(); // 取得一共有多少行
$arr = [];
for ($currentRow = $startRow; $currentRow <= $allRow; $currentRow++)
{
// 從第1列開始輸出
for ($currentColumn = 1; $currentColumn <= $allColumn; $currentColumn++)
{
$cellObj = $currentSheet->getCellByColumnAndRow($currentColumn, $currentRow);
$type = $cellObj->getDataType();
$val = $cellObj->getValue();
$arr[$currentRow][] = trim($val);
}
// $arr[$currentRow] = array_filter($arr[$currentRow]);
// 統計連續空行
if (empty($arr[$currentRow]) && $emptyRowNum <= 50)
{
$emptyRowNum++ ;
}
else
{
$emptyRowNum = 0;
}
// 連續50行數據爲空,不再讀取後面行的數據,防止讀滿內存
if ($emptyRowNum > 50)
{
break;
}
}
//開始處理圖片
foreach ($currentSheet->getDrawingCollection() as $drawing) {
if ($drawing instanceof MemoryDrawing) {
switch ($drawing->getMimeType()) {
case MemoryDrawing::MIMETYPE_PNG :
$extension = 'png';
break;
case MemoryDrawing::MIMETYPE_GIF :
$extension = 'gif';
break;
case MemoryDrawing::MIMETYPE_JPEG :
$extension = 'jpg';
break;
}
$gdRes = $drawing->getImageResource();
ob_start();
if($extension == 'png'){
//設置透明
imagesavealpha($gdRes,true);
}
call_user_func(
$drawing->getRenderingFunction(),
$gdRes //$drawing->getImageResource()
);
$imageContents = ob_get_contents();
ob_end_clean();
} else {
$zipReader = fopen($drawing->getPath(), 'r');
$imageContents = '';
while (!feof($zipReader)) {
$imageContents .= fread($zipReader, 1024);
}
fclose($zipReader);
$extension = $drawing->getExtension();
}
//列從 0開始,行從1開始 和數據保持一致
list($imageStartColumn, $imageStartRow) = Coordinate::coordinateFromString($drawing->getCoordinates());
$imageStartColumn = Coordinate::columnIndexFromString($imageStartColumn) -1 ;
$folder_name = sys_get_temp_dir();
$myFileName = time() . '_' . mt_rand(100000, 999999) . '.' . $extension;
$images[] = $arr[$imageStartRow][$imageStartColumn] = $folder_name.'/'.$myFileName;
file_put_contents("{$folder_name}/{$myFileName}", $imageContents);
}
$excleDatas[$i] = $arr; // 多個sheet的數組的集合
}
return array('data' => $excleDatas, 'images' => $images);
}
注意的地方:
$reader = new \PhpOffice\PhpSpreadsheet\Reader\Xls(); // setReadDataOnly Set read data only 只讀單元格的數據,不格式化 e.g. 讀時間會變成一個數據等
不要對 $read 進行 setReadDataOnly的設置爲true 這樣做會使下邊無法獲取到圖片資源,也會對時間等內容產生影響;
難點的解決代碼:
$gdRes = $drawing->getImageResource();
ob_start();
if($extension == 'png'){
//設置透明
imagesavealpha($gdRes,true);
}
解決的思路:
1. 查看PhpSpreadsheet 的文檔查找對 png格式特殊處理的函數;結果沒有找到!
2. 斷點調試代碼打印 $gdRes 對象;結果發現它就是 gd庫的圖片資源類型;這就說明可以使用原始的gd庫的方法 imagesavealpha()來設置透明瞭