在企業級應用開發中,數據導出功能是剛需。本文將詳細解析一個基於 PHP 實現的考核統計導出 Excel 功能,包含核心邏輯代碼與底層 Excel 生成類的完整實現,助你快速掌握服務端生成二進制 .xls 文件的技巧。
daochu() 函數作為入口,主要完成以下流程:
outExcel.class.phpPerformanceServices 服務層獲取考核基本信息與統計數據SimpleExcel 類,寫入標題行、表頭與數據行excelEnd() 輸出文件結尾標記,完成下載function daochu(){
require_once 'outExcel.class.php';
header("Content-Type: application/vnd.ms-excel;charset=utf-8");
$kaoheCode = $_GET['kaoheCode'];
$dao = new PerformanceServices();
$kaoheinfo = $dao->getKaoheInfo($kaoheCode);
$filename = $kaoheinfo['KH_NAME']."考核統計";
// ... 文件名編碼兼容處理 ...
header('Content-Type: application/octet-stream');
// ... 瀏覽器差異化 Content-Disposition ...
header("Pragma: no-cache");
header("Expires: 0");
$dates_excel = $dao->getTongjiInfo($kaoheCode);
$mytime = date("Y-m-d H:i:s", $dates_excel['KH_TIME']);
$excel = new SimpleExcel();
$excel->excelItem(array("統計時間", $mytime));
$excel->excelItem(array("序號", "姓 名", "部門", "分數"));
$excel->colsAttrib(array("1", "a", "a", "1")); // 1=數值型, a=字符型
$scores = explode(',', $dates_excel['KH_SCORES']);
$i = 0;
foreach ($scores as $v) {
$i++;
$r = explode(':', $v);
$userCode = $r[0];
$user = $dao->getUserInfo($userCode);
$dept = $dao->getCellName($userCode);
$excel->excelWrite(array($i, $user['QT_NAME'], $dept, $r[1]));
}
$excel->excelEnd();
}
該類採用 BIFF 格式(Binary Interchange File Format)直接輸出二進制 .xls 文件流,無需依賴 PHPExcel 等重型庫,極其輕量高效。
| 方法 | 功能 | 關鍵點 |
|---|---|---|
| 構造函數 | 輸出 BIFF 文件頭標識 | pack("ssssss", 0x809, 0x8, 0x0, 0x10, 0x0, 0x0) |
| excelItem() | 寫入標題/表頭行 | 逐單元格打包標籤 0x204 (LabelSST) |
| colsAttrib() | 定義列屬性 | 數組值 "1" 表數值,"a" 表字符串 |
| excelWrite() | 寫入數據行 | 根據屬性選擇 0x203 (Number) 或 0x204 (Label) |
| excelEnd() | 輸出 EOF 標記 | pack("ss", 0x0A, 0x00) |
| iconvToData() | 編碼轉換 | UTF-8 → GB2312,確保 Excel 正確顯示中文 |
<?php
class SimpleExcel {
var $rowsNum = 0;
var $attrib = array();
var $in_charset = 'UTF-8';
function SimpleExcel() {
echo pack("ssssss", 0x809, 0x8, 0x0, 0x10, 0x0, 0x0);
return;
}
function excelItem($string = array()) {
for ($i = 0; $i < count($string); $i++) {
$curStr = $this->iconvToData($string[$i]);
$L = strlen($curStr);
echo pack("ssssss", 0x204, 8 + $L, $this->rowsNum, $i, 0x0, $L);
echo $curStr;
}
$this->rowsNum++;
return;
}
function colsAttrib($string = array()) {
$this->attrib = $string;
return;
}
function excelWrite($string = array()) {
for ($i = 0; $i < count($string); $i++) {
$curStr = $this->iconvToData($string[$i]);
if ($this->attrib[$i] == "1") {
echo pack("sssss", 0x203, 14, $this->rowsNum, $i, 0x0);
echo pack("d", $curStr);
} else {
$L = strlen($curStr);
echo pack("ssssss", 0x204, 8 + $L, $this->rowsNum, $i, 0x0, $L);
echo $curStr;
}
}
$this->rowsNum++;
}
function excelEnd() {
echo pack("ss", 0x0A, 0x00);
return;
}
function iconvToData($data) {
return iconv($this->in_charset, 'gb2312', $data);
}
}
?>
iconv('UTF-8', 'GB2312'),否則中文會亂碼;若項目統一 UTF-8,建議改用 UTF-16LE BOM 方案或引入 PhpSpreadsheet。fwrite 分塊寫入臨時文件,或採用生成器模式流式輸出。$_GET['kaoheCode'] 直接用於查詢,務必在 Service 層做參數綁定/白名單校防 SQL 注入。| 方案 | 優點 | 缺點 | 適用場景 |
|---|---|---|---|
| SimpleExcel (本文) | 零依賴、極快、文件極小 | 功能極簡、編碼麻煩、維護成本高 | 極簡導出、舊項目維護 |
| PhpSpreadsheet | 功能全、支持 .xlsx/.ods、活躍維護 | 內存佔用大、速度較慢 | 複雜報表、樣式需求、現代項目 |
| Box/Spout | 流式讀寫、常數內存、速度快 | 不支持圖表/宏、樣式受限 | 大數據導出、高併發場景 |
| Laravel-Excel | 集成優雅、隊列導出、模板支持 | 依賴 Laravel 生態 | Laravel 項目標配 |
本文完整展示了從業務邏輯到底層二進制構造的 Excel 導出實現。雖然 SimpleExcel 在現代項目中已較少直接使用,但其「無依賴、直輸出二進制」的設計思想極具參考價值,適合理解 Excel 文件結構、排查導出亂碼、或在極度受限環境下快速落地。新項目建議優先選擇 PhpSpreadsheet 或 Box/Spout,獲得更好的可維護性與擴展性。