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

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,提问作者Майкл Миллер

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 23:57:26