You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PHP多文件上传异常:仅随机传部分文件且数据库存重复记录

多文件上传部分成功+重复记录问题排查与修复

核心问题分析

你的代码存在几个关键问题,直接导致了部分上传失败和重复记录:

1. 文件名重复风险

生成文件名的代码md5(date('Y-m-d H:i:s:u')).'-'.date('YmdHis')存在严重重复概率:

  • 循环执行速度极快,多个文件可能在同一微秒(u)内生成文件名,导致md5结果完全一致
  • 最终多个文件会被重命名为相同的名字,后上传的文件会覆盖之前的,同时数据库会插入重复的文件名记录

2. 错误处理缺失

  • 没有检查每个文件的上传错误状态($_FILES['frm-activity-files']['error'][$i]),即便是上传失败的文件(比如临时文件不存在、尺寸超限),依然会执行数据库插入操作
  • 原判断!empty($_FILES['frm-activity-files']['tmp_name'])逻辑错误:多文件上传时tmp_name是数组,只要数组非空就会进入循环,但数组内可能存在空元素(对应上传失败的文件)

3. 未验证临时文件有效性

调用move_uploaded_file前,没有检查临时文件是否真实存在且是通过HTTP POST上传的,可能导致无效操作

4. 变量未定义风险

代码中$frm_uuid和$frm_uid没有看到赋值逻辑,如果这两个变量未初始化,会导致数据库插入空值,也可能引发其他异常

修复后的代码

HTML部分(无需修改)

<form action="" method="POST" enctype="multipart/form-data">
    <label for="frm-activity-files"><h3>Attach files:</h3></label>
    <input type="file" multiple="multiple" name="frm-activity-files[]">
    <p>Files limited to 10MB each.</p>
</form>

PHP修复版本

<?php
$frm_upload_count = 0;
$frm_upload_path = $_SERVER['DOCUMENT_ROOT'].'/uploads/';
// 确保上传目录存在且可写
if (!is_dir($frm_upload_path)) {
    mkdir($frm_upload_path, 0755, true);
}
// 请确保$frm_uuid和$frm_uid已根据业务逻辑正确赋值
// 示例:$frm_uuid = uniqid('', true); $frm_uid = $_SESSION['user_id'];

// 正确判断多文件上传的数组是否存在且有效
if (isset($_FILES['frm-activity-files']) && is_array($_FILES['frm-activity-files']['tmp_name'])) {
    $error = '';
    $frm_upload_count = count($_FILES['frm-activity-files']['tmp_name']);

    // 提前准备SQL语句,避免循环内重复创建
    $sql_insert_attachment = 'INSERT INTO data__attachments(attachment_auuid, attachment_uid, attachment_filename) VALUES (?,?,?)';
    $stmt_insert_attachment = $mysqli->prepare($sql_insert_attachment);
    if (!$stmt_insert_attachment) {
        die('SQL准备失败: ' . $mysqli->error);
    }

    for ($i = 0; $i < $frm_upload_count; $i++) {
        // 获取当前文件的错误状态
        $file_error = $_FILES['frm-activity-files']['error'][$i];
        $tmp_name = $_FILES['frm-activity-files']['tmp_name'][$i];
        $file_name = $_FILES['frm-activity-files']['name'][$i];

        // 跳过上传失败的文件
        if ($file_error !== UPLOAD_ERR_OK || empty($tmp_name) || !is_uploaded_file($tmp_name)) {
            $error .= "文件{$file_name}上传失败,错误码: {$file_error}\n";
            continue;
        }

        // 生成唯一文件名:用uniqid+随机字符串,避免重复
        $random_suffix = uniqid('', true) . mt_rand(1000, 9999);
        $frm_upload_newname = md5($random_suffix) . '-' . date('YmdHis');
        $frm_upload_ext = pathinfo($file_name, PATHINFO_EXTENSION);
        $frm_upload_rename = $frm_upload_newname . '.' . $frm_upload_ext;

        // 极端情况再次校验文件名唯一性
        while (file_exists($frm_upload_path . $frm_upload_rename)) {
            $frm_upload_newname = md5(uniqid('', true)) . '-' . date('YmdHis');
            $frm_upload_rename = $frm_upload_newname . '.' . $frm_upload_ext;
        }

        // 执行文件移动
        if (move_uploaded_file($tmp_name, $frm_upload_path . $frm_upload_rename)) {
            // 绑定参数并插入数据库
            $stmt_insert_attachment->bind_param("sss", $frm_uuid, $frm_uid, $frm_upload_rename);
            if (!$stmt_insert_attachment->execute()) {
                $error .= "文件{$file_name}数据库插入失败: " . $stmt_insert_attachment->error . "\n";
                // 插入失败时删除已上传的文件
                unlink($frm_upload_path . $frm_upload_rename);
            }
        } else {
            $error .= "文件{$file_name}移动失败\n";
        }
    }

    // 关闭语句
    $stmt_insert_attachment->close();
}
?>

额外检查项

  1. PHP配置确认:再次确认以下配置值是否足够:
    • upload_max_filesize ≥ 10M
    • post_max_size ≥ 上传总文件大小(比如6个10M文件需要≥60M)
    • max_file_uploads ≥ 你允许的最大上传文件数(默认20,一般足够)
  2. 服务器权限:确保/uploads/目录的所有者是Web服务器进程(比如www-data),权限设置为0755或0775
  3. 临时目录权限:PHP的upload_tmp_dir配置的目录需要有可写权限,避免临时文件无法创建

内容的提问来源于stack exchange,提问作者C Wo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 20:03:13