0

0

PHP 文件上传大小验证:正确实现与常见错误修复

花韻仙語

花韻仙語

发布时间:2026-03-07 10:58:09

|

899人浏览过

|

来源于php中文网

原创

PHP 文件上传大小验证:正确实现与常见错误修复

本文详解如何在 php 中为多文件上传添加可靠的大小验证逻辑,避免因误用 $_files 数组结构导致的验证失效问题,并结合 phpmailer 实现安全、健壮的邮件附件发送流程。

本文详解如何在 php 中为多文件上传添加可靠的大小验证逻辑,避免因误用 $_files 数组结构导致的验证失效问题,并结合 phpmailer 实现安全、健壮的邮件附件发送流程。

在使用 PHP 处理多文件上传并集成至邮件系统(如 PHPMailer)时,文件大小验证失效是高频问题——代码看似完整,却无法阻止超限文件被附加并发送。根本原因往往并非逻辑缺失,而是对 $_FILES 超全局数组结构的误解。下面我们将从结构解析、验证实现、错误处理到完整示例,系统性构建一套可落地的解决方案。

✅ 正确理解 $_FILES 的嵌套结构

PHP 将每个同名多文件字段(如 )解析为一个二维数组,其键为 name、type、tmp_name、error、size —— 全部位于 $_FILES['uploaded-file'] 下一级,而非嵌套在 ['name'] 内部。

❌ 错误写法(导致始终跳过验证):

$_FILES['uploaded-file']['name'][$i]['size'] // 不存在!
$_FILES['uploaded-file']['name'][$i] > $max_size // 比较的是文件名字符串,非字节数!

✅ 正确路径:

Post AI
Post AI

博客文章AI生成器

下载

立即学习PHP免费学习笔记(深入)”;

$_FILES['uploaded-file']['size'][$i]      // ✅ 当前第 i 个文件的大小(字节)
$_FILES['uploaded-file']['error'][$i]     // ✅ 当前第 i 个文件的上传错误码
$_FILES['uploaded-file']['tmp_name'][$i]  // ✅ 临时文件路径(用于 move_uploaded_file)
$_FILES['uploaded-file']['name'][$i]       // ✅ 原始文件名(需过滤/转义)

✅ 完整、健壮的文件大小验证流程

以下为修正后的核心逻辑,已整合进 PHPMailer 发送流程,并包含关键防护点:

<?php
use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\Exception;
require 'vendor/autoload.php';

if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
    die('Invalid request method.');
}

// 防垃圾邮件(蜜罐)
if (!empty(trim($_POST['honey'] ?? ''))) {
    http_response_code(403);
    echo "SPAM detected.";
    exit;
}

// 配置基础信息
$user_name  = $_POST['name'] ?? '';
$user_email = filter_var($_POST['email'] ?? '', FILTER_SANITIZE_EMAIL);
$user_message = $_POST['message'] ?? '';
$user_phone = $_POST['phone'] ?? '';
$max_size   = 2 * 1024 * 1024; // 2 MB(注意:1024×1024,原文 1204 是笔误)

// ✅ 关键:检查 $_FILES 是否存在且非空(使用 count > 0 更可靠)
$attachments = $_FILES['uploaded-file'] ?? null;
$has_files = is_array($attachments) && !empty($attachments['name']);

$mail = new PHPMailer(true);
try {
    $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\nTreść wiadomości:\n" . $user_message;

    // ✅ 处理附件:逐个验证 + 安全移动 + 附加
    if ($has_files) {
        $upload_dir = __DIR__ . '/uploads/';
        if (!is_dir($upload_dir) && !mkdir($upload_dir, 0755, true)) {
            throw new Exception('Upload directory not writable.');
        }

        $file_count = count($attachments['name']);
        for ($i = 0; $i < $file_count; $i++) {
            $tmp_path = $attachments['tmp_name'][$i] ?? '';
            $orig_name = $attachments['name'][$i] ?? '';
            $size = $attachments['size'][$i] ?? 0;
            $error = $attachments['error'][$i] ?? UPLOAD_ERR_NO_FILE;

            // ✅ 忽略空文件或上传失败项
            if ($error !== UPLOAD_ERR_OK) {
                error_log("File upload error #{$error} at index {$i}");
                continue;
            }

            // ✅ 核心:大小验证(单位:字节)
            if ($size === 0 || $size > $max_size) {
                throw new Exception("File '{$orig_name}' exceeds maximum size of " . 
                    number_format($max_size / 1024, 0) . " KB.");
            }

            // ✅ 安全生成唯一文件名(防覆盖 & XSS)
            $safe_name = preg_replace('/[^a-zA-Z0-9._-]/', '_', $orig_name);
            $unique_name = uniqid() . '_' . $safe_name;
            $target_path = $upload_dir . $unique_name;

            // ✅ 移动临时文件(失败则抛异常)
            if (!move_uploaded_file($tmp_path, $target_path)) {
                throw new Exception("Failed to save uploaded file: {$orig_name}");
            }

            // ✅ 添加至邮件(使用绝对路径更可靠)
            $mail->addAttachment($target_path, $orig_name);
        }
    }

    $mail->send();
    header('Location: sent.html');
    exit;

} catch (Exception $e) {
    error_log('Mailer exception: ' . $e->getMessage());
    echo "Error: " . htmlspecialchars($e->getMessage());
}

