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

PHP 實作 CSV 檔案下載:檔案串流與字串直接輸出兩種模式

     編輯:PHP 相關知識

    核心 HTTP 標頭設定

    無論哪種模式,必須發送正確的回應標頭告訴瀏覽器「這是一個應該下載的檔案」:

    header('Content-Type: application/octet-stream');        // 通用二進位串流
    header('Content-Disposition: attachment; filename="export.csv"'); // 觸發下載並指定檔名
    header('Content-Transfer-Encoding: binary');             // 二進位傳輸
    // Content-Length 僅適用於實體檔案模式

    模式一:讀取實體檔案並串流下載

    <?php
    $filePath = 'data/prefs.csv'; // 伺服器上的實體檔案路徑
    
    if (!is_file($filePath)) {
        http_response_code(404);
        exit('檔案不存在');
    }
    
    // 必須在任何輸出前發送標頭
    header('Content-Type: application/octet-stream');
    header('Content-Disposition: attachment; filename="' . basename($filePath) . '"');
    header('Content-Transfer-Encoding: binary');
    header('Content-Length: ' . filesize($filePath)); // 讓瀏覽器顯示進度條
    
    // 直接輸出檔案內容到輸出緩衝區 (記憶體效率高)
    readfile($filePath);
    exit; // 確保無額外輸出

    模式二:動態產生 CSV 字串直接輸出

    <?php
    // 例如從資料庫查詢組裝 CSV 內容
    $csvData = "ID,Name,Email\n";
    $csvData .= "1,張三,zhang@example.com\n";
    $csvData .= "2,李四,li@example.com\n";
    // ... 迴圈組裝更多行
    
    $fileName = 'export_' . date('Ymd_His') . '.csv';
    
    header('Content-Type: application/octet-stream');
    header('Content-Disposition: attachment; filename="' . $fileName . '"');
    // 動態內容無法預知長度,省略 Content-Length
    // header('Content-Length: ' . strlen($csvData)); // 可選加上
    
    echo $csvData;
    exit;

    進階:大量資料分塊輸出 (避免記憶體耗盡)

    <?php
    $fileName = 'big_export_' . date('Ymd_His') . '.csv';
    
    header('Content-Type: application/octet-stream');
    header('Content-Disposition: attachment; filename="' . $fileName . '"');
    header('Content-Transfer-Encoding: chunked'); // 分塊傳輸編碼
    
    $handle = fopen('php://output', 'w');
    
    // 寫入 BOM (可選,解決 Excel 開啟 UTF-8 亂碼)
    fwrite($handle, "\xEF\xBB\xBF");
    
    // 寫入標題列
    fputcsv($handle, ['ID', '姓名', 'Email', '建立時間']);
    
    // 模擬大量資料分批輸出
    $batchSize = 1000;
    $offset = 0;
    while (true) {
        // $rows = $db->query("SELECT * FROM users LIMIT $batchSize OFFSET $offset")->fetchAll();
        $rows = get_batch_data($offset, $batchSize); // 假設函數
        
        if (empty($rows)) break;
        
        foreach ($rows as $row) {
            fputcsv($handle, $row);
        }
        
        $offset += $batchSize;
        // 可選:flush() 強制輸出到瀏覽器,減少伺服器記憶體壓力
        // flush(); 
    }
    
    fclose($handle);
    exit;
    
    function get_batch_data($offset, $limit) {
        // 實際對接資料庫查詢
        static $dummy = [
            [1, '張三', 'zhang@example.com', '2024-01-01'],
            [2, '李四', 'li@example.com', '2024-01-02'],
        ];
        return array_slice($dummy, $offset, $limit);
    }

    常見問題與解決方案

    問題原因解決
    Excel 開啟中文亂碼缺少 UTF-8 BOM輸出前寫入 \xEF\xBB\xBF 或改用 UTF-16LE 編碼
    下載檔案內容包含 HTML 錯誤頁面標頭前有空白/換行或錯誤輸出確保 <?php 起始標籤前無任何字元,exit 結束腳本
    大檔案下載中斷/記憶體超限一次性讀入記憶體使用 readfile() 或 fopen php://output 分塊輸出
    檔名中文亂碼RFC 5987 編碼問題使用 filename*=UTF-8'' . rawurlencode($name) 格式

    檔名中文相容寫法

    $encodedName = rawurlencode($chineseName);
    header("Content-Disposition: attachment; filename*=UTF-8''{$encodedName}; filename=\"fallback.csv\"");

    掌握這兩種模式與進階技巧,即可滿足從簡單報表到大量資料匯出的各類 CSV 下載需求。

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