
1. 概述
在web应用开发中,有时我们需要在客户端生成pdf文档,并将其作为附件通过电子邮件发送。直接在客户端发送邮件存在安全和功能限制,因此通常的做法是将生成的pdf数据发送到服务器,再由服务器端的邮件服务(如phpmailer)进行发送。本文将详细介绍如何结合html2pdf.js、ajax和phpmailer实现这一功能。
2. 客户端PDF生成与数据准备 (JavaScript)
客户端的核心任务是将HTML内容转换为PDF,并以可传输的格式(通常是Base64编码字符串)获取PDF数据。html2pdf.js库提供了outputPdf('datauristring')方法来获取这种格式的数据。
2.1 html2pdf配置与PDF生成
首先,确保你的HTML页面中有一个用于生成PDF的元素,例如一个div。
PDF 文档标题
这是一段示例文本,将被包含在生成的PDF中。
@@##@@
接下来,在JavaScript中配置html2pdf并获取PDF内容:
立即学习“PHP免费学习笔记(深入)”;
// 假设你的HTML中有一个ID为'printPage'的元素,这是要转换为PDF的内容源
let page = document.getElementById('printPage');
// html2pdf的配置选项
var options = {
margin: [5, 0, 0, 0], // 上右下左边距
filename: 'document.pdf', // 默认文件名,在服务器端可覆盖
image: {
type: 'jpeg',
quality: 1 // 图像质量
},
pagebreak: {
mode: ['legacy'] // 分页模式
},
html2canvas: {
scale: 3 // html2canvas渲染比例,影响清晰度
},
jsPDF: {
unit: 'mm', // 单位
format: 'a4', // 纸张格式
orientation: 'portrait' // 方向:纵向
}
};
// 监听按钮点击事件,触发PDF生成和发送
$(document).on('click', '#sendPdfBtn', async function() {
let pdfContent;
try {
// 使用await等待PDF内容生成,并以datauristring格式获取
// datauristring格式包含 "data:application/pdf;base64," 前缀
pdfContent = await html2pdf().from(page).set(options).outputPdf('datauristring');
// 成功获取PDF内容后,通过Ajax发送到服务器
sendPdfToServer(pdfContent);
} catch (error) {
console.error("PDF生成失败:", error);
alert("PDF生成失败,请稍后再试。");
}
});
// 这是一个示例函数,用于将PDF内容发送到服务器
async function sendPdfToServer(pdfData) {
// 假设ajaxUrl是你的PHP处理脚本的URL
const ajaxUrl = 'your_php_mailer_script.php';
// 其他需要发送的表单数据,例如邮件接收者、主题、消息等
const emailTo = $("#emailTo").val(); // 假设有输入框获取收件人
const emailSubject = $("#emailSubject").val(); // 假设有输入框获取邮件主题
const emailMessage = $("#emailMessage").val(); // 假设有输入框获取邮件内容
$.ajax({
type: "POST", // 使用POST方法发送数据
url: ajaxUrl,
data: {
action: "sendEmail", // 自定义动作,用于PHP脚本识别
emailTo: emailTo,
emailSubject: emailSubject,
emailMessage: emailMessage,
pdfContent: pdfData // 将Base64编码的PDF内容作为参数发送
},
success: function(response) {
console.log("服务器响应:", response);
alert("邮件发送成功!");
},
error: function(xhr, status, error) {
console.error("Ajax请求失败:", status, error);
alert("邮件发送失败,请检查网络或联系管理员。");
}
});
}关键点:
采用.NET CLR2.0、VS2005及SQL2000,前台页面使用用DIV+CSS开发;可以使用动态化运行,也可以采用全部静态化动作,甚至自己定义模板;后台信息编辑器采用最新版FCKeditor;产品信息可导出为EXCEL、WORD、PDF等格式存储;产品信息可以通过EXCEL模板批量导入;产品分类采用无限级分类;产品图片上传支持图片水印和文字水印,同时支持自动生成缩略图功能;电子邮件发送支持
- outputPdf('datauristring'): 这是将PDF内容转换为Base64编码字符串的关键。它返回的字符串会包含一个data:URI前缀,例如data:application/pdf;base64,...。
- await: html2pdf的outputPdf方法是异步的,因此需要使用await关键字(或.then()方法)来等待PDF内容生成完毕。这要求包裹该代码的函数是async函数。
- Ajax POST请求:通过POST方法发送数据,确保PDF内容作为请求体的一部分发送,避免URL长度限制。
3. 服务器端PDF处理与邮件发送 (PHP with PHPMailer)
服务器端PHP脚本负责接收客户端发送的Base64编码PDF数据,解码它,然后使用PHPMailer将其作为附件发送。
3.1 接收与解码PDF数据
当客户端通过Ajax发送pdfContent时,PHP可以通过$_POST['pdfContent']来获取它。由于datauristring包含data:application/pdf;base64,前缀,我们需要先去除这个前缀,然后再进行Base64解码。
SMTPDebug = 0; // 启用详细调试输出 (0为关闭,1为客户端,2为客户端和服务器)
$mail->isSMTP(); // 使用SMTP
$mail->Host = 'smtp.example.com'; // 你的SMTP服务器地址
$mail->SMTPAuth = true; // 启用SMTP认证
$mail->Username = 'your_email@example.com'; // SMTP用户名
$mail->Password = 'your_email_password'; // SMTP密码
$mail->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS; // 启用TLS加密,或者PHPMailer::ENCRYPTION_SMTPS for SSL
$mail->Port = 587; // SMTP端口 (TLS通常是587,SSL通常是465)
// 收件人
$mail->setFrom('sender@example.com', '你的公司名称'); // 发件人邮箱和名称
$mail->addAddress($emailTo); // 添加收件人
// $mail->addCC('cc@example.com'); // 添加抄送
// $mail->addBCC('bcc@example.com'); // 添加密送
// 附件
// AddStringAttachment用于添加字符串作为附件
// 第一个参数是附件内容(已解码的二进制数据)
// 第二个参数是附件文件名
// 第三个参数是内容的编码类型 (这里是'binary'因为我们已经解码了)
// 第四个参数是MIME类型
$mail->AddStringAttachment($decodedPdf, "GeneratedDocument.pdf", "binary", "application/pdf");
// 内容
$mail->isHTML(true); // 邮件内容为HTML格式
$mail->Subject = $emailSubject; // 邮件主题
$mail->Body = $emailMessage; // 邮件HTML内容
$mail->AltBody = strip_tags($emailMessage); // 非HTML邮件客户端的纯文本内容
$mail->send();
echo '邮件已成功发送!';
} catch (Exception $e) {
echo "邮件发送失败。 PHPMailer 错误: {$mail->ErrorInfo}";
}
} else {
echo '无效的请求或缺少PDF内容。';
}
?>关键点:
- Base64解码: substr($pdfdoc, strpos($pdfdoc, ",") + 1)用于去除data:application/pdf;base64,前缀。base64_decode()将剩余的Base64字符串转换为原始二进制数据。
-
AddStringAttachment: PHPMailer的AddStringAttachment()方法非常适合这种场景,因为它允许你直接从字符串添加附件内容,而无需先将文件保存到服务器。
- 第一个参数是已解码的二进制PDF数据。
- 第三个参数"binary"至关重要,它告诉PHPMailer你提供的数据是原始二进制格式,而不是需要PHPMailer再次解码的Base64字符串。
- PHPMailer配置: 务必根据你的SMTP服务商正确配置Host、Username、Password、SMTPSecure和Port。
4. 注意事项与最佳实践
- 文件大小限制: 通过Ajax发送Base64编码的PDF数据,如果PDF文件过大,可能会导致POST请求体过大,超出服务器或PHP的配置限制(如post_max_size,upload_max_filesize)。对于非常大的PDF文件,考虑将文件上传到服务器的临时目录,然后将文件路径传递给PHPMailer。
-
安全性:
- 输入验证: 永远不要信任来自客户端的数据。对emailTo、emailSubject、emailMessage等所有接收到的POST数据进行严格的验证和过滤,以防止XSS攻击、邮件头注入等安全漏洞。
- 文件类型验证: 虽然这里是内部生成,但如果是用户上传,应严格验证文件类型。
-
错误处理:
- 客户端: 在JavaScript中添加try...catch块来捕获html2pdf生成PDF时的错误,以及Ajax请求的错误。
- 服务器端: PHPMailer的构造函数传入true可以启用异常处理,try...catch块可以捕获邮件发送过程中的错误,并通过$mail->ErrorInfo获取详细错误信息。
- 异步操作: html2pdf的PDF生成和Ajax请求都是异步操作。确保你的JavaScript代码正确处理了这些异步性(使用async/await或.then())。
- PHPMailer库路径: 在PHP代码中,确保require语句指向了PHPMailer库的正确路径。
5. 总结
通过结合html2pdf.js在客户端生成PDF,利用Ajax将Base64编码的PDF数据传输到服务器,再通过PHPMailer在服务器端解码并发送邮件附件,我们实现了一个完整的客户端PDF生成与服务器端邮件发送的解决方案。这种方法避免了在客户端直接处理邮件发送的复杂性和安全问题,提供了一个健壮且可扩展的实现方案。