⚠️ 关键注意事项与最佳实践

  • $_FILES 判空逻辑:isset($_FILES['xxx']) 仅判断字段是否存在,不保证有有效文件;应结合 count($_FILES['xxx']['name']) > 0 或检查 $_FILES['xxx']['error'][0] !== UPLOAD_ERR_NO_FILE。
  • 错误码优先级:始终先检查 $_FILES['...']['error'][$i],再检查 size。网络中断、用户取消上传等均会导致 error ≠ UPLOAD_ERR_OK,此时 size 可能为 0 或不可信。
  • 单位一致性:$_FILES['...']['size'] 单位为字节,2 * 1024 * 1024 = 2MB(原文 1204 为明显笔误,已修正)。
  • 临时文件清理:move_uploaded_file() 成功后,PHP 会自动清理临时文件;若验证失败未移动,则需手动 unlink($tmp_path)(本例中因 continue 跳过,故无需额外清理)。
  • 安全性加固
    • 使用 filter_var(..., FILTER_SANITIZE_EMAIL) 过滤邮箱;
    • 对输出内容使用 htmlspecialchars() 防 XSS;
    • 重命名上传文件(移除特殊字符+加随机前缀),避免路径遍历或执行风险;
    • 设置 uploads/ 目录无脚本执行权限(如 Apache 中配置 Options -ExecCGI)。

通过以上重构,你的文件大小验证将真正生效:任何单个附件超过 2MB 时,脚本将立即终止并返回明确错误,绝不会进入邮件发送环节。这不仅是修复 Bug,更是构建生产级表单处理流程的必要基石。

相关文章

PHP速学教程(入门到精通)
PHP速学教程(入门到精通)

PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
counta和count的区别
counta和count的区别

Count函数用于计算指定范围内数字的个数,而CountA函数用于计算指定范围内非空单元格的个数。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

203

2023.11.20

scripterror怎么解决
scripterror怎么解决

scripterror的解决办法有检查语法、文件路径、检查网络连接、浏览器兼容性、使用try-catch语句、使用开发者工具进行调试、更新浏览器和JavaScript库或寻求专业帮助等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

451

2023.10.18

500error怎么解决
500error怎么解决

500error的解决办法有检查服务器日志、检查代码、检查服务器配置、更新软件版本、重新启动服务、调试代码和寻求帮助等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

373

2023.10.25

java break和continue
java break和continue

本专题整合了java break和continue的区别相关内容,阅读专题下面的文章了解更多详细内容。

261

2025.10.24

点击input框没有光标怎么办
点击input框没有光标怎么办

点击input框没有光标的解决办法:1、确认输入框焦点;2、清除浏览器缓存;3、更新浏览器;4、使用JavaScript;5、检查硬件设备;6、检查输入框属性;7、调试JavaScript代码;8、检查页面其他元素;9、考虑浏览器兼容性。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

197

2023.11.24

apache是什么意思
apache是什么意思

Apache是Apache HTTP Server的简称,是一个开源的Web服务器软件。是目前全球使用最广泛的Web服务器软件之一,由Apache软件基金会开发和维护,Apache具有稳定、安全和高性能的特点,得益于其成熟的开发和广泛的应用实践,被广泛用于托管网站、搭建Web应用程序、构建Web服务和代理等场景。本专题为大家提供了Apache相关的各种文章、以及下载和课程,希望对各位有所帮助。

419

2023.08.23

apache启动失败
apache启动失败

Apache启动失败可能有多种原因。需要检查日志文件、检查配置文件等等。想了解更多apache启动的相关内容,可以阅读本专题下面的文章。

938

2024.01.16

Java 流式处理与 Apache Kafka 实战
Java 流式处理与 Apache Kafka 实战

本专题专注讲解 Java 在流式数据处理与消息队列系统中的应用,系统讲解 Apache Kafka 的基础概念、生产者与消费者模型、Kafka Streams 与 KSQL 流式处理框架、实时数据分析与监控,结合实际业务场景,帮助开发者构建 高吞吐量、低延迟的实时数据流管道,实现高效的数据流转与处理。

131

2026.02.04

JavaScript浏览器渲染机制与前端性能优化实践
JavaScript浏览器渲染机制与前端性能优化实践

本专题围绕 JavaScript 在浏览器中的执行与渲染机制展开,系统讲解 DOM 构建、CSSOM 解析、重排与重绘原理,以及关键渲染路径优化方法。内容涵盖事件循环机制、异步任务调度、资源加载优化、代码拆分与懒加载等性能优化策略。通过真实前端项目案例,帮助开发者理解浏览器底层工作原理,并掌握提升网页加载速度与交互体验的实用技巧。

1

2026.03.06

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
PHP课程
PHP课程

共137课时 | 13万人学习

JavaScript ES5基础线上课程教学
JavaScript ES5基础线上课程教学

共6课时 | 11.3万人学习

PHP新手语法线上课程教学
PHP新手语法线上课程教学

共13课时 | 1.0万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号