
本文详解如何在使用 phpmailer 发送邮件时,正确实现多文件上传的大小校验,避免因语法错误或逻辑疏漏导致超限文件被忽略、邮件仍被发送的问题。
本文详解如何在使用 phpmailer 发送邮件时,正确实现多文件上传的大小校验,避免因语法错误或逻辑疏漏导致超限文件被忽略、邮件仍被发送的问题。
在基于表单的文件上传 + 邮件发送场景中(如联系表单附带简历/图纸),仅靠前端限制或简单 if 判断无法保障安全性——PHP 层必须对每个上传文件进行独立、准确的大小验证。原代码存在三类典型问题:错误的数组键路径访问(如 $_FILES['uploaded-file']['name']['size'][$i])、不严谨的空文件判断(isset($attachment) 恒为真),以及缺失上传错误码检查(如 UPLOAD_ERR_INI_SIZE)。这些问题共同导致验证逻辑失效,超限文件悄然进入邮件附件队列。
以下为修复后的完整、健壮的验证实现:
✅ 正确获取文件大小与错误码
PHP 的 $_FILES 超全局数组结构是扁平化的二维结构,每个字段(name、tmp_name、size、error、type)均为独立索引数组。切勿嵌套访问 ['name']['size'] —— 正确路径是:
$_FILES['uploaded-file']['size'][$i] // ✅ 当前第 i 个文件的字节数 $_FILES['uploaded-file']['error'][$i] // ✅ 当前第 i 个文件的上传错误码
✅ 完整校验流程(含示例代码)
<?php
use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\Exception;
require 'vendor/autoload.php'; // 确保路径正确
// 基础配置
$user_name = $_POST['name'] ?? '';
$user_email = $_POST['email'] ?? '';
$user_message = $_POST['message'] ?? '';
$user_phone = $_POST['phone'] ?? '';
$honeypot = trim($_POST['honey'] ?? '');
// 防垃圾邮件检查
if (!empty($honeypot)) {
http_response_code(403);
echo "SPAM detected.";
exit;
}
// 文件大小上限:2MB(注意单位是字节)
$max_size = 2 * 1024 * 1024; // 修正原代码中的 1204 → 1024
// 初始化邮件对象
$mail = new PHPMailer(true);
$mail->isMail();
$mail->setFrom($user_email, $user_name);
$mail->addAddress('contact@example.com'); // 替换为目标邮箱
$mail->isHTML(true);
$mail->Subject = 'Zapytanie ze strony www';
$mail->Body = "Telefon: $user_phone<br><br>Treść wiadomości:<br>" . nl2br(htmlspecialchars($user_message));
$mail->AltBody = "Telefon: $user_phone\n" . strip_tags($user_message);
// 处理附件(关键校验段)
if (isset($_FILES['uploaded-file']) && is_array($_FILES['uploaded-file']['name'])) {
$fileCount = count($_FILES['uploaded-file']['name']);
for ($i = 0; $i < $fileCount; $i++) {
$tmpName = $_FILES['uploaded-file']['tmp_name'][$i];
$fileName = $_FILES['uploaded-file']['name'][$i];
$fileSize = $_FILES['uploaded-file']['size'][$i];
$fileError = $_FILES['uploaded-file']['error'][$i];
// 步骤1:检查上传是否成功(跳过错误文件)
if ($fileError !== UPLOAD_ERR_OK) {
// 可记录日志:error code $fileError
continue;
}
// 步骤2:检查文件是否为空(size=0 但 error=OK 是合法空文件)
if ($fileSize === 0) {
continue;
}
// 步骤3:核心大小校验(单位:字节)
if ($fileSize > $max_size) {
http_response_code(400);
echo "Błąd: Plik '{$fileName}' przekracza dozwolony rozmiar (maks. 2 MB).";
exit;
}
// 步骤4:安全保存并附加
$uploadDir = 'uploads/';
$safeFileName = basename($fileName); // 防止路径遍历
$targetPath = $uploadDir . uniqid() . '_' . $safeFileName;
if (!is_dir($uploadDir)) {
mkdir($uploadDir, 0755, true);
}
if (!move_uploaded_file($tmpName, $targetPath)) {
http_response_code(500);
echo "Nie udało się zapisać pliku '{$fileName}'.";
exit;
}
$mail->addAttachment($targetPath, $fileName); // 第二个参数为原始文件名(显示用)
}
}
// 发送邮件
try {
$mail->send();
header('Location: sent.html');
exit;
} catch (Exception $e) {
error_log("Mailer Error: " . $e->getMessage());
http_response_code(500);
echo "Wystąpił błąd podczas wysyłania wiadomości.";
}⚠️ 关键注意事项
- 永远校验 $_FILES['...']['error']:网络中断、用户取消、INI 配置超限等均会触发非 UPLOAD_ERR_OK 错误码,此时 size 字段不可信。
- isset($_FILES['field']) ≠ 有有效文件:该检查仅确认表单提交了该字段(即使为空数组也返回 true),必须配合 is_array() 和 count() 进一步判断。
- 文件名安全处理:使用 basename() 防止 ../../etc/passwd 类路径遍历;建议结合 pathinfo() 过滤扩展名。
- 临时目录清理:move_uploaded_file() 后,tmp_name 自动失效,无需手动清理。
- 错误反馈友好化:生产环境应记录详细错误(error_log()),但向用户仅返回泛化提示(如“文件过大”),避免暴露服务器细节。
通过以上结构化校验,可确保任何单个附件一旦超过阈值,整个请求立即终止,彻底杜绝“超限文件仍被发送”的安全隐患。记住:服务端验证不是可选项,而是邮件系统可靠性的基石。
立即学习“PHP免费学习笔记(深入)”;











