
本文详解如何修改 PHP 表单处理器,使其支持 <input type="file" name="userImages[]" multiple> 提交的多个文件,包括文件数组解析、逐个验证、编码与邮件附件组装等完整流程。
本文详解如何修改 php 表单处理器,使其支持 `` 提交的多个文件,包括文件数组解析、逐个验证、编码与邮件附件组装等完整流程。
在 HTML 表单中启用多文件上传仅需为 <input type="file"> 添加 multiple 属性并使用数组式名称(如 name="userImages[]"),但后端 PHP 必须适配 $_FILES 的二维数组结构——这是多数开发者踩坑的核心原因。原代码将 $_FILES['userImages'] 当作单维数组处理(如 $_FILES['userImages']['name']),而实际它是一个按字段键(name, tmp_name, size, error, type)组织的二维数组,需按索引遍历每个上传项。
✅ 正确解析多文件上传数据
当表单提交多个文件时,$_FILES['userImages'] 结构如下:
[ 'name' => ['photo1.jpg', 'logo.png', 'scan.pdf'], 'tmp_name' => ['/tmp/phpabc123', '/tmp/phpdef456', '/tmp/phpghi789'], 'size' => [102400, 5200, 845000], 'error' => [0, 0, 0], 'type' => ['image/jpeg', 'image/png', 'application/pdf'] ]
因此,必须先校验上传是否成功(error === 0),再逐个处理:
// 获取上传文件数组(注意:必须用 [] 命名才能生成此结构)
$files = $_FILES['userImages'];
$name = $_POST['userName'] ?? '';
$email = $_POST['userEmail'] ?? '';
// 检查是否有文件且无错误
if (!isset($files['name']) || !is_array($files['name'])) {
die("未检测到上传文件,请检查表单配置。");
}
$uploadedFiles = [];
for ($i = 0; $i < count($files['name']); $i++) {
if ($files['error'][$i] === UPLOAD_ERR_OK) {
$uploadedFiles[] = [
'name' => $files['name'][$i],
'tmp_name' => $files['tmp_name'][$i],
'size' => $files['size'][$i],
'type' => $files['type'][$i]
];
} else {
// 可记录或跳过失败项(如 UPLOAD_ERR_NO_FILE)
error_log("文件 {$i} 上传失败,错误码: {$files['error'][$i]}");
}
}✅ 构建支持多附件的 MIME 邮件
原代码仅处理单个附件,现需为每个文件生成独立的 MIME 段。关键点:
立即学习“PHP免费学习笔记(深入)”;
- 所有附件共享同一 boundary
- 每个附件段以 --{boundary} 开头
- 最终以 --{boundary}-- 结尾(注意结尾双横线)
// 基础邮件内容
$composition = "\r\n\n\nName: " . htmlspecialchars($name) .
"\r\nEmail Address: " . htmlspecialchars($email);
$subject = "Form Submission";
$fromname = $name;
$fromemail = $email;
$mailto = 'recipient@example.com';
// 生成唯一 boundary
$separator = md5(uniqid(time()));
$eol = "\r\n";
$headers = "From: {$fromname} <{$fromemail}>{$eol}";
$headers .= "MIME-Version: 1.0{$eol}";
$headers .= "Content-Type: multipart/mixed; boundary=\"{$separator}\"{$eol}";
$body = "--{$separator}{$eol}";
$body .= "Content-Type: text/plain; charset=\"utf-8\"{$eol}";
$body .= "Content-Transfer-Encoding: 8bit{$eol}{$eol}";
$body .= $composition . $eol;
// 逐个添加附件
foreach ($uploadedFiles as $file) {
$content = file_get_contents($file['tmp_name']);
if ($content === false) {
error_log("无法读取临时文件: {$file['tmp_name']}");
continue;
}
$encoded = chunk_split(base64_encode($content));
$body .= "--{$separator}{$eol}";
$body .= "Content-Type: {$file['type']}; name=\"{$file['name']}\"{$eol}";
$body .= "Content-Transfer-Encoding: base64{$eol}";
$body .= "Content-Disposition: attachment; filename=\"{$file['name']}\"{$eol}{$eol}";
$body .= $encoded . $eol;
}
$body .= "--{$separator}--"; // 注意结尾双横线
// 发送邮件
if (mail($mailto, $subject, $body, $headers)) {
header('Location: /formSent_confirmationPage.php');
exit;
} else {
die("邮件发送失败,请检查服务器配置。");
}⚠️ 关键注意事项
- 表单 enctype 必须为 multipart/form-data:缺失将导致 $_FILES 为空;
- PHP 配置限制:检查 upload_max_filesize、post_max_size 和 max_file_uploads(默认20),必要时在 php.ini 中调高;
- 安全过滤:对 $name 和 $email 使用 htmlspecialchars() 防止 XSS;对文件名建议重命名(如 uniqid() . '.' . pathinfo($file['name'], PATHINFO_EXTENSION))避免路径遍历;
- 临时文件生命周期:$_FILES['tmp_name'] 在脚本结束时自动删除,务必在 mail() 前完成读取;
- 错误处理:始终检查 $_FILES['userImages']['error'] 数组值,区分 UPLOAD_ERR_OK、UPLOAD_ERR_NO_FILE 等状态。
通过以上改造,您的表单即可稳定支持多图上传并作为邮件附件发送。核心在于理解 $_FILES 的数组维度,并采用循环+MIME 多段结构实现可扩展附件处理。



















