jQuery+PHP多文件上传重复提交问题求助
问题诊断与修复方案
核心问题分析
- 多文件重复上传:大概率是
change事件被重复绑定(比如代码多次执行、动态渲染后重复绑定),导致每次选文件时多个回调同时启动上传流程,每个流程都会遍历所有文件,最终每个文件被上传N次(N为事件绑定次数)。 - 单文件仅传最后一个:原代码中
FormData从现有表单初始化,会包含文件输入框的历史文件,后续set('file', file)的覆盖逻辑在单文件场景下可能被多次执行,最终只保留最后一次设置的文件。
修复代码
前端jQuery代码优化
$('input[type="file"]').off('change').on('change', function (e) { // 变量放在闭包内,避免全局污染 let files = e.target.files; let currentFileIndex = 0; let isUploading = false; const progressBar = $('.js-upload-progress-bar'); function uploadNextFile() { if (currentFileIndex < files.length) { if (!isUploading) { isUploading = true; const file = files[currentFileIndex]; const fileSize = file.size / (1024 * 1024); const fileType = file.type; const isImage = fileType.startsWith('image/'); const isVideo = fileType.startsWith('video/'); if (fileSize <= 1024 && (isImage || isVideo)) { const previewSrc = isVideo ? '../assets/images/icons/icons-video.png' : URL.createObjectURL(file); $('.js-previewImg').attr('src', previewSrc); $('.js-uploadStatus').text(`Uploading ${currentFileIndex + 1}/${files.length}`); // 创建空FormData,手动添加文件和表单字段 const formData = new FormData(); // 若表单有其他字段,手动追加,例如:formData.append('csrf', $('[name="csrf"]').val()); formData.append('file', file); $.ajax({ url: 'upload.php', type: 'POST', data: formData, processData: false, contentType: false, xhr: () => { const xhr = new window.XMLHttpRequest(); xhr.upload.addEventListener('progress', (e) => { if (e.lengthComputable) { const progress = Math.round((e.loaded / e.total) * 100); progressBar.val(progress); } }); return xhr; }, success: (response) => { console.log(response); currentFileIndex++; isUploading = false; uploadNextFile(); }, error: (xhr, status, error) => { console.log(`Error: ${error}`); currentFileIndex++; isUploading = false; uploadNextFile(); } }); } else { console.log('File validation failed'); currentFileIndex++; isUploading = false; uploadNextFile(); } } } else { $('.js-uploadStatus').text('Upload Successful'); setTimeout(() => { $('.uploadProgress').removeClass('show'); $('input[type="file"]').val(''); isUploading = false; }, 1000); progressBar.val(0); currentFileIndex = 0; } } uploadNextFile(); $('.uploadProgress').addClass('show'); });
后端PHP接收脚本示例
<?php $targetDir = 'uploads/'; // 确保上传目录存在 if (!is_dir($targetDir)) mkdir($targetDir, 0755, true); if ($_FILES['file']['error'] === UPLOAD_ERR_OK) { $fileName = uniqid() . '-' . basename($_FILES['file']['name']); $targetFile = $targetDir . $fileName; if (move_uploaded_file($_FILES['file']['tmp_name'], $targetFile)) { echo json_encode(['status' => 'success', 'file' => $fileName]); } else { echo json_encode(['status' => 'error', 'msg' => 'Failed to save file']); } } else { echo json_encode(['status' => 'error', 'msg' => 'Upload error: ' . $_FILES['file']['error']]); } ?>
关键修复点
- 用
off('change')强制解绑后再绑定,避免事件重复触发上传流程。 - 将控制变量放在事件回调闭包内,彻底避免全局变量冲突。
- 初始化空
FormData并手动添加文件,排除原表单历史数据的干扰。
内容的提问来源于stack exchange,提问作者Forever Edits
相关产品推荐
相关产品推荐

