使用html2pdf生成PDF并通過(guò)Ajax發(fā)送至PHPMailer的完整教程

使用html2pdf生成PDF并通過(guò)Ajax發(fā)送至PHPMailer的完整教程

本教程詳細(xì)介紹了如何利用JavaScript庫(kù)html2pdf在客戶端生成PDF文檔,并將其以Base64編碼字符串的形式通過(guò)ajax異步發(fā)送至服務(wù)器。在服務(wù)器端,我們將使用php處理接收到的Base64數(shù)據(jù),去除URI前綴后進(jìn)行解碼,最終通過(guò)PHPMailer庫(kù)將生成的PDF作為附件發(fā)送電子郵件。本文將涵蓋從前端PDF生成、數(shù)據(jù)傳輸?shù)胶蠖颂幚砗袜]件發(fā)送的全過(guò)程,并提供完整的代碼示例和注意事項(xiàng)。

1. 概述與準(zhǔn)備工作

在web應(yīng)用中,有時(shí)我們需要將用戶界面上的內(nèi)容轉(zhuǎn)換為pdf文檔,并將其通過(guò)郵件發(fā)送。直接在客戶端生成并發(fā)送郵件是不安全的,也無(wú)法實(shí)現(xiàn)。因此,常見(jiàn)的做法是:在客戶端生成pdf的二進(jìn)制數(shù)據(jù)(通常是base64編碼),通過(guò)ajax發(fā)送到服務(wù)器,再由服務(wù)器端腳本(如php)處理并發(fā)送郵件。

本教程將使用以下關(guān)鍵技術(shù)

  • 前端: html2pdf.JS (基于html2canvas和jsPDF) 用于將HTML內(nèi)容轉(zhuǎn)換為PDF,jquery 或原生 XMLhttpRequest 進(jìn)行Ajax通信。
  • 后端: PHP 處理數(shù)據(jù),PHPMailer 庫(kù)發(fā)送電子郵件。

在開始之前,請(qǐng)確保你的項(xiàng)目已引入 html2pdf.js 和 jQuery (如果使用),并且服務(wù)器端已安裝 PHPmailer。

2. 客戶端:生成PDF并以Base64字符串形式傳輸

在客戶端,我們首先使用html2pdf.js將指定的html元素內(nèi)容轉(zhuǎn)換為PDF。關(guān)鍵在于不直接保存PDF,而是將其輸出為Base64編碼的URI字符串。

2.1 HTML結(jié)構(gòu)準(zhǔn)備

確保你的HTML頁(yè)面中有一個(gè)包含需要轉(zhuǎn)換為PDF內(nèi)容的元素,例如:

立即學(xué)習(xí)PHP免費(fèi)學(xué)習(xí)筆記(深入)”;

<div id="printPage">     <h1>這是一個(gè)PDF標(biāo)題</h1>     <p>這是需要轉(zhuǎn)換為PDF的內(nèi)容。</p>     <ul>         <li>列表項(xiàng)1</li>         <li>列表項(xiàng)2</li>     </ul>     @@##@@ </div> <button id="sendPdfBtn">生成并發(fā)送PDF</button>

2.2 JavaScript代碼:生成Base64 PDF并發(fā)送Ajax請(qǐng)求

html2pdf.js 提供了一個(gè) output() 方法,可以指定輸出格式。我們使用 datauristring 格式來(lái)獲取PDF的Base64編碼字符串。

