`header("Content-Disposition: attachment")` 只能觸發瀏覽器下載,**無法直接保存到服務器指定目錄**。需先生成文件對象,再調用保存方法寫入磁盤。
composer require phpoffice/phpspreadsheet
PHPExcel 已停止維護 (2017),PhpSpreadsheet 支援 PHP 7.1+、更快、功能更全、命名空間規範。
<?php
require 'vendor/autoload.php';
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
use PhpOffice\PhpSpreadsheet\Style\Alignment;
use PhpOffice\PhpSpreadsheet\Style\Border;
use PhpOffice\PhpSpreadsheet\Style\Fill;
use PhpOffice\PhpSpreadsheet\Style\Font;
function generateExcelReport(array $data, string $savePath, string $title = '報表'): bool {
try {
$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();
$sheet->setTitle($title);
// 1. 設置表頭
$headers = ['ID', '姓名', '部門', '薪資', '入職日期'];
$sheet->fromArray($headers, null, 'A1');
// 表頭樣式
$headerStyle = [
'font' => ['bold' => true, 'color' => ['rgb' => 'FFFFFF'], 'size' => 12],
'fill' => ['fillType' => Fill::FILL_SOLID, 'startColor' => ['rgb' => '4472C4']],
'alignment' => ['horizontal' => Alignment::HORIZONTAL_CENTER],
'borders' => ['allBorders' => ['borderStyle' => Border::BORDER_THIN, 'color' => ['rgb' => '000000']]],
];
$sheet->getStyle('A1:E1')->applyFromArray($headerStyle);
// 2. 填充數據 (從第 2 行開始)
$sheet->fromArray($data, null, 'A2');
// 數據行樣式
$lastRow = count($data) + 1;
$dataStyle = [
'alignment' => ['horizontal' => Alignment::HORIZONTAL_CENTER],
'borders' => ['allBorders' => ['borderStyle' => Border::BORDER_THIN, 'color' => ['rgb' => 'CCCCCC']]],
];
$sheet->getStyle("A2:E{$lastRow}")->applyFromArray($dataStyle);
// 3. 自動列寬
foreach (range('A', 'E') as $col) {
$sheet->getColumnDimension($col)->setAutoSize(true);
}
// 4. 凍結首行
$sheet->freezePane('A2');
// 5. 保存到指定路徑
$writer = new Xlsx($spreadsheet);
$writer->save($savePath);
// 釋放內存
$spreadsheet->disconnectWorksheets();
unset($spreadsheet);
return true;
} catch (Exception $e) {
error_log("Excel 生成失敗: " . $e->getMessage());
return false;
}
}
// 使用示例
$data = [
[1, '張三', '技術部', 15000, '2020-01-15'],
[2, '李四', '市場部', 12000, '2021-03-22'],
[3, '王五', '技術部', 18000, '2019-07-01'],
];
$saveDir = __DIR__ . '/exports/';
if (!is_dir($saveDir)) mkdir($saveDir, 0755, true);
$fileName = 'employee_report_' . date('Ymd_His') . '.xlsx';
$fullPath = $saveDir . $fileName;
if (generateExcelReport($data, $fullPath, '員工薪資表')) {
echo "生成成功: {$fullPath}";
// 可選:記錄數據庫、發送郵件、推送通知...
} else {
echo "生成失敗";
}
?>
<?php
use PhpOffice\PhpSpreadsheet\Worksheet\Drawing;
$drawing = new Drawing();
$drawing->setName('公司Logo');
$drawing->setDescription('Logo');
$drawing->setPath(__DIR__ . '/assets/logo.png'); // 本地圖片路徑
$drawing->setHeight(60); // 高度 (寬度自動按比例)
$drawing->setCoordinates('A1'); // 插入位置
$drawing->setOffsetX(10); // 微調
$drawing->setWorksheet($sheet);
// 也可插入 URL 圖片 (需開啟 allow_url_fopen)
// $drawing->setPath('https://example.com/logo.png');
?>
<?php
function exportLargeDataset(Generator $dataGen, string $savePath, int $chunkSize = 1000): bool {
$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();
// 寫入表頭
$sheet->fromArray(['ID', '數據'], null, 'A1');
$row = 2;
foreach ($dataGen as $record) {
$sheet->fromArray([$record], null, "A{$row}");
$row++;
// 定期刷新到磁盤 (需自定義 Writer 或分多個文件)
if ($row % 5000 === 0) {
// PhpSpreadsheet 無原生流式寫入,大數據建議:
// 1. 分多個文件 (employee_part_1.xlsx, part_2.xlsx...)
// 2. 改用 CSV (fputcsv) 內存極低
// 3. 使用 Box/Spout 流式庫
}
}
$writer = new Xlsx($spreadsheet);
$writer->save($savePath);
return true;
}
// CSV 大數據導出示例 (推薦)
function exportCsv(Generator $dataGen, string $savePath): bool {
$fp = fopen($savePath, 'w');
fputcsv($fp, ['ID', '數據']); // 表頭
foreach ($dataGen as $record) {
fputcsv($fp, $record);
}
fclose($fp);
return true;
}
?>
| 格式 | Writer 類 | 適用場景 | 最大行數 |
|---|---|---|---|
| XLSX (OOXML) | Xlsx | 現代標準、樣式豐富、公式支援 | 1,048,576 |
| XLS (BIFF) | Xls | 舊系統兼容 | 65,536 |
| CSV | Csv | 大數據、純文本、跨語言、無樣式 | 無限制 (受限於文件系統) |
| ODS | Ods | OpenDocument、LibreOffice | 1,048,576 |
| HTML | Html | 網頁預覽、郵件內嵌 | - |
| Mpdf / Dompdf (需額外庫) | 打印、歸檔 | - |
使用 PhpSpreadsheet 可輕鬆實現 Excel 生成、樣式、圖片插入、保存到指定目錄。關鍵步驟:創建 Spreadsheet → 填充數據/樣式 → 實例化 Writer → `save($path)`。大數據場景請改用 CSV 或流式庫。舊代碼中的 `PHPExcel` 類名需更新為對應的 PhpSpreadsheet 命名空間類。