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(); } ?>
额外检查项
- PHP配置确认:再次确认以下配置值是否足够:
upload_max_filesize≥ 10Mpost_max_size≥ 上传总文件大小(比如6个10M文件需要≥60M)max_file_uploads≥ 你允许的最大上传文件数(默认20,一般足够)
- 服务器权限:确保
/uploads/目录的所有者是Web服务器进程(比如www-data),权限设置为0755或0775 - 临时目录权限:PHP的
upload_tmp_dir配置的目录需要有可写权限,避免临时文件无法创建
内容的提问来源于stack exchange,提问作者C Wo
相关产品推荐
相关产品推荐