// 獲取需要轉(zhuǎn)換為PDF的HTML元素 let page = document.getElementById('printPage');  // html2pdf 配置選項(xiàng) var pdfOptions = {     margin: [5, 0, 0, 0], // 上右下左邊距     filename: 'document.pdf', // 盡管不直接保存,但此文件名會(huì)作為附件默認(rèn)名     image: {         type: 'jpeg',         quality: 1 // 圖片質(zhì)量     },     pagebreak: {         mode: ['legacy'] // 分頁(yè)模式     },     html2canvas: {         scale: 3 // html2canvas 渲染比例     },     jsPDF: {         unit: 'mm', // 單位         format: 'a4', // 紙張格式         orientation: 'portrait' // 方向:縱向     } };  // 監(jiān)聽(tīng)按鈕點(diǎn)擊事件 $(document).on('click', '#sendPdfBtn', async function() {     let pdfContent;      try {         // 使用 await 等待 PDF 生成為 datauristring         pdfContent = await html2pdf().from(page).set(pdfOptions).outputPdf('datauristring');         // 或者使用 .then() 回調(diào)方式         // await html2pdf().from(page).set(pdfOptions).outputPdf('datauristring').then(function(pdfAsString) {         //     pdfContent = pdfAsString;         // });          // 準(zhǔn)備 Ajax 請(qǐng)求數(shù)據(jù)         let ajaxUrl = 'your_php_mailer_script.php'; // 替換為你的php腳本URL         let transaction = 'someTransactionType'; // 示例數(shù)據(jù)         let transactionId = '12345'; // 示例數(shù)據(jù)          $.ajax({             type: "POST",             url: ajaxUrl,             data: {                 action: "sendEmail", // 示例動(dòng)作                 transaction: transaction,                 transactionId: transactionId,                 emailTo: $("#emailTo").val() || "recipient@example.com", // 接收者郵箱                 emailCc: $("#emailCc").val(), // 抄送                 emailBcc: $("#emailBcc").val(), // 密送                 emailSubject: $("#emailSubject").val() || "來(lái)自網(wǎng)站的PDF報(bào)告", // 郵件主題                 emailMessage: $("#emailMessage").val() || "請(qǐng)查收附件中的PDF文檔。", // 郵件內(nèi)容                 pdfContent: pdfContent // 核心:Base64編碼的PDF內(nèi)容             },             success: function(data) {                 console.log("郵件發(fā)送響應(yīng):", data);                 alert("郵件發(fā)送成功!");             },             error: function(xhr, status, error) {                 console.error("Ajax請(qǐng)求失敗:", status, error);                 alert("郵件發(fā)送失敗,請(qǐng)查看控制臺(tái)了解詳情。");             }         });      } catch (error) {         console.error("PDF生成或發(fā)送過(guò)程中發(fā)生錯(cuò)誤:", error);         alert("PDF生成或發(fā)送失敗。");     } });

代碼解釋:

  • html2pdf().from(page).set(pdfOptions).outputPdf(‘datauristring’): 這是核心部分。它指示 html2pdf 從 page 元素生成PDF,應(yīng)用 pdfOptions 配置,并將結(jié)果輸出為 datauristring。
  • datauristring 格式通常是 data:application/pdf;base64,JVBERi…,其中 JVBERi… 是PDF的Base64編碼內(nèi)容。服務(wù)器端需要處理這個(gè)前綴。
  • await 關(guān)鍵字用于等待異步的 html2pdf 操作完成。為了使用 await,你的函數(shù)需要被聲明為 async。
  • $.ajax() 用于發(fā)送POST請(qǐng)求,將 pdfContent 作為數(shù)據(jù)的一部分發(fā)送到服務(wù)器。

3. 服務(wù)器端:處理Base64 PDF數(shù)據(jù)并使用PHPMailer發(fā)送郵件

在服務(wù)器端(PHP腳本),我們將接收前端發(fā)送過(guò)來(lái)的Base64字符串,進(jìn)行解碼,然后使用PHPMailer將其作為附件發(fā)送。

3.1 PHP代碼:接收、解碼并發(fā)送郵件

