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

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'>&times;</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;
?>

问题原因

  1. 页面跳转问题:未阻止表单原生默认提交行为,文件选择后浏览器触发了form原生整页POST请求,没有走jQuery-File-Upload的AJAX异步上传逻辑,因此不会停留在模态框展示进度条。
  2. 后端收不到文件问题:
    • 整页提交的场景下请求逻辑异常,本身就可能出现文件未附带的情况;
    • 开启了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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 15:24:21