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

PHP 將數據寫入 CSV 文件的完整實現與避坑指南

     編輯:PHP 相關知識

從數據源到 CSV 導出:fputcsv 實戰與編碼、換行、大文件處理

CSV 導出是後台管理系統、報表系統的高頻功能。看似簡單的 fputcsv(),實際落地時常遇到中文亂碼、換行符不一致、內存溢出、Excel 打開欄位錯位等問題。本文通過重構示例代碼,給出生產級導出方案。

原始代碼問題分析

<?php
// 原代碼存在的問題:
// 1. 硬編碼文件名、行數限制 1838 行
// 2. 直接操作 $item[0]..$item[3] 假設固定列數,極易越界
// 3. 無 BOM 頭,Excel 直接打開中文亂碼
// 4. 未處理字段內含逗號、雙引號、換行符的轉義
// 5. 全量讀入內存,大文件導致 OOM

生產級導出類封裝

<?php
class CsvExporter
{
    private $handle;
    private string $filename;
    private int $bufferSize = 1000; // 緩衝行數
    private array $buffer = [];
    private int $count = 0;

    public function __construct(string $filename, array $headers = [])
    {
        $this->filename = $filename;
        // 以追加模式打開,自動創建
        $this->handle = fopen($filename, 'w');
        if (!$this->handle) {
            throw new RuntimeException("無法創建文件: $filename");
        }
        // 寫入 UTF-8 BOM,修復 Excel 亂碼
        fwrite($this->handle, "\xEF\xBB\xBF");
        if ($headers) {
            $this->writeRow($headers);
        }
    }

    public function writeRow(array $row): void
    {
        $this->buffer[] = $row;
        if (count($this->buffer) >= $this->bufferSize) {
            $this->flush();
        }
    }

    public function flush(): void
    {
        foreach ($this->buffer as $row) {
            fputcsv($this->handle, $row);
        }
        $this->buffer = [];
    }

    public function __destruct()
    {
        $this->flush();
        if (is_resource($this->handle)) {
            fclose($this->handle);
        }
    }

    public function getRowCount(): int
    {
        return $this->count;
    }
}

業務調用示例

<?php
// 模擬從數據庫分批讀取(生成器/PDOStatement fetchAll 分頁)
$exporter = new CsvExporter('export_orders_' . date('YmdHis') . '.csv', [
    '訂單號', '用戶ID', '商品名', '金額', '下單時間'
]);

// 假設 $pdo 為 PDO 實例
$stmt = $pdo->query("SELECT order_no, user_id, goods_name, amount, created_at FROM orders WHERE status=1");
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
    $exporter->writeRow([
        $row['order_no'],
        $row['user_id'],
        $row['goods_name'],
        $row['amount'],
        $row['created_at']
    ]);
}
// 析構函數自動 flush & close
echo "導出完成,共 {$exporter->getRowCount()} 行。";

核心避坑清單

問題原因解決方案
Excel 打開中文亂碼缺少 UTF-8 BOMfwrite($fp, "\xEF\xBB\xBF") 在寫入首行前
字段含逗號/換行/雙引號導致列錯位CSV 格式要求包含分隔符的字段必須雙引號包裹且內部雙引號轉義fputcsv() 內部已自動處理,勿自行拼接字符串
大數據導出內存溢出一次性 fetchAll 或併發寫入分批游標讀取 + 緩衝寫入(如上類)
數字科學計數法/前導零丟失Excel 自動識別數值格式字段前加 \t 或 ='value' 強制文本格式
換行符不一致(Windows CRLF vs Linux LF)跨平台查看差異fopen 模式用 'w' 由 PHP 自動轉換為系統默認;或指定 'c' 模式手動控制

進階擴展建議

  • 流式下載:導出超大文件時,直接 fopen('php://output', 'w') 配合 header('Content-Type: text/csv') 邊生成邊輸出,不落盤。
  • 多 Sheet 需求:CSV 不支援多工作表,需改用 PhpSpreadsheet 導出真正的 .xlsx。
  • 並發導出:生成唯一文件名(UUID+時間戳),記錄任務狀態表,前端輪詢下載鏈接。

掌握 fputcsv 的正確姿勢,加上 BOM、緩衝、流式輸出三板斧,CSV 導出功能即可穩定支撐百萬級數據業務。

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