本教程詳細介紹了如何利用 JavaScript 庫 html2pdf 在客戶端生成 PDF 文件,并將其以數據 URI 字符串的形式通過 ajax 異步發送至 php 后端。在服務器端,我們將學習如何接收并解析這份 PDF 數據,最終使用 PHPMailer 庫將其作為附件發送電子郵件。文章涵蓋了從前端數據準備到后端文件處理及郵件發送的完整流程,并提供了關鍵代碼示例和注意事項。
在現代 web 應用中,用戶可能需要將頁面內容導出為 pdf 并通過郵件發送。直接在客戶端保存 pdf 相對簡單,但要將生成的 pdf 發送到服務器并作為郵件附件,則需要一套完整的客戶端與服務器端協作機制。本文將詳細闡述如何結合 html2pdf.JS、ajax 和 phpmailer 實現這一功能。
1. 客戶端 PDF 生成與數據準備 (JavaScript)
html2pdf.js 庫能夠將 HTML 內容轉換為 PDF。其核心在于 outputPdf() 方法,特別是當它與 ‘datauriString’ 參數結合使用時,可以將生成的 PDF 內容以 Base64 編碼的字符串形式返回,這正是通過 Ajax 傳輸的理想格式。
首先,確保你的頁面中有一個 HTML 元素作為 PDF 的內容源,例如:
<div id="printPage"> <!-- 這里是你要轉換為PDF的內容 --> <h1>報告標題</h1> <p>這是一段示例文本,將包含在PDF中。</p> <table> <thead> <tr><th>列1</th><th>列2</th></tr> </thead> <tbody> <tr><td>數據A</td><td>數據B</td></tr> </tbody> </table> </div>
接下來是 JavaScript 代碼,用于生成 PDF 字符串并準備 Ajax 請求。請注意,html2pdf() 操作是異步的,因此我們需要使用 await 或 .then() 來確保在發送 Ajax 請求之前 PDF 內容已經完全生成。
立即學習“PHP免費學習筆記(深入)”;
// 獲取要轉換為PDF的html元素 const page = document.getElementById('printPage'); // html2pdf 配置選項 const pdfOptions = { margin: [5, 0, 0, 0], // 上、右、下、左邊距 filename: 'generated_document.pdf', // 盡管此處設置了文件名,但發送時可能需要服務器端重新指定 image: { type: 'jpeg', quality: 1 }, pagebreak: { mode: ['legacy'] }, // 分頁模式 html2canvas: { scale: 3 }, // html2canvas 渲染比例 jsPDF: { unit: 'mm', format: 'a4', orientation: 'portrait' } // jsPDF 庫配置 }; let pdfContent; // 異步函數,用于生成PDF并發送Ajax請求 async function sendPdfViaAjax() { try { // 使用 outputPdf('datauristring') 獲取Base64編碼的PDF字符串 // await 確保在獲取到pdfAsString后再繼續執行 pdfContent = await html2pdf().from(page).set(pdfOptions).outputPdf('datauristring'); // 構建Ajax請求數據 const requestData = { action: "sendEmail", // 服務器端用于識別操作的參數 // 其他需要發送的郵件信息,例如: transaction: "some_transaction_data", transactionId: "12345", emailTo: $("#emailTo").val(), emailCc: $("#emailCc").val(), emailBcc: $("#emailBcc").val(), emailSubject: $("#emailSubject").val(), emailMessage: $("#emailMessage").val(), pdfContent: pdfContent // 將Base64編碼的PDF字符串作為參數發送 }; // 發送Ajax POST請求到后端 $.ajax({ type: "POST", url: ajaxUrl, // 你的后端處理腳本URL data: requestData, success: function(response) { console.log("郵件發送成功:", response); alert("郵件已成功發送!"); }, error: function(xhr, status, error) { console.error("郵件發送失敗:", error); alert("郵件發送失敗,請稍后再試。"); } }); } catch (error) { console.error("生成PDF或發送Ajax時出錯:", error); alert("操作失敗,請檢查控制臺信息。"); } } // 觸發發送的事件監聽器,例如一個按鈕點擊事件 $(document).on('click', '#sendEmailBtn', function() { sendPdfViaAjax(); });
在上述代碼中,outputPdf(‘datauristring’) 是關鍵。它會返回一個形如 data:application/pdf;base64,JVBERi… 的字符串。這個字符串包含了 PDF 的 MIME 類型前綴和 Base64 編碼的實際 PDF 數據。
2. 服務器端 PDF 處理與郵件發送 (PHP with PHPMailer)
在 PHP 后端,我們需要接收前端發送過來的 pdfContent 字符串,對其進行解析,然后使用 PHPMailer 將其作為附件添加到郵件中。
<?php // 引入PHPMailer庫 use PHPMailerPHPMailerPHPMailer; use PHPMailerPHPMailerException; // 根據你的項目結構調整路徑 require 'path/to/PHPMailer/src/Exception.php'; require 'path/to/PHPMailer/src/PHPMailer.php'; require 'path/to/PHPMailer/src/SMTP.php'; // 假設這是你的Ajax處理入口 if (isset($_POST['action']) && $_POST['action'] === 'sendEmail') { // 接收前端發送的PDF內容及其他郵件信息 $pdfdoc = $_POST['pdfContent'] ?? ''; $emailTo = $_POST['emailTo'] ?? ''; $emailCc = $_POST['emailCc'] ?? ''; $emailBcc = $_POST['emailBcc'] ?? ''; $emailSubject = $_POST['emailSubject'] ?? '無主題'; $emailMessage = $_POST['emailMessage'] ?? '無內容'; // 從data URI字符串中提取Base64編碼的PDF數據 // datauristring的格式通常是: data:application/pdf;base64,實際數據 // 我們需要移除 "data:application/pdf;base64," 這部分前綴 $pdfData = substr($pdfdoc, strpos($pdfdoc, ',') + 1); // 對Base64編碼的數據進行解碼 $decodedPdf = base64_decode($pdfData); // 確保解碼成功且數據不為空 if ($decodedPdf === false || empty($decodedPdf)) { echo "Error: PDF data decoding failed."; exit; } // 創建PHPMailer實例 $mail = new PHPMailer(true); // 啟用異常處理 try { // 服務器設置 $mail->SMTPDebug = 0; // 調試輸出 (0 = 關閉, 1 = 客戶端, 2 = 客戶端和服務器) $mail->isSMTP(); // 使用SMTP $mail->Host = 'your.smtp.host.com'; // 你的SMTP服務器地址 $mail->SMTPAuth = true; // 啟用SMTP認證 $mail->Username = 'your_smtp_username'; // SMTP 用戶名 $mail->Password = 'your_smtp_password'; // SMTP 密碼 $mail->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS; // 啟用TLS加密,或者 PHPMailer::ENCRYPTION_SMTPS 用于SSL $mail->Port = 587; // TLS端口通常是587,SSL通常是465 // 收件人 $companyEmail = 'sender@yourcompany.com'; // 發件人郵箱 $companyName = 'My Company'; // 發件人名稱 $mail->setFrom($companyEmail, $companyName); $mail->addAddress($emailTo); // 收件人郵箱 if (!empty($emailCc)) { $mail->addCC($emailCc); // 抄送 } if (!empty($emailBcc)) { $mail->addBCC($emailBcc); // 密送 } // 附件 // AddStringAttachment 允許直接從字符串添加附件 // 參數: $string, $filename, $encoding, $type $mail->AddStringAttachment($decodedPdf, "GeneratedDocument.pdf", "base64", "application/pdf"); // 內容 $mail->isHTML(true); // 郵件內容為HTML格式 $mail->Subject = $emailSubject; // 郵件主題 $mail->Body = nl2br(htmlspecialchars($emailMessage)); // 郵件HTML內容 $mail->AltBody = strip_tags($emailMessage); // 非HTML郵件客戶端的替代內容 $mail->send(); echo 'Message has been sent'; } catch (Exception $e) { echo "Message could not be sent. Mailer Error: {$mail->ErrorInfo}"; } } else { echo "Invalid request."; } ?>
在 PHP 代碼中,有幾個關鍵點:
- 數據提?。?/strong> substr($pdfdoc, strpos($pdfdoc, ‘,’) + 1) 用于從 datauristring 中精確地提取出 Base64 編碼的 PDF 數據,移除了 data:application/pdf;base64, 前綴。
- Base64 解碼: base64_decode($pdfData) 將 Base64 編碼的字符串解碼為原始的二進制 PDF 數據。
- PHPMailer::AddStringAttachment: 這個方法是 PHPMailer 的一個強大功能,它允許你直接從內存中的字符串(而不是文件路徑)添加附件。參數包括:
- $string: 解碼后的二進制 PDF 數據。
- $filename: 附件在郵件中顯示的文件名。
- $encoding: 附件的編碼方式,這里是 “base64″。
- $type: 附件的 MIME 類型,這里是 “application/pdf”。
3. 注意事項與總結
- 異步處理: html2pdf() 是異步的,務必使用 await 或 .then() 確保 PDF 內容完全生成后再進行 Ajax 請求。
- POST 請求大小限制: Base64 編碼會使數據量增大約 33%。如果 PDF 文件較大,可能會超出 PHP 服務器的 post_max_size 和 upload_max_filesize 限制。你可能需要在 php.ini 中調整這些設置。
- 安全性: 在處理用戶上傳或生成的數據時,始終要注意安全。雖然 Base64 編碼的 PDF 數據本身通常不包含可執行代碼,但仍需確保你的 PHP 腳本對輸入進行適當的驗證和清理。
- 錯誤處理: 前端和后端都應包含健壯的錯誤處理機制,以便在出現問題時能夠及時發現并通知用戶。
- PHPMailer 配置: 請根據你的 SMTP 服務提供商正確配置 PHPMailer 的 Host、Port、Username、Password 和 SMTPSecure 等參數。
- 文件命名: 在 AddStringAttachment 中指定的文件名 (“GeneratedDocument.pdf”) 是郵件客戶端接收時顯示的文件名,可以根據業務邏輯動態生成。
通過上述步驟,你現在應該能夠成功地在客戶端生成 PDF,并通過 Ajax 將其發送到 PHP 后端,最終使用 PHPMailer 作為附件發送電子郵件。這種方法避免了在服務器端生成 PDF 的額外開銷,同時提供了靈活的客戶端交互體驗。