
本文详解如何在 PHP 后端正确接收、验证并邮件发送 HTML 表单中通过 multiple 属性上传的多个图像文件,涵盖数组化 $_FILES 结构解析、循环处理、附件编码及 MIME 邮件构建等关键步骤。
本文详解如何在 php 后端正确接收、验证并邮件发送 html 表单中通过 `multiple` 属性上传的多个图像文件,涵盖数组化 `$_files` 结构解析、循环处理、附件编码及 mime 邮件构建等关键步骤。
HTML 表单中使用 是启用多文件上传的正确方式——关键在于 name 属性末尾的 [],它使浏览器将所有选中文件以关联数组形式提交至 $_FILES['userImages']。但原 PHP 代码仍按单文件逻辑访问 $_FILES['userImages']['name'] 等键,这会导致仅获取第一个文件名(PHP 会自动降维为标量),且无法遍历其余文件。
✅ 正确解析多文件上传的 $_FILES 结构
当提交多个文件时,$_FILES['userImages'] 不再是单层数组,而是包含五个平行子数组的二维结构:
$_FILES['userImages'] = [ 'name' => ['photo1.jpg', 'photo2.png', 'logo.svg'], 'type' => ['image/jpeg', 'image/png', 'image/svg+xml'], 'tmp_name' => ['/tmp/phpabc123', '/tmp/phpdef456', '/tmp/phpghi789'], 'error' => [0, 0, 0], 'size' => [24567, 89123, 1245] ];
因此,必须使用 foreach 按索引同步遍历各字段:
if (!empty($_FILES['userImages']['name'][0])) {
$fileNames = $_FILES['userImages']['name'];
$fileTmps = $_FILES['userImages']['tmp_name'];
$fileSizes = $_FILES['userImages']['size'];
$fileErrors = $_FILES['userImages']['error'];
for ($i = 0; $i 5 * 1024 * 1024) {
die("Error: File {$fileNames[$i]} exceeds 5MB limit.");
}
$finfo = finfo_open(FILEINFO_MIME_TYPE);
$mimeType = finfo_file($finfo, $fileTmps[$i]);
finfo_close($finfo);
if (!in_array($mimeType, ['image/jpeg', 'image/png', 'image/gif', 'image/webp'])) {
die("Error: {$fileNames[$i]} is not a supported image type.");
}
// 读取并 Base64 编码文件内容(用于邮件附件)
$content = file_get_contents($fileTmps[$i]);
$encoded = chunk_split(base64_encode($content));
// 构建该附件的 MIME 段(见下文整合逻辑)
$attachmentPart = "--" . $separator . $eol
. "Content-Type: " . $mimeType . "; name=\"" . $fileNames[$i] . "\"" . $eol
. "Content-Transfer-Encoding: base64" . $eol
. "Content-Disposition: attachment; filename=\"" . $fileNames[$i] . "\"" . $eol . $eol
. $encoded . $eol;
$body .= $attachmentPart;
}
}
? 构建支持多附件的 MIME 邮件正文
原始代码仅附加一个文件,需将所有合法附件追加到 $body 中,并确保每个附件段以 --$separator 分隔,结尾用 --$separator-- 标记结束。完整邮件头保持不变,但正文结构需扩展:
// 初始化邮件主体(文本部分)
$body = "--" . $separator . $eol;
$body .= "Content-Type: text/plain; charset=\"utf-8\"" . $eol;
$body .= "Content-Transfer-Encoding: 8bit" . $eol;
$body .= $composition . $eol;
// 追加所有有效附件
if (!empty($fileNames)) {
foreach (array_keys($fileNames) as $i) {
if (empty($fileNames[$i]) || $fileErrors[$i] !== UPLOAD_ERR_OK) continue;
$content = file_get_contents($fileTmps[$i]);
$encoded = chunk_split(base64_encode($content));
$mimeType = $_FILES['userImages']['type'][$i];
$body .= "--" . $separator . $eol;
$body .= "Content-Type: " . $mimeType . "; name=\"" . $fileNames[$i] . "\"" . $eol;
$body .= "Content-Transfer-Encoding: base64" . $eol;
$body .= "Content-Disposition: attachment; filename=\"" . $fileNames[$i] . "\"" . $eol . $eol;
$body .= $encoded . $eol;
}
}
// 结束 multipart 边界
$body .= "--" . $separator . "--";
⚠️ 重要注意事项
- 表单 enctype 必须为 multipart/form-data:缺失将导致 $_FILES 为空;
- name 属性必须含 []:如 name="userImages[]",否则 PHP 无法生成数组结构;
- 务必校验 $_FILES['...']['error']:UPLOAD_ERR_OK(值为 0)是唯一成功标识,其他值(如 4=无文件)需显式处理;
- 临时文件仅在脚本执行期间有效:$_FILES['...']['tmp_name'] 指向的文件会在脚本结束时被 PHP 自动删除,不可延迟处理;
- 邮件附件大小受 SMTP 服务商限制:单封邮件通常限 10–25MB,建议前端限制总上传体积,并提示用户;
- 生产环境应使用 PHPMailer 或 Symfony Mailer:手动构造 MIME 邮件易出错,且缺乏 TLS/SMTP 认证支持。
通过以上改造,你的 formHandler.php 即可健壮地处理任意数量的图像上传,并通过邮件完整送达——既解决了“只发一个”的核心痛点,也为后续扩展(如保存到服务器、生成缩略图等)打下规范基础。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











