jQuery-File-Upload上传跳转页面且$_FILES['upl']为空问题排查
jQuery-File-Upload 文件上传功能异常修复
问题现象
- 后端
upload.php打印$_FILES['upl']数组时,仅error字段值为4(对应未接收到上传文件的错误码),name、tmp_name、size等其余字段均为空,未正确接收到上传文件数据。 - 文件上传触发后,页面未停留在当前模态框内通过Knob组件展示上传进度与状态,直接跳转至
upload.php页面,单独显示接口echo输出的错误状态。

原有实现代码
模态框文件 uploadTaskAttachments.php
<?php include dirname(__FILE__) . DIRECTORY_SEPARATOR . '../db/dbconnect.php'; require(dirname(__FILE__) . DIRECTORY_SEPARATOR . "../Login/logincheck.php"); $strHTML = "<div class='modal-dialog' role='document'> <div class='modal-content'> <div class='modal-header'> <button type='button' class='close' data-dismiss='modal' aria-label='Close'><span aria-hidden='true'>×</span></button> <h4 class='modal-title' id='edit-modal-label'>Upload Attachments</h4> </div>"; $strHTML .= " <form id='taskUpload' method='post' action='upload.php' enctype='multipart/form-data'> <div id='drop'> Drop Here <a>Browse</a> <input type='file' name='upl' multiple /> </div> <ul> <!-- The file uploads will be shown here --> </ul> </form> </div> </div>"; echo $strHTML; ?>
前端JavaScript逻辑代码
function fnUploadTaskAttachments() { $.ajax({ type: "POST", data: { "id": task_id }, url: "uploadTaskAttachments.php", success: function(data) { $("#UploadTaskAttach").html(data); $('#UploadTaskAttach').modal({ backdrop: false }); $('#UploadTaskAttach').modal('show'); $('#UploadTaskAttach').modal({ refresh: true }); $('#UploadTaskAttach').draggable({ handle: ".modal-header" }); $(function() { var ul = $('#taskUpload ul'); $('#drop a').click(function() { $(this).parent().find('input').click(); }); $('#taskUpload').fileupload({ dropZone: $('#drop'), add: function(e, data) { var tpl = $('<li class="working"><input type="text" value="0" data-width="48" data-height="48"' + ' data-fgColor="#0788a5" data-readOnly="1" data-bgColor="#3e4043" /><p></p><span></span></li>'); tpl.find('p').text(data.files[0].name) .append('<i>' + formatFileSize(data.files[0].size) + '</i>'); data.context = tpl.appendTo(ul); tpl.find('input').knob(); tpl.find('span').click(function() { if (tpl.hasClass('working')) { jqXHR.abort(); } tpl.fadeOut(function() { tpl.remove(); }); }); console.log({data}); var jqXHR = data.submit(); }, progress: function(e, data) { var progress = parseInt(data.loaded / data.total * 100, 10); data.context.find('input').val(progress).change(); if (progress == 100) { data.context.removeClass('working'); } }, fail: function(e, data) { data.context.addClass('error'); } }); $(document).on('drop dragover', function(e) { e.preventDefault(); }); function formatFileSize(bytes) { if (typeof bytes !== 'number') { return ''; } if (bytes >= 1000000000) { return (bytes / 1000000000).toFixed(2) + ' GB'; } if (bytes >= 1000000) { return (bytes / 1000000).toFixed(2) + ' MB'; } return (bytes / 1000).toFixed(2) + ' KB'; } }); } }); }
后端上传处理文件 upload.php
<?php $allowed =array('swf', 'bak', 'msg', 'blank'); if(isset($_FILES['upl']) && $_FILES['upl']['error'] == 0){ $extension = pathinfo($_FILES['upl']['name'], PATHINFO_EXTENSION); if(!in_array(strtolower($extension), $allowed)){ echo '{"status":"error"}'; exit; } if(move_uploaded_file($_FILES['upl']['tmp_name'], $FileServer.$_FILES['upl']['name'])){ echo '{"status":"success"}'; exit; } } echo '{"status":"error"}'; exit; ?>
问题原因
- 页面跳转问题:未阻止表单原生默认提交行为,文件选择后浏览器触发了form原生整页POST请求,没有走jQuery-File-Upload的AJAX异步上传逻辑,因此不会停留在模态框展示进度条。
- 后端收不到文件问题:
- 整页提交的场景下请求逻辑异常,本身就可能出现文件未附带的情况;
- 开启了
multiple多文件上传属性,但file input的name设置为upl,PHP接收多文件上传要求name格式为upl[],否则无法正确解析多文件数组结构; - 后端代码按单文件逻辑编写,未兼容多文件上传的数组格式,即使文件上传成功也无法正确读取。
修复方案
- 第一步:修改模态框内的文件输入框名称,适配PHP多文件接收规则
将<input type='file' name='upl' multiple />修改为<input type='file' name='upl[]' multiple /> - 第二步:阻止表单原生提交,修正前端初始化逻辑
去掉ajax成功回调里冗余的$(function() {})DOM就绪包裹(模态框HTML是动态加载后直接渲染的,此时DOM已就绪,无需额外包裹),给表单绑定submit事件阻止默认行为,同时修正jqXHR变量声明提前的问题,避免取消上传时变量未定义。修正后的核心JS逻辑如下:
function fnUploadTaskAttachments() { $.ajax({ type: "POST", data: { "id": task_id }, url: "uploadTaskAttachments.php", success: function(data) { $("#UploadTaskAttach").html(data); $('#UploadTaskAttach').modal({ backdrop: false }); $('#UploadTaskAttach').modal('show'); $('#UploadTaskAttach').modal({ refresh: true }); $('#UploadTaskAttach').draggable({ handle: ".modal-header" }); var ul = $('#taskUpload ul'); var jqXHR; // 提前声明变量,避免取消时未定义 // 阻止表单原生提交 $('#taskUpload').on('submit', function(e) { e.preventDefault(); }); $('#drop a').click(function() { $(this).parent().find('input').click(); }); $('#taskUpload').fileupload({ dropZone: $('#drop'), dataType: 'json', // 显式指定返回格式为json add: function(e, data) { var tpl = $('<li class="working"><input type="text" value="0" data-width="48" data-height="48"' + ' data-fgColor="#0788a5" data-readOnly="1" data-bgColor="#3e4043" /><p></p><span></span></li>'); tpl.find('p').text(data.files[0].name) .append('<i>' + formatFileSize(data.files[0].size) + '</i>'); data.context = tpl.appendTo(ul); tpl.find('input').knob(); tpl.find('span').click(function() { if (tpl.hasClass('working')) { jqXHR.abort(); } tpl.fadeOut(function() { tpl.remove(); }); }); jqXHR = data.submit(); }, progress: function(e, data) { var progress = parseInt(data.loaded / data.total * 100, 10); data.context.find('input').val(progress).change(); if (progress == 100) { data.context.removeClass('working'); } }, fail: function(e, data) { data.context.addClass('error'); }, done: function(e, data) { // 可在此处处理上传成功后的逻辑 console.log('上传结果', data.result); } }); $(document).on('drop dragover', function(e) { e.preventDefault(); }); function formatFileSize(bytes) { if (typeof bytes !== 'number') { return ''; } if (bytes >= 1000000000) { return (bytes / 1000000000).toFixed(2) + ' GB'; } if (bytes >= 1000000) { return (bytes / 1000000).toFixed(2) + ' MB'; } return (bytes / 1000).toFixed(2) + ' KB'; } } }); }
- 第三步:重写后端
upload.php逻辑,兼容多文件上传处理,修正返回格式:
<?php $allowed = array('swf', 'bak', 'msg', 'blank'); // 提前确认$FileServer变量已正确定义,为文件存储的绝对路径 if (!isset($_FILES['upl']) || empty($_FILES['upl']['name'][0])) { echo json_encode(['status' => 'error', 'msg' => '未接收到上传文件']); exit; } $fileCount = count($_FILES['upl']['name']); $result = ['status' => 'success', 'msg' => '上传成功']; for ($i = 0; $i < $fileCount; $i++) { $errCode = $_FILES['upl']['error'][$i]; if ($errCode !== UPLOAD_ERR_OK) { $result = ['status' => 'error', 'msg' => '文件上传出错,错误码:' . $errCode]; break; } $fileName = $_FILES['upl']['name'][$i]; $tmpPath = $_FILES['upl']['tmp_name'][$i]; $ext = strtolower(pathinfo($fileName, PATHINFO_EXTENSION)); if (!in_array($ext, $allowed)) { $result = ['status' => 'error', 'msg' => '不支持的文件类型:' . $ext]; break; } // 处理存储路径,避免末尾缺少斜杠导致路径拼接错误 $targetPath = rtrim($FileServer, '/') . '/' . $fileName; if (!move_uploaded_file($tmpPath, $targetPath)) { $result = ['status' => 'error', 'msg' => '文件写入失败,请检查目录权限']; break; } } echo json_encode($result); exit; ?>
内容的提问来源于stack exchange,提问作者Rohit Gowda
相关产品推荐
相关产品推荐

