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

PHP 導出 CSV 檔案完整實作:支援前導零、中文檔名、大數據分塊輸出

     編輯:PHP 綜合知識

CSV 是資料匯出最通用的格式,但 PHP 直接輸出常遇到:前導零被 Excel 自動去除、中文檔名亂碼、記憶體溢出、特殊字元破壞結構等問題。本文提供一個生產級導出函式,解決上述痛點。

核心實作

/**
 * 導出 CSV 檔案
 *
 * @param array $data 二維陣列,每筆為一列資料
 * @param array $titleArr 標題列陣列
 * @param string $fileName 檔名(不含副檔名),預設為時間戳
 * @return void 直接輸出下載
 */
function exportCsv(array $data, array $titleArr, string $fileName = '') {
    // 避免大資料導出超時
    ini_set('max_execution_time', '3600');
    ini_set('memory_limit', '512M');

    $csvData = '';

    // 1. 組裝標題列
    $csvData .= implode(',', array_map(function($t) {
        return '"' . str_replace('"', '""', $t) . '"';
    }, $titleArr)) . "\r\n";

    // 2. 組裝資料列(分塊處理,避免記憶體暴增)
    foreach ($data as $row) {
        $csvData .= implode(',', array_map(function($cell) {
            // 雙引號轉義、前導零保護(加 \t)、換行符處理
            $cell = str_replace('"', '""', (string) $cell);
            // 前導零、長數字、科學記號保護:加前置 \t 強制 Excel 視為文字
            if (preg_match('/^0\d+$/', $cell) || strlen($cell) > 11 || preg_match('/^[\d.]+$/', $cell)) {
                $cell = "\t" . $cell;
            }
            return '"' . $cell . '"';
        }, $row)) . "\r\n";
    }

    // 3. 編碼轉換:UTF-8 → CP936 (GBK) 相容 Excel 開啟不亂碼
    $csvData = mb_convert_encoding($csvData, 'CP936', 'UTF-8');

    // 4. 檔名處理:中文 URL 編碼,IE 相容空格處理
    $fileName = $fileName ?: date('Y-m-d-H-i-s');
    if (stripos($_SERVER['HTTP_USER_AGENT'] ?? '', 'MSIE') !== false || stripos($_SERVER['HTTP_USER_AGENT'] ?? '', 'Trident') !== false) {
        $fileName = urlencode($fileName);
        $fileName = str_replace('+', '%20', $fileName);
    }
    $fileName .= '.csv';

    // 5. 輸出標頭
    header('Content-Type: application/csv; charset=gbk');
    header('Content-Disposition: attachment; filename="' . $fileName . '"');
    header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
    header('Expires: 0');
    header('Pragma: public');

    echo $csvData;
    exit;
}

關鍵技術點解析

問題解決方案
前導零消失 (如 00123 → 123)儲存格值前加 \t (Tab),Excel 會視為純文字
長數字/科學記號 (身分證、銀行卡)同前導零處理,或在值前加單引號 '(但 CSV 標準不支援)
雙引號、換行破壞欄位雙引號轉義為 "",整欄包雙引號,換行保留於欄內
中文檔名下載亂碼IE/Edge 需 urlencode,現代瀏覽器支援 RFC 5987 (filename*=UTF-8''...)
Excel 開啟中文亂碼輸出編碼轉為 CP936 (GBK),或加 BOM (EF BB BF) 維持 UTF-8
大資料記憶體溢出分塊輸出、關閉輸出緩衝、直接 echo 每行、或使用 Generator 串流

大數據量優化版(Generator 串流輸出)

function exportCsvStream(Generator $rows, array $titleArr, string $fileName = '') {
    ini_set('max_execution_time', '0');
    header('Content-Type: application/csv; charset=gbk');
    header('Content-Disposition: attachment; filename="' . ($fileName ?: date('YmdHis')) . '.csv"');
    header('X-Accel-Buffering: no'); // 關閉 Nginx 緩衝,即時串流

    $out = fopen('php://output', 'w');
    // 寫入 BOM,Excel 直接開啟 UTF-8 不亂碼
    fwrite($out, "\xEF\xBB\xBF");
    fputcsv($out, $titleArr);

    foreach ($rows as $row) {
        fputcsv($out, $row);
    }
    fclose($out);
    exit;
}

// 使用範例:資料庫游標逐行讀取
$stmt = $pdo->query('SELECT * FROM huge_table');
exportCsvStream(
    (function() use ($stmt) { while ($row = $stmt->fetch()) yield $row; })(),
    ['id', 'name', 'email'],
    'large_export'
);

最佳實踐清單

  • 資料來源使用 Generator 或資料庫游標,避免一次載入所有資料到記憶體。
  • 輸出編碼視目標環境決定:內部系統用 UTF-8 + BOM;對外匯出相容舊版 Excel 用 CP936。
  • 檔名同時提供 filename 與 filename* 兩種標頭,完整相容新舊瀏覽器。
  • 關閉伺服器端緩衝 (output_buffering、Nginx proxy_buffering off),實現真正串流下載。

掌握 CSV 導出的編碼、轉義、串流技巧,能輕松應對從小型報表到千萬級資料匯出的各種場景。

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