<?php // 引入 PHPMailer 相關(guān)的類文件 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';  // 設(shè)置響應(yīng)頭,防止CORS問(wèn)題或確保JSON響應(yīng) header('Content-Type: application/json');  // 檢查是否是POST請(qǐng)求 if ($_SERVER['REQUEST_METHOD'] !== 'POST') {     echo json_encode(['status' => 'error', 'message' => 'Invalid request method.']);     exit; }  // 獲取前端發(fā)送的PDF內(nèi)容及其他郵件信息 $pdfdoc = $_POST['pdfContent'] ?? ''; $emailTo = $_POST['emailTo'] ?? ''; $emailCc = $_POST['emailCc'] ?? ''; $emailBcc = $_POST['emailBcc'] ?? ''; $emailSubject = $_POST['emailSubject'] ?? '郵件主題未設(shè)置'; $emailMessage = $_POST['emailMessage'] ?? '郵件內(nèi)容為空';  // 驗(yàn)證PDF內(nèi)容是否存在 if (empty($pdfdoc)) {     echo json_encode(['status' => 'error', 'message' => 'PDF content is missing.']);     exit; }  // 提取Base64編碼的PDF數(shù)據(jù) // 'data:application/pdf;base64,' 這個(gè)前綴需要被移除 $pdfData = substr($pdfdoc, strpos($pdfdoc, ',') + 1); // 從逗號(hào)后面開始截取  // 對(duì)Base64數(shù)據(jù)進(jìn)行解碼 $decodedPdf = base64_decode($pdfData);  // 檢查解碼是否成功 if ($decodedPdf === false) {     echo json_encode(['status' => 'error', 'message' => 'Failed to decode PDF content.']);     exit; }  // PHPMailer 實(shí)例 $mail = new PHPMailer(true); // true enables exceptions  try {     // 服務(wù)器設(shè)置 (根據(jù)你的SMTP服務(wù)商配置)     $mail->SMTPDebug = 0; // 0 = off (for production), 1 = client messages, 2 = client and server messages     $mail->isSMTP(); // 使用SMTP     $mail->Host       = 'smtp.yourdomain.com'; // SMTP 服務(wù)器地址     $mail->SMTPAuth   = true; // 啟用SMTP認(rèn)證     $mail->Username   = 'your_email@yourdomain.com'; // SMTP 用戶名     $mail->Password   = 'your_email_password'; // SMTP 密碼     $mail->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS; // 啟用TLS加密,或者 PHPMailer::ENCRYPTION_SMTPS for SSL     $mail->Port       = 587; // TLS 端口通常是 587,SSL 端口通常是 465      // 收件人     $mail->setFrom('sender@yourdomain.com', 'Your Company Name'); // 發(fā)件人郵箱和名稱     $mail->addAddress($emailTo); // 收件人郵箱     if (!empty($emailCc)) {         $mail->addCC($emailCc); // 抄送     }     if (!empty($emailBcc)) {         $mail->addBCC($emailBcc); // 密送     }      // 附件     // AddStringAttachment(string $string, string $filename, string $encoding = 'base64', string $type = '', string $disposition = 'attachment')     // 這里我們傳入的是原始的二進(jìn)制PDF數(shù)據(jù),所以編碼類型是 'base64' (因?yàn)樗笆莃ase64編碼的),MIME類型是 'application/pdf'     $mail->AddStringAttachment($decodedPdf, "GeneratedDocument.pdf", "base64", "application/pdf");      // 內(nèi)容     $mail->isHTML(true); // 郵件內(nèi)容為HTML格式     $mail->Subject = $emailSubject; // 郵件主題     $mail->Body    = nl2br(htmlspecialchars($emailMessage)); // 郵件HTML內(nèi)容,nl2br保留換行,htmlspecialchars防止xss     $mail->AltBody = strip_tags($emailMessage); // 純文本內(nèi)容,用于不支持HTML的郵件客戶端      $mail->send();     echo json_encode(['status' => 'success', 'message' => 'Message has been sent.']);  } catch (Exception $e) {     echo json_encode(['status' => 'error', 'message' => "Message could not be sent. Mailer Error: {$mail->ErrorInfo}"]); } ?>

代碼解釋:

  • PHPMailer 引入: 確保 require 語(yǔ)句指向你的PHPMailer庫(kù)的正確路徑。
  • 數(shù)據(jù)提取: $_POST[‘pdfContent’] 獲取前端發(fā)送的Base64字符串。
  • substr($pdfdoc, strpos($pdfdoc, ‘,’) + 1): 這是關(guān)鍵一步。datauristring 格式包含一個(gè)前綴(例如 data:application/pdf;base64,),我們需要用 strpos 找到逗號(hào)的位置,然后用 substr 從逗號(hào)之后開始截取,從而得到純粹的Base64編碼數(shù)據(jù)。
  • base64_decode($pdfData): 將純粹的Base64編碼數(shù)據(jù)解碼回原始的二進(jìn)制PDF數(shù)據(jù)。
  • $mail->AddStringAttachment(…): 這是PHPMailer中用于添加字符串作為附件的方法。
    • 第一個(gè)參數(shù) $decodedPdf 是解碼后的二進(jìn)制PDF數(shù)據(jù)。
    • 第二個(gè)參數(shù) “GeneratedDocument.pdf” 是附件的文件名。
    • 第三個(gè)參數(shù) “base64” 表示附件的編碼方式(盡管我們傳入的是解碼后的數(shù)據(jù),PHPMailer內(nèi)部會(huì)根據(jù)這個(gè)參數(shù)進(jìn)行處理,這里指明原始數(shù)據(jù)是Base64編碼的)。
    • 第四個(gè)參數(shù) “application/pdf” 是附件的MIME類型,這非常重要,它告訴郵件客戶端這是一個(gè)PDF文件。
  • SMTP 配置: 替換 host, username, password, port, SMTPSecure 為你的SMTP服務(wù)器的實(shí)際配置。
  • 錯(cuò)誤處理: try…catch 塊用于捕獲PHPMailer可能拋出的異常,并返回詳細(xì)的錯(cuò)誤信息。

4. 注意事項(xiàng)與總結(jié)

  • 文件大小限制: 通過(guò)Ajax發(fā)送Base64編碼的數(shù)據(jù)會(huì)顯著增加數(shù)據(jù)量(Base64編碼會(huì)使數(shù)據(jù)量增大約33%)。對(duì)于非常大的PDF文件,這可能會(huì)導(dǎo)致HTTP請(qǐng)求體過(guò)大,超出服務(wù)器或Web服務(wù)器(如nginx, apache)的請(qǐng)求體大小限制。你可能需要調(diào)整服務(wù)器配置(例如PHP的 post_max_size 和 upload_max_filesize,以及Web服務(wù)器的 client_max_body_size)。
  • 安全性:
    • 始終在服務(wù)器端驗(yàn)證所有接收到的輸入數(shù)據(jù),包括郵件地址、主題和內(nèi)容,以防止注入攻擊(如XSS)。
    • 不要直接暴露你的SMTP憑據(jù)在客戶端代碼中。PHPMailer配置應(yīng)完全在服務(wù)器端進(jìn)行。
    • 考慮對(duì)生成的PDF內(nèi)容進(jìn)行服務(wù)器端驗(yàn)證或消毒,如果內(nèi)容來(lái)源于用戶輸入。
  • 異步操作: html2pdf 的生成過(guò)程是異步的。確保你在發(fā)送Ajax請(qǐng)求之前,PDF內(nèi)容已經(jīng)完全生成并賦值給 pdfContent 變量。使用 await 或 .then() 回調(diào)是處理異步操作的正確方式。
  • MIME 類型: 在 AddStringAttachment 中正確指定 application/pdf MIME 類型至關(guān)重要,它能確保郵件客戶端正確識(shí)別并顯示附件。
  • 調(diào)試: 在開發(fā)階段,將 PHPMailer 的 SMTPDebug 設(shè)置為 1 或 2 可以幫助你查看SMTP通信過(guò)程,從而診斷連接或認(rèn)證問(wèn)題。在生產(chǎn)環(huán)境中,務(wù)必將其設(shè)置為 0。
  • PHPMailer 路徑: 確保 require 語(yǔ)句中PHPMailer庫(kù)的路徑是正確的。

通過(guò)以上步驟,你就可以成功地在客戶端生成PDF,并通過(guò)Ajax將其發(fā)送到服務(wù)器,再由PHPMailer將其作為附件發(fā)送電子郵件。這種方法兼顧了客戶端生成PDF的靈活性和服務(wù)器端發(fā)送郵件的可靠性與安全性。

使用html2pdf生成PDF并通過(guò)Ajax發(fā)送至PHPMailer的完整教程

以上就是使用html2pdf生成PDF并通過(guò)Ajax發(fā)送至PHPM

? 版權(quán)聲明
THE END
喜歡就支持一下吧
點(diǎn)贊14 分享