PHP Session Upload Progress 上传进度读取为空问题求助
问题根因
三个核心问题直接导致上传进度读取失败:
- 进度查询接口传参错误:
getting_progress()里直接把jQuery对象$('#systemName')当POST数据传,后端拿不到进度标识参数,拼不对session里存储进度的key。 - 上传请求序列化逻辑错误:jQuery原生没有
serializefiles()方法,如果你没提前自定义该方法,会直接抛出JS错误,上传请求根本不会发送;就算自定义了方法,如果没把表单里的隐藏进度标识字段和文件一起提交,PHP内核不会触发进度写入session的逻辑。 - Session锁阻塞:默认文件Session驱动带写锁,上传请求如果长时间持有session锁,会导致进度查询请求的
session_start()一直阻塞,直到上传完成才会返回,自然拿不到实时进度。
修复方案
前端代码修复
删除依赖未知第三方方法的序列化逻辑,直接用原生FormData处理表单数据,同时修正进度查询的传参逻辑:
$('.uploadBtn').on('click', function(){ // 直接用原生FormData序列化整个表单,自动包含隐藏进度字段和文件数据 var formData = new FormData($('#uploadForm')[0]); $.ajax({ url: 'upload.php', type: 'post', dataType: 'json', data: formData, async: true, cache: false, contentType: false, processData: false, success: function(json){ if(json.success){ $.jGrowl(json.success); } else if(json.error){ $.jGrowl(json.error); } }, error: function(jqXHR, status){ $.jGrowl('AJAX请求错误: ' + status); } }); getting_progress(); }); function getting_progress(){ var interval_id = setInterval(function () { // 正确拼接进度查询需要的POST参数 var progressInput = $('#systemName'); var postData = {}; postData[progressInput.attr('name')] = progressInput.val(); $.ajax({ url: 'progress.php', type: 'post', dataType: 'json', data: postData, success: function(json){ if(json.completed){ clearInterval(interval_id); $.jGrowl('上传完成'); } else if(json.progress !== undefined){ // 此处可绑定页面进度条渲染逻辑,json.progress为已上传百分比 console.log('上传进度:' + json.progress + '%'); } else if(json.error){ $.jGrowl(json.error); clearInterval(interval_id); } }, error: function(jqXHR, status){ $.jGrowl('进度查询错误: ' + status); } }); }, 1000); }
progress.php 修复
启动session后立刻释放写锁避免阻塞,补充进度计算逻辑:
<?php session_start(); // 立刻关闭session写锁,避免阻塞上传请求的写入 session_write_close(); $progressName = ini_get("session.upload_progress.name"); if (!isset($_POST[$progressName])) { echo json_encode(['error' => '缺少进度标识参数'], JSON_UNESCAPED_UNICODE); exit; } $key = ini_get("session.upload_progress.prefix") . $_POST[$progressName]; if (!isset($_SESSION[$key])) { echo json_encode(['error' => '未找到上传进度,session内容:'.json_encode($_SESSION)], JSON_UNESCAPED_UNICODE); exit; } $progressData = $_SESSION[$key]; $totalSize = $progressData['content_length']; $uploadedSize = $progressData['bytes_processed']; $percent = round($uploadedSize / $totalSize * 100, 2); if ($progressData['done'] || $percent >= 100) { echo json_encode(['completed' => true, 'progress' => 100], JSON_UNESCAPED_UNICODE); } else { echo json_encode(['progress' => $percent], JSON_UNESCAPED_UNICODE); } exit;
upload.php 修复
启动session后立刻释放锁,避免后续文件处理逻辑长时间占用锁资源:
<?php session_start(); // 提前释放session锁,不要在文件移动、校验等耗时逻辑里持有锁 session_write_close(); // 原有文件上传处理逻辑写在这里,比如格式校验、移动文件到存储目录等 if (!empty($_FILES['video'])) { echo json_encode(['success' => '文件上传处理完成'], JSON_UNESCAPED_UNICODE); } else { echo json_encode(['error' => '未接收到上传文件'], JSON_UNESCAPED_UNICODE); } exit;
额外检查项
注意:测试时请使用100MB以上的大文件,小文件上传速度过快会导致进度查询还未启动就已完成,无法捕获中间进度
- 确认php.ini中
short_open_tag配置为On,否则HTML里的<? echo ini_get("session.upload_progress.name"); ?>不会被PHP解析,隐藏域的name值会是错误的字面量,PHP无法识别进度标识。 - 确认两个接口请求域名、端口完全一致,不存在跨域导致session不共享的问题。
- 确认
session.upload_progress.cleanup = Off配置已生效,避免上传完成后内核立刻清空进度数据。
内容的提问来源于stack exchange,提问作者Майкл Миллер
相关产品推荐
相关产品推荐

