function exportCsvDownload(array $data, array $headers, string $filename = '') {
// 設定標頭
$filename = $filename ?: date('YmdHis');
if (stripos($_SERVER['HTTP_USER_AGENT'], 'MSIE') !== false || stripos($_SERVER['HTTP_USER_AGENT'], 'Trident') !== false) {
$filename = urlencode($filename);
$filename = str_replace('+', '%20', $filename);
}
header("Content-Type: text/csv; charset=UTF-8");
header("Content-Disposition: attachment; filename=\"{$filename}.csv\"");
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Expires: 0');
header('Pragma: public');
// 輸出 BOM 讓 Excel 正確識別 UTF-8
echo "\xEF\xBB\xBF";
// 標題列
echo implode(',', array_map(function($h) { return '"' . str_replace('"', '""', $h) . '"'; }, $headers)) . "\r\n";
// 資料列
foreach ($data as $row) {
echo implode(',', array_map(function($v) { return '"' . str_replace('"', '""', $v) . '"'; }, $row)) . "\r\n";
}
exit;
}
// 使用
$headers = ['ID', '姓名', 'Email', '註冊時間'];
$data = [
[1, '張三', 'zhang@example.com', '2024-01-15 10:30:00'],
[2, '李四', 'li@example.com', '2024-01-16 14:22:00'],
];
exportCsvDownload($data, $headers, '會員名單');
function exportCsvSave(array $data, array $headers, string $filepath): bool {
$fp = fopen($filepath, 'w');
if (!$fp) return false;
// 寫入 BOM
fwrite($fp, "\xEF\xBB\xBF");
// 標題
fputcsv($fp, $headers);
// 資料
foreach ($data as $row) {
fputcsv($fp, $row);
}
fclose($fp);
return true;
}
// 使用
$path = '/var/www/exports/members_' . date('Ymd') . '.csv';
exportCsvSave($data, $headers, $path);
| 細節 | 處理方式 |
|---|---|
| 中文亂碼 | 輸出 UTF-8 BOM (\xEF\xBB\xBF),Excel 可正確開啟 |
| 欄位含逗號/雙引號/換行 | fputcsv() 自動處理;手動拼接時需雙引號包裹並轉義雙引號 |
| 大量資料記憶體 | 分批查詢、逐行 fputcsv() 寫入,避免一次載入所有資料 |
| IE 下載檔名亂碼 | urlencode() 處理檔名 |
| 編碼轉換 | 資料庫非 UTF-8 時,mb_convert_encoding($v, 'UTF-8', 'GBK') |
use League\Csv\Writer;
$csv = Writer::createFromFileObject(new SplTempFileObject());
$csv->insertOne($headers);
$csv->insertAll($data);
$csv->output('members.csv'); // 直接下載
// 或
$csv->saveToPath('/path/to/file.csv');
功能更強大:欄位對應、格式化、流式處理、多編碼支援。