在後台管理、數據報表、用戶導出等場景中,將數據導出為 Excel 是高頻需求。PHP 原生不支持直接生成 .xls/.xlsx,常見方案有:HTML 表格偽裝、PHPExcel/PhpSpreadsheet 庫、CSV 格式。本文提供兩種**零依賴、即插即用**的完整代碼方案,專門解決中文編碼亂碼、長數字科學計數法、大數據導出性能等痛點。
原理:輸出帶有 Office XML 命名空間的 HTML 表格,瀏覽器/Excel 識別為 .xls 文件。無需第三方庫,支持樣式、合併單元格、凍結窗格等基礎功能。
<?php
class ToExcel {
/**
* 導出 Excel
* @param array $mapping 表頭映射 ['編號','姓名','郵箱','年齡']
* @param array $dataList 數據二維數組 [[1,'張三','zhang@example.com',25], ...]
* @param string $fileName 文件名(不含副檔名)
*/
public function toExcel($mapping, $dataList, $fileName) {
// 1. 設置響應頭:強制下載、指定文件名(中文需轉 GB2312 避免瀏覽器亂碼)
header("Content-Type: application/vnd.ms-excel");
header("Content-Disposition: attachment; filename=" . iconv('UTF-8', 'GB2312', $fileName) . ".xls");
header("Pragma: no-cache");
header("Expires: 0");
// 2. 輸出 HTML + Office XML 命名空間
echo '<html xmlns:o="urn:schemas-microsoft-com:office:office"
xmlns:x="urn:schemas-microsoft-com:office:excel"
xmlns="https://www.w3.org/TR/REC-html40">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<!--[if gte mso 9]><xml>
<x:ExcelWorkbook>
<x:ExcelWorksheets>
<x:ExcelWorksheet>
<x:Name>Sheet1</x:Name>
<x:WorksheetOptions>
<x:DisplayGridlines/>
<x:Print>
<x:ValidPrinterInfo/>
</x:Print>
</x:WorksheetOptions>
</x:ExcelWorksheet>
</x:ExcelWorksheets>
</x:ExcelWorkbook>
</xml><![endif]-->
</head>
<body>';
// 3. 表頭
echo '<table border="1" cellspacing="0" cellpadding="3"><tr>';
foreach ($mapping as $col) {
echo '<th style="background:#0066CC;color:#fff;font-weight:bold;">' . htmlspecialchars($col) . '</th>';
}
echo '</tr>';
// 4. 數據行
foreach ($dataList as $row) {
echo '<tr>';
foreach ($row as $key => $val) {
// 長數字(≥14位,如身份證、銀行卡)強制文本格式,防科學計數法
if (is_numeric($val) && strlen($val) >= 14) {
echo '<td style="vnd.ms-excel.numberformat:@">' . htmlspecialchars($val) . '</td>';
} else {
echo '<td>' . htmlspecialchars($val) . '</td>';
}
}
echo '</tr>';
}
echo '</table></body></html>';
}
}
// === 使用示例 ===
$map = ['編號', '姓名', '郵箱'];
$data = [
[1, '管理員', 'admin@example.com'],
[2, '會員', 'member@example.com'],
[3, '測試用戶', 'test12345678901234@example.com'], // 長數字測試
];
$excel = new ToExcel();
$excel->toExcel($map, $data, '用戶列表_' . date('YmdHis'));
?>
iconv('UTF-8','GB2312',$fileName) 解決中文文件名在 IE/Edge 下載亂碼。style="vnd.ms-excel.numberformat:@" 強制 Excel 以文本顯示,避免身份證號變科學計數法。htmlspecialchars() 防止數據中含 < > & 破壞結構。原理:直接輸出 Tab (\t) 分隔、換行 (\n) 的純文本,Excel 打開自動識別列。無 HTML 開銷,內存佔用極低,速度最快。
<?php
header("Content-Type: application/vnd.ms-excel");
header("Content-Disposition: attachment; filename=数据导出_" . date('YmdHis') . ".xls");
header("Pragma: no-cache");
header("Expires: 0");
// 模擬大數據流式輸出(不佔內存)
$handle = fopen('php://output', 'w');
// 表頭
$header = ['編號', '姓名', '郵箱', '註冊時間'];
// 寫入 BOM 防 UTF-8 無 BOM 導致 Excel 亂碼
fwrite($handle, chr(0xEF).chr(0xBB).chr(0xBF));
fputcsv($handle, $header, "\t"); // 使用 Tab 分隔
// 模擬分批查詢輸出
for ($i = 1; $i <= 100000; $i++) {
$row = [
$i,
"用戶{$i}",
"user{$i}@example.com",
date('Y-m-d H:i:s', strtotime("-$i days"))
];
fputcsv($handle, $row, "\t");
// 每 1000 行刷新一次,避免內存堆積
if ($i % 1000 === 0) fflush($handle);
}
fclose($handle);
?>
| 特性 | 方案一 HTML 偽裝 | 方案二 Tab 文本流 |
|---|---|---|
| 中文支持 | 優(需 iconv 文件名) | 優(需 UTF-8 BOM) |
| 樣式/合併儲存格 | 支持 | 不支持 |
| 長數字文本化 | 支持 | 需在 Excel 導入時指定列格式 |
| 性能/內存 | 中等(<5萬行) | 極高(百萬行秒級) |
| 依賴 | 零依賴 | 零依賴 |
| 適用場景 | 後台導出、帶樣式報表 | 大數據導出、日志導出、定時任務 |
若需:多工作表、圖表、公式、條件格式、圖片嵌入、.xlsx 格式,請使用官方維護的 PhpSpreadsheet(原 PHPExcel 繼任者)。
composer require phpoffice/phpspreadsheet
但注意:PhpSpreadsheet 將所有數據載入內存,**百萬行級會 OOM**,需配合 CellCaching 或分塊寫入技巧。
根據業務場景選擇合適方案,即可輕鬆解決 PHP 導出中文 Excel 的所有痛點。