需要在请求结束时清理的临时文件 */ protected static $tempFiles = []; /** * 导出 Excel(支持指定列插入图片) * * @param string $fileName 输出文件名(可不带扩展名) * @param array $headers 列定义,例如 ['name' => '姓名', 'phone' => '电话'] * @param array $rows 数据行,需与 $headers 的 key 对应 * @param array $imageColumns 需要渲染为图片的列 key 列表 * @param string $sheetName 工作表名称 * * @throws Exception */ public static function exportExcelWithImages( $fileName, array $headers, array $rows, array $imageColumns = [], $sheetName = 'Sheet1' ) { if (empty($headers)) { throw new Exception('导出列定义不能为空'); } if (empty($rows)) { throw new Exception('导出数据不能为空'); } $excel = new PHPExcel(); $sheet = $excel->getActiveSheet(); $sheet->setTitle($sheetName); $columnKeys = array_keys($headers); // 写入表头 foreach ($columnKeys as $index => $key) { $columnLetter = self::columnLetter($index); $sheet->setCellValue($columnLetter . '1', $headers[$key]); $sheet->getColumnDimension($columnLetter)->setAutoSize(true); } // 写入数据与图片 foreach ($rows as $rowIndex => $rowData) { $excelRow = $rowIndex + 2; // 数据从第 2 行开始 foreach ($columnKeys as $colIndex => $key) { $columnLetter = self::columnLetter($colIndex); $cell = $columnLetter . $excelRow; $value = isset($rowData[$key]) ? $rowData[$key] : ''; if (in_array($key, $imageColumns, true) && !empty($value)) { $imagePath = self::resolveImagePath($value); if ($imagePath) { $drawing = new PHPExcel_Worksheet_Drawing(); $drawing->setPath($imagePath); $drawing->setCoordinates($cell); $drawing->setOffsetX(5); $drawing->setOffsetY(5); $drawing->setHeight(60); $drawing->setWorksheet($sheet); $sheet->getRowDimension($excelRow)->setRowHeight(60); } else { $sheet->setCellValue($cell, $value); } } else { $sheet->setCellValue($cell, $value); } } } $safeName = preg_replace('/[^\w\-]/', '_', $fileName ?: 'export_' . date('Ymd_His')); if (stripos($safeName, '.xlsx') === false) { $safeName .= '.xlsx'; } if (ob_get_length()) { ob_end_clean(); } header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'); header('Cache-Control: max-age=0'); header('Content-Disposition: attachment;filename="' . $safeName . '"'); $writer = PHPExcel_IOFactory::createWriter($excel, 'Excel2007'); $writer->save('php://output'); self::cleanupTempFiles(); exit; } /** * 根据列序号生成 Excel 列字母 * * @param int $index * @return string */ protected static function columnLetter($index) { $letters = ''; do { $letters = chr($index % 26 + 65) . $letters; $index = intval($index / 26) - 1; } while ($index >= 0); return $letters; } /** * 将远程或本地图片路径转换为可用的本地文件路径 * * @param string $path * @return string|null */ protected static function resolveImagePath($path) { if (empty($path)) { return null; } if (preg_match('/^https?:\/\//i', $path)) { $tempFile = tempnam(sys_get_temp_dir(), 'export_img_'); $stream = @file_get_contents($path); if ($stream === false) { return null; } file_put_contents($tempFile, $stream); self::$tempFiles[] = $tempFile; return $tempFile; } if (file_exists($path)) { return $path; } return null; } /** * 清理所有临时文件 */ protected static function cleanupTempFiles() { foreach (self::$tempFiles as $file) { if (file_exists($file)) { @unlink($file); } } self::$tempFiles = []; } }