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

PHP 陣列轉 CSV 檔案下載與 CSV 讀取完整範例

     編輯:PHP 相關知識

前言

CSV(Comma-Separated Values)是最通用的表格交換格式。PHP 內建 fputcsv、fgetcsv 使得陣列與 CSV 雙向轉換極為簡單。本文提供「陣列寫入 CSV 下載」與「讀取 CSV 解析為陣列」兩個完整、可直接部署的範例,並處理中文編碼、大檔案記憶體優化等實務細節。

一、陣列寫入 CSV 並提供下載

<?php
/**
 * 將二維陣列輸出為 CSV 檔案下載
 * @param array $data  二維陣列,每個子陣列為一列
 * @param string $filename 不含副檔名的檔名
 * @param string $encoding 輸出編碼,預設 big5(Excel 相容),可改 utf-8
 */
function outputCSV(array $data, $filename = 'export', $encoding = 'big5') {
    // 設定下載標頭
    header('Content-Type: text/csv; charset=' . $encoding);
    header('Content-Disposition: attachment; filename="' . $filename . '.csv"');
    header('Pragma: no-cache');
    header('Expires: 0');

    $out = fopen('php://output', 'w');

    // 可選:寫入 BOM,讓 Excel 直接雙擊開啟 UTF-8 不亂碼
    if (strtolower($encoding) === 'utf-8') {
        fwrite($out, "\xEF\xBB\xBF");
    }

    foreach ($data as $row) {
        // 編碼轉換
        if (strtolower($encoding) !== 'utf-8') {
            $row = array_map(function($v) use ($encoding) {
                return iconv('utf-8', $encoding . '//IGNORE', $v);
            }, $row);
        }
        fputcsv($out, $row);
    }
    fclose($out);
    exit; // 避免後續輸出汙染 CSV
}

// ---------- 使用範例 ----------
$data = [
    ['姓名', '性別', '年齡', 'Email', '電話'],
    ['王小明', '男', 28, 'wang@example.com', '0912-345678'],
    ['李小美', '女', 25, 'li@example.com', '0923-456789'],
    ['陳大同', '男', 32, 'chen@example.com', '0934-567890'],
];

outputCSV($data, 'member_list', 'big5'); // 或 'utf-8'

關鍵細節說明

  1. 編碼策略:台灣/香港繁體環境 Excel 預設用 Big5,建議輸出 Big5;若確定使用者用新版 Excel 或 LibreOffice,可輸出 UTF-8 並加 BOM(\xEF\xBB\xBF)。
  2. 串流輸出:fopen('php://output', 'w') 直接寫入 HTTP 回應主體,不佔用暫存檔空間。
  3. 結束腳本:exit 防止框架/模板輸出額外 HTML 破壞 CSV 格式。

二、讀取 CSV 檔案解析為陣列

<?php
/**
 * 讀取 CSV 檔案,回傳關聯式陣列(第一列為欄位名)
 * @param string $filepath CSV 檔案路徑
 * @param string $inputEncoding 檔案編碼,預設 big5
 * @param int $maxLineLen 單行最大長度,0 為不限制(PHP 5.1+)
 * @return array 結構:[ ['欄位1'=>值, '欄位2'=>值, ...], ... ]
 */
function readCSV($filepath, $inputEncoding = 'big5', $maxLineLen = 0) {
    if (!file_exists($filepath) || !is_readable($filepath)) {
        throw new InvalidArgumentException("檔案不存在或不可讀:$filepath");
    }

    $handle = fopen($filepath, 'r');
    if (!$handle) {
        throw new RuntimeException("無法開啟檔案:$filepath");
    }

    $header = null;
    $data = [];
    $lineNum = 0;

    while (($row = fgetcsv($handle, $maxLineLen)) !== false) {
        $lineNum++;
        // 跳過空行
        if (count($row) === 1 && $row[0] === '') continue;

        // 編碼轉為 UTF-8 內部處理
        if (strtolower($inputEncoding) !== 'utf-8') {
            $row = array_map(function($v) use ($inputEncoding) {
                return iconv($inputEncoding, 'utf-8//IGNORE', $v);
            }, $row);
        }

        if ($header === null) {
            $header = $row; // 第一列當標題
            continue;
        }

        // 欄位數不一致時補齊或截斷
        if (count($row) < count($header)) {
            $row = array_pad($row, count($header), '');
        } elseif (count($row) > count($header)) {
            $row = array_slice($row, 0, count($header));
        }

        $data[] = array_combine($header, $row);
    }
    fclose($handle);
    return $data;
}

// ---------- 使用範例 ----------
try {
    $records = readCSV('/path/to/uploaded.csv', 'big5');
    foreach ($records as $rec) {
        // 直接以欄位名存取
        echo "{$rec['姓名']} / {$rec['Email']} / {$rec['電話']}
"; } } catch (Exception $e) { echo '讀取失敗:' . $e->getMessage(); }

進階:大檔案分塊讀取(Generator 版)

若 CSV 超過百 MB,一次載入陣列會爆記憶體。可用 Generator 逐行處理:

function readCSVChunked($filepath, $inputEncoding = 'big5') {
    $handle = fopen($filepath, 'r');
    $header = null;
    while (($row = fgetcsv($handle)) !== false) {
        if (strtolower($inputEncoding) !== 'utf-8') {
            $row = array_map(fn($v) => iconv($inputEncoding, 'utf-8//IGNORE', $v), $row);
        }
        if ($header === null) {
            $header = $row;
            continue;
        }
        yield array_combine($header, $row);
    }
    fclose($handle);
}

// 使用:foreach (readCSVChunked('big.csv') as $row) { ... }

三、常見坑與解法

問題原因解決
Excel 開啟 CSV 中文亂碼編碼不符輸出 Big5 或 UTF-8+BOM
欄位含逗號/換行/雙引號導致欄位錯位未正確逸出用 fputcsv 自動處理,勿手動拼字串
長數字(身分證、卡號)變科學記號Excel 自動偵測數值寫入前加單引號 ' 或用 HTML 表格法 style="vnd.ms-excel.numberformat:@"
fgetcsv 讀到一半停止欄位含未閉合雙引號、換行確認 CSV 產生端正確逸出;必要時自寫解析器
記憶體耗盡大檔一次 file() 或 array_map改用 Generator 逐行處理

總結

  • 寫入:fputcsv + php://output + 編碼轉換 + exit。
  • 讀取:fgetcsv + iconv + 關聯式陣列回傳;大檔用 Generator。
  • 編碼:內部統一 UTF-8,對外依 Excel 環境決定 Big5/UTF-8+BOM。

掌握這兩個函式,即可輕鬆處理 90% 的 CSV 匯入匯出需求,無需引入重型第三方套件。

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