getActiveSheet(); // 开始写入内容 $sheetIndex = 0; foreach ($list as $sheetTitle => $sheetListItem) { if ($sheetIndex > 0) { $spreadsheet->createSheet(); $sheet = $spreadsheet->getSheet($sheetIndex); } $sheet->setTitle($sheetTitle); // 从第几行开始写入 $column = 2; // 写入头部 $hk = 1; foreach ($header as $k => $v) { $sheet->setCellValue(Coordinate::stringFromColumnIndex($hk) . '1', $v[0]); $sheet->getStyle(Coordinate::stringFromColumnIndex($hk) . '1')->getFont()->setBold(true); $sheet->getColumnDimension(Coordinate::stringFromColumnIndex($hk))->setAutoSize(true); $hk += 1; } $size = ceil(count($sheetListItem) / 500); for ($i = 0; $i < $size; $i++) { $buffer = array_slice($sheetListItem, $i * 500, 500); foreach ($buffer as $k => $row) { $span = 1; foreach ($header as $key => $value) { // 解析字段 $realData = self::formatting($header[$key], trim(self::formattingField($row, $value[1])), $row); // 写入excel $sheet->setCellValueExplicit(Coordinate::stringFromColumnIndex($span) . $column, $realData, DataType::TYPE_STRING); // $sheet->setCellValue(Coordinate::stringFromColumnIndex($span) . $column, $realData); $span++; } $column++; unset($buffer[$k]); } } $sheetIndex++; } // 清除之前的错误输出 // ob_end_clean(); ob_start(); // 直接输出下载 switch ($suffix) { case 'xlsx' : $writer = new Xlsx($spreadsheet); if (!empty($path)) { $writer->save($path); } else { // 2. 保存到内存(使用 php://memory) $tempFile = 'php://memory'; $stream = fopen($tempFile, 'w+'); $writer->save($stream); rewind($stream); $excelOutput = stream_get_contents($stream); fclose($stream); // 3. 返回给客户端下载 return $response->withHeader('Content-Type', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet') ->withHeader('Content-Disposition', 'attachment; filename=' . $filename . '.xlsx') ->withHeader('Cache-Control', 'max-age=0') ->raw($excelOutput); } break; case 'xls' : $writer = new Xls($spreadsheet); if (!empty($path)) { $writer->save($path); } else { header("Content-Type:application/vnd.ms-excel;charset=utf-8;"); header("Content-Disposition:inline;filename=\"{$filename}.xls\""); header('Cache-Control: max-age=0'); $writer->save('php://output'); } break; case 'csv' : $writer = new Csv($spreadsheet); if (!empty($path)) { $writer->save($path); } else { header("Content-type:text/csv;charset=utf-8;"); header("Content-Disposition:attachment; filename={$filename}.csv"); header('Cache-Control: max-age=0'); $writer->save('php://output'); } break; case 'html' : $writer = new Html($spreadsheet); if (!empty($path)) { $writer->save($path); } else { header("Content-Type:text/html;charset=utf-8;"); header("Content-Disposition:attachment;filename=\"{$filename}.{$suffix}\""); header('Cache-Control: max-age=0'); $writer->save('php://output'); } break; } /* 释放内存 */ $spreadsheet->disconnectWorksheets(); unset($spreadsheet); $content = ob_end_flush(); // 创建一个临时流,并将内容写入其中 $tempStream = fopen('php://temp', 'r+'); if ($tempStream === false) { throw new \RuntimeException('Unable to open temporary stream'); } fwrite($tempStream, $content); rewind($tempStream); // $response = new Response(); $contentType = 'text/csv'; return $response->withHeader('content-description', 'File Transfer') ->withHeader('content-type', $contentType) ->withHeader('content-disposition', "attachment; filename=text.xlsx") ->withHeader('content-transfer-encoding', 'binary') ->withHeader('pragma', 'public') ->withBody(new SwooleStream($content)); return $response->withHeader('Content-Type', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet') ->withHeader('Content-Disposition', 'attachment; filename="exported_file.xlsx"') ->withBody(new \GuzzleHttp\Psr7\Stream($tempStream)); // exit(); } /** * 导出的另外一种形式(不建议使用) * * @param array $list * @param array $header * @param string $filename * @return bool */ public static function exportCsvData($list = [], $header = [], $filename = '') { if (!is_array($list) || !is_array($header)) { return false; } // 清除之前的错误输出 ob_end_clean(); ob_start(); !$filename && $filename = time(); $html = "\xEF\xBB\xBF"; foreach ($header as $k => $v) { $html .= $v[0] . "\t ,"; } $html .= "\n"; if (!empty($list)) { $info = []; $size = ceil(count($list) / 500); for ($i = 0; $i < $size; $i++) { $buffer = array_slice($list, $i * 500, 500); foreach ($buffer as $k => $row) { $data = []; foreach ($header as $key => $value) { // 解析字段 $realData = self::formatting($header[$key], trim(self::formattingField($row, $value[1])), $row); $data[] = '"' . $realData . '"'; } $info[] = implode("\t ,", $data) . "\t ,"; unset($data, $buffer[$k]); } } $html .= implode("\n", $info); } header("Content-type:text/csv"); header("Content-Disposition:attachment; filename={$filename}.csv"); echo $html; exit(); } /** * 导入 * * @param $filePath * @param int $startRow * @return array|mixed * @throws Exception * @throws \PhpOffice\PhpSpreadsheet\Exception * @throws \PhpOffice\PhpSpreadsheet\Reader\Exception */ public static function import($filePath, $startRow = 1) { $reader = new \PhpOffice\PhpSpreadsheet\Reader\Xlsx(); $reader->setReadDataOnly(true); if (!$reader->canRead($filePath)) { $reader = new \PhpOffice\PhpSpreadsheet\Reader\Xls(); // setReadDataOnly Set read data only 只读单元格的数据,不格式化 e.g. 读时间会变成一个数据等 $reader->setReadDataOnly(true); if (!$reader->canRead($filePath)) { throw new Exception('不能读取Excel'); } } $spreadsheet = $reader->load($filePath); $sheetCount = $spreadsheet->getSheetCount();// 获取sheet的数量 // 获取所有的sheet表格数据 $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++) { $val = $currentSheet->getCellByColumnAndRow($currentColumn, $currentRow)->getValue(); $arr[$currentRow][] = trim($val); } // $arr[$currentRow] = array_filter($arr[$currentRow]); // 统计连续空行 if (empty($arr[$currentRow]) && $emptyRowNum <= 50) { $emptyRowNum++; } else { $emptyRowNum = 0; } // 防止坑队友的同事在excel里面弄出很多的空行,陷入很漫长的循环中,设置如果连续超过50个空行就退出循环,返回结果 // 连续50行数据为空,不再读取后面行的数据,防止读满内存 if ($emptyRowNum > 50) { break; } } $excleDatas[$i] = $arr; // 多个sheet的数组的集合 } // 这里我只需要用到第一个sheet的数据,所以只返回了第一个sheet的数据 $returnData = $excleDatas ? array_shift($excleDatas) : []; // 第一行数据就是空的,为了保留其原始数据,第一行数据就不做array_fiter操作; $returnData = $returnData && isset($returnData[$startRow]) && !empty($returnData[$startRow]) ? array_filter($returnData) : $returnData; return $returnData; } /** * 格式化内容 * * @param array $array 头部规则 * @return false|mixed|null|string 内容值 */ protected static function formatting(array $array, $value, $row) { !isset($array[2]) && $array[2] = 'text'; switch ($array[2]) { // 文本 case 'text' : return $value; break; // 日期 case 'date' : return !empty($value) ? date($array[3], $value) : null; break; // 选择框 case 'selectd' : return $array[3][$value] ?? null; break; // 匿名函数 case 'function' : return isset($array[3]) ? call_user_func($array[3], $row) : null; break; // 默认 default : break; } return null; } /** * 解析字段 * * @param $row * @param $field * @return mixed */ protected static function formattingField($row, $field) { $newField = explode('.', $field); if (count($newField) == 1) { return $row[$field] ?? ''; } foreach ($newField as $item) { if (isset($row[$item])) { $row = $row[$item]; } else { break; } } return is_array($row) ? false : $row; } }