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

PHP 導出 Excel 並作為郵件附件發送:輸出緩衝與 PHPMailer 完整方案

     編輯:PHP 相關知識

核心難點

PHP 直接輸出 Excel 時會發送 HTTP Header 導致瀏覽器下載,無法同時作為附件發送郵件。解決關鍵在於捕獲輸出內容到變數/文件,而非直接輸出給瀏覽器。

方案一:輸出緩衝捕獲內容(推薦)

<?php
require 'vendor/autoload.php';
use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\Exception;

function generateExcelContent(array $title, array $data): string
{
    // 1. 開啟輸出緩衝
    ob_start();

    // 2. 發送 Excel Header(此處僅為模擬,實際不輸出給瀏覽器)
    // header("Content-type:application/vnd.ms-excel");
    // header("Content-Disposition:attachment;filename=export.xls");

    // 3. 輸出內容(實際寫入緩衝區)
    if (!empty($title)) {
        $title = array_map(fn($v) => iconv('UTF-8', 'GB2312//IGNORE', $v), $title);
        echo implode("\t", $title) . "\n";
    }
    if (!empty($data)) {
        foreach ($data as $row) {
            $row = array_map(fn($v) => iconv('UTF-8', 'GB2312//IGNORE', $v), $row);
            echo implode("\t", $row) . "\n";
        }
    }

    // 4. 獲取緩衝內容並關閉緩衝
    return ob_get_clean();
}

function sendExcelEmail(string $to, string $subject, string $body, string $excelContent, string $filename = 'export.xls'): bool
{
    $mail = new PHPMailer(true);
    try {
        // SMTP 配置
        $mail->isSMTP();
        $mail->Host       = 'smtp.example.com';
        $mail->SMTPAuth   = true;
        $mail->Username   = 'sender@example.com';
        $mail->Password   = 'your_password';
        $mail->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS;
        $mail->Port       = 587;
        $mail->CharSet    = 'UTF-8';

        // 發件/收件
        $mail->setFrom('sender@example.com', '系統通知');
        $mail->addAddress($to);
        $mail->Subject = $subject;
        $mail->msgHTML($body);

        // 核心:將字符串內容作為附件添加
        $mail->addStringAttachment($excelContent, $filename, 'base64', 'application/vnd.ms-excel');

        return $mail->send();
    } catch (Exception $e) {
        error_log("郵件發送失敗: {$mail->ErrorInfo}");
        return false;
    }
}

// 使用範例
$title = ['訂單號', '商品', '金額', '下單時間'];
$data = [
    ['202401001', '筆記本電腦', '5999.00', '2024-01-15 10:30'],
    ['202401002', '無線滑鼠', '199.00', '2024-01-15 11:00'],
];

$excelContent = generateExcelContent($title, $data);
$success = sendExcelEmail('user@example.com', '訂單導出報表', '請查收附件', $excelContent, 'orders_202401.xls');

echo $success ? '發送成功' : '發送失敗';

方案二:臨時文件落地(大數據量適用)

function generateExcelToFile(array $title, array $data, string $dir = '/tmp'): string
{
    $filename = $dir . '/excel_' . date('Ymd_His') . '_' . uniqid() . '.xls';
    $fp = fopen($filename, 'w');

    // 寫入 BOM 防止 Excel 打開亂碼
    fwrite($fp, "\xEF\xBB\xBF");

    if ($title) {
        fputcsv($fp, $title, "\t");
    }
    foreach ($data as $row) {
        fputcsv($fp, $row, "\t");
    }
    fclose($fp);
    return $filename;
}

// 發送時
$filePath = generateExcelToFile($title, $data);
$mail->addAttachment($filePath, 'orders.xls');
// 發送後清理
@unlink($filePath);

進階:使用 PhpSpreadsheet 生成真正的 .xlsx

use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;

function generateRealXlsx(array $title, array $data): string
{
    $spreadsheet = new Spreadsheet();
    $sheet = $spreadsheet->getActiveSheet();

    // 標題行樣式
    $sheet->fromArray($title, null, 'A1');
    $sheet->getStyle('A1:' . $sheet->getHighestColumn() . '1')
          ->getFont()->setBold(true);

    // 數據
    $sheet->fromArray($data, null, 'A2');

    // 自動欄寬
    foreach (range('A', $sheet->getHighestColumn()) as $col) {
        $sheet->getColumnDimension($col)->setAutoSize(true);
    }

    // 寫入臨時文件並返回路徑
    $filename = sys_get_temp_dir() . '/export_' . time() . '.xlsx';
    $writer = new Xlsx($spreadsheet);
    $writer->save($filename);
    return $filename;
}

關鍵點總結

方案優點缺點適用場景
ob_get_clean() + addStringAttachment 無磁盤 IO、記憶體中完成、速度快 大數據量會佔用大量記憶體 < 5000 行、簡單導出
臨時文件 + addAttachment 記憶體穩定、支援超大數據 需磁盤 IO、需手動清理 > 5000 行、長時間運行腳本
PhpSpreadsheet .xlsx 真正 Excel 格式、支援樣式/公式/多工作表 依賴較重、效能較低 專業報表、需樣式控制

常見坑位避雷

  • 編碼問題:中文內容務必用 iconv('UTF-8', 'GB2312//IGNORE') 或直接生成 UTF-8 的 .xlsx。
  • Header 衝突:生成 Excel 過程中絕對不能輸出任何 HTML/空白字符,否則附件會損壞。
  • 內存限制:大數據用 fputcsv 流式寫入文件,避免 memory_limit 耗盡。
  • 附件 MIME:addStringAttachment 第四參數務必設為 application/vnd.ms-excel 或 application/vnd.openxmlformats-officedocument.spreadsheetml.sheet。

掌握輸出緩衡與 PHPMailer 附件 API,即可靈活實現「導出即發送」的自動化報表流程。

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