首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

PHP 導出 Excel 避坑指南:解決身份證變科學計數法、中文亂碼、數字格式化三大痛點

     編輯:PHP 相關知識

通過設置 Content-Type: application/vnd.ms-excel 輸出 HTML 表格,是 PHP 導出 Excel 最輕量的方式(無需第三方庫)。但直接輸出常遇三大問題:長數字(身份證/銀行卡)自動變科學計數法、中文亂碼、數字/日期/貨幣格式不受控。本文系統講解 Excel 單元格格式化原理,提供完整可用的導出方案。

核心原理:Excel 單元格格式屬性

Excel 讀取 HTML 表格時,會解析 <td> 的 style 屬性中的 vnd.ms-excel.numberformat 格式代碼,決定該單元格的顯示格式。最近的樣式優先級最高(內層 <td> > <tr> > <table>)。

常用格式代碼速查表

用途格式代碼示例輸出
文本(防科學計數法)vnd.ms-excel.numberformat:@410522198402161833
日期vnd.ms-excel.numberformat:yyyy/mm/dd2024/03/15
數字(千分位,2 位小數)vnd.ms-excel.numberformat:#,##0.001,234.56
貨幣vnd.ms-excel.numberformat:¥#,##0.00¥1,234.56
百分比vnd.ms-excel.numberformat:#0.00%12.34%

完整導出腳本

<?php
// export.php
$list = [
    ['user_name' => '張三', 'account_id' => '410522198402161833', 'contact_name' => '李四'],
    ['user_name' => '王五', 'account_id' => '410522199001011234', 'contact_name' => '趙六'],
];

// 1. 設置響應頭
$filename = '會員名_' . date('YmdHis') . '.xls';
// 兼容中文文件名:IE/Edge 用 urlencode,Firefox/Chrome 支持 RFC 5987
$ua = $_SERVER['HTTP_USER_AGENT'] ?? '';
if (preg_match('/MSIE|Trident|Edge/', $ua)) {
    $filename = urlencode($filename);
} else {
    $filename = "utf-8''" . rawurlencode($filename);
}

header("Content-Type: application/vnd.ms-excel; charset=utf-8");
header("Content-Disposition: attachment; filename*=utf-8''" . rawurlencode($filename));
header("Cache-Control: max-age=0");
header("Expires: 0");

// 2. 輸出 HTML 表格(帶 Office 命名空間,增強 Excel 識別度)
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>會員數據</x:Name>
<x:WorksheetOptions>
<x:DisplayGridlines/>
</x:WorksheetOptions>
</x:ExcelWorksheet>
</x:ExcelWorksheets>
</x:ExcelWorkbook>
</xml><![endif]-->
</head>
<body>
<table border="1">
<tr>
<th>會員名</th>
<th>賬號(身份證)</th>
<th>聯系人</th>
</tr>';

foreach ($list as $v) {
    echo '<tr>';
    // 普通文本欄位
    echo '<td>' . htmlspecialchars($v['user_name']) . '</td>';
    // 身份證:強制文本格式,防科學計數法
    echo '<td style="vnd.ms-excel.numberformat:@">' . htmlspecialchars($v['account_id']) . '</td>';
    echo '<td>' . htmlspecialchars($v['contact_name']) . '</td>';
    echo '</tr>';
}

echo '</table></body></html>';

關鍵點深度解析

1. 身份證/長數字防科學計數法

核心:<td style="vnd.ms-excel.numberformat:@">>內容</td>。@ 代表「文本格式」,Excel 將按原樣顯示,不嘗試解析為數字。

補充:若數據極長(>255 字符),Excel 單元格可能截斷,建議業務層面控制長度或改用真實 .xlsx 庫(如 PhpSpreadsheet)。

2. 中文亂碼解決

  • 響應頭:header("Content-Type: application/vnd.ms-excel; charset=utf-8");
  • HTML meta:<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
  • 文件名編碼:使用 RFC 5987 格式 filename*=utf-8''...,兼容現代瀏覽器;舊 IE 用 urlencode。

⚠️ 早期方案常用 iconv('UTF-8', 'GB2312//IGNORE', ...) 強制轉 GB2312,**不推薦**,會導致生僻字丟失,現代 Excel 完美支持 UTF-8。

3. 數字/日期/貨幣格式化

直接在對應 <td> 加入 style="vnd.ms-excel.numberformat:...",如:

<td style="vnd.ms-excel.numberformat:#,##0.00">1234.5</td>       <!-- 顯示 1,234.50 -->
<td style="vnd.ms-excel.numberformat:yyyy-mm-dd">2024-03-15</td> <!-- 顯示 2024-03-15 -->
<td style="vnd.ms-excel.numberformat:¥#,##0">100</td>          <!-- 顯示 ¥100 -->

進階:封裝通用導出類

<?php
class ExcelExporter {
    private array $headers = [];
    private array $rows    = [];
    private string $title  = 'Sheet1';

    public function setTitle(string $title): self {
        $this->title = $title;
        return $this;
    }

    public function setHeaders(array $headers): self {
        $this->headers = $headers; // [['field'=>'id', 'label'=>'ID', 'format'=>'@'], ...]
        return $this;
    }

    public function addRows(array $rows): self {
        $this->rows = $rows;
        return $this;
    }

    public function download(string $filename = ''): void {
        $filename = $filename ?: $this->title . '_' . date('YmdHis') . '.xls';
        $this->sendHeaders($filename);
        $this->outputTable();
        exit;
    }

    private function sendHeaders(string $filename): void {
        $ua = $_SERVER['HTTP_USER_AGENT'] ?? '';
        $encoded = preg_match('/MSIE|Trident|Edge/', $ua) ? urlencode($filename) : "utf-8''" . rawurlencode($filename);
        header("Content-Type: application/vnd.ms-excel; charset=utf-8");
        header("Content-Disposition: attachment; filename*=$encoded");
        header("Cache-Control: max-age=0");
    }

    private function outputTable(): void {
        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"></head><body><table border="1">';

        // 表頭
        echo '<tr>';
        foreach ($this->headers as $h) {
            echo '<th>' . htmlspecialchars($h['label']) . '</th>';
        }
        echo '</tr>';

        // 數據行
        foreach ($this->rows as $row) {
            echo '<tr>';
            foreach ($this->headers as $h) {
                $val = $row[$h['field']] ?? '';
                $style = isset($h['format']) ? ' style="vnd.ms-excel.numberformat:' . $h['format'] . '"' : '';
                echo "<td$style>" . htmlspecialchars($val) . "</td>";
            }
            echo '</tr>';
        }
        echo '</table></body></html>';
    }
}

// 使用示例
$exporter = new ExcelExporter();
$exporter->setTitle('會員導出')
    ->setHeaders([
        ['field' => 'user_name', 'label' => '會員名'],
        ['field' => 'account_id', 'label' => '身份證', 'format' => '@'],
        ['field' => 'contact_name', 'label' => '聯系人'],
    ])
    ->addRows($list)
    ->download('會員名單.xls');

局限性與替代方案

場景HTML 導出PhpSpreadsheet / Box/Spout
純數據導出、簡單格式、無樣式需求✅ 輕量、無依賴、極快⚠️ 依賴大、內存佔用高
需合併儲存格、圖表、圖片、條件格式❌ 不支持✅ 功能全
超大數據量(>5萬行)⚠️ 內存壓力大,需分塊輸出✅ Spout 流式寫入,常駐內存低
.xlsx 格式(現代標準)❌ 僅 .xls (HTML)✅ 原生 .xlsx

總結

HTML 導出 Excel 是「零依賴、極速開發」的利器。掌握 vnd.ms-excel.numberformat 格式代碼、UTF-8 編碼響應頭、文件名 RFC 5987 編碼三大核心,即可解決 90% 導出痛點。複雜報表、大數據量、.xlsx 需求請轉向 PhpSpreadsheet/Spout。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved