登录
推荐 文章 Go 技术 课程 下载 专题 AI
首页 >  文章 >  php教程

PHP 上传进度怎么取消当前文件而不影响已经完成的文件

来源:17golang原创

时间:2026-10-13 08:22:46 442浏览 收藏

我在处理多文件上传时,最容易把“取消当前文件”和“删除已完成文件”混成一个动作。PHP 的 Session Upload Progress 已经提供了一个清晰的边界:把对应进度项的 cancel_upload 设为 true,会取消当前正在上传的文件和同一请求中还没开始处理的文件,但不会移除已经成功完成的文件。

真正的做法是:用独立的进度查询请求定位同一个 Session 进度项,在服务端设置 $_SESSION[$key]['cancel_upload'] = true;上传处理端再根据 UPLOAD_ERR_EXTENSION 区分取消结果。它不是断点续传,也不是删除接口。

官方参考地址:https://www.php.net/manual/en/session.upload-progress.php

先把上传请求和取消请求绑定到同一个进度项

Session Upload Progress 的关键不是“前端点击了取消”,而是两个请求能否找到同一个 Session 数组。上传表单提交一个与 session.upload_progress.name 同名的隐藏字段,PHP 会把进度写进 $_SESSION;查询接口再用配置项的前缀和这个字段值拼出索引。

进度索引通常可以写成下面这样。这里的值来自本次 POST 的隐藏字段,不能把一个新生成的随机值直接拿来查询,否则查到的不是正在上传的那一项。

PHP 多文件上传请求、进度查询请求与 Session cancel_upload 字段的关系示意图
图1:PHP 上传取消的会话关系示意图,取消标记作用于当前与待处理文件,已完成文件保持不变。

取消接口只修改 cancel_upload 标记

取消接口可以和进度查询接口分开,也可以复用同一个入口。它的职责应该很窄:校验当前用户能操作这次上传,定位进度项,然后只写入 cancel_upload。不要在这里删除已完成文件,也不要把上传记录直接标记成“全部失败”。

 128) {
    http_response_code(400);
    echo json_encode(['ok' => false, 'message' => '无效的上传标识'], JSON_UNESCAPED_UNICODE);
    exit;
}

$key = $prefix . $progressValue;

// 不存在时返回可重复调用的结果,避免取消按钮重试造成二次副作用
if (!isset($_SESSION[$key]) || !is_array($_SESSION[$key])) {
    echo json_encode(['ok' => true, 'state' => 'not-found-or-finished'], JSON_UNESCAPED_UNICODE);
    exit;
}

// PHP 会据此取消当前进行中的文件和同请求中的待处理文件
$_SESSION[$key]['cancel_upload'] = true;

echo json_encode(['ok' => true, 'state' => 'cancel-requested'], JSON_UNESCAPED_UNICODE);
?>

这里的“当前”是 PHP 此刻正在接收或处理的那个文件;如果同一个请求里还有排队的文件,它们也会被取消。已经完成的文件不在这个取消范围内。也就是说,取消接口不能替代业务层的文件清理策略:已完成文件是否保留、是否从业务表撤销,仍应由单独的业务动作决定。

按文件状态和错误码收口处理结果

上传脚本收到请求后,不要只看 HTTP 状态码。要遍历 $_FILES,把已经成功保存、被取消和真正失败的文件分开记录。PHP 手册说明,被取消的上传会把对应 error 设为 UPLOAD_ERR_EXTENSION;它是这个功能的结果信号,不应被误报为普通扩展限制故障。

 $error) {
    $name = $_FILES['files']['name'][$index] ?? '';

    if ($error === UPLOAD_ERR_OK) {
        // 只有校验通过后才把临时文件转成已完成业务记录
        echo "completed: " . htmlspecialchars($name, ENT_QUOTES, 'UTF-8') . "\n";
        continue;
    }

    if ($error === UPLOAD_ERR_EXTENSION) {
        // 取消结果单独记录,便于前端显示“已取消”而非“上传失败”
        echo "cancelled: " . htmlspecialchars($name, ENT_QUOTES, 'UTF-8') . "\n";
        continue;
    }

    // 其它错误仍按 PHP 上传错误码进入失败处理和告警
    echo "failed(" . $error . "): " . htmlspecialchars($name, ENT_QUOTES, 'UTF-8') . "\n";
}
?>

处理结果可以按下面的表理解:

文件状态取消后的结果业务处理
已经完成保留,不被 cancel_upload 删除保留成功记录;如需撤销,走独立删除或撤回动作
当前进行中停止当前文件上传按取消状态记录,不把它当成成功文件
同请求中待处理不会继续处理记录为取消或未处理,避免自动补写业务表
其它上传错误不等同于取消保留原始错误码,进入常规失败排查
PHP 多文件上传取消后已完成、当前和待处理文件的结果与错误码示意图
图2:取消结果与排查边界示意图,把文件状态、错误码和请求缓冲放在同一张静态图里。

取消无效时先查请求缓冲和 Session 条件

如果点击取消后进度仍然不变,我会先查基础设施,而不是先改前端按钮。PHP 手册明确提醒:Web 服务器的请求缓冲需要关闭,否则 PHP 可能要等到文件完整上传后才看到请求;Nginx 对较大的请求尤其需要关注这一点。缓冲没有释放时,取消接口即使代码正确,也可能来不及影响上传。

  1. 确认进度开关:检查 session.upload_progress.enabled 是否开启,并确认表单包含正确的进度字段。
  2. 确认索引一致:取消请求使用的字段名、字段值、Session ID 和上传请求一致;不要把配置中的字段名误当成字段值。
  3. 确认 Session 已初始化:生成表单和处理查询、取消的脚本都要在读取或写入 $_SESSION 前调用 session_start()。
  4. 确认缓冲层:检查 Nginx 或其它 Web 服务器是否先缓存整个 multipart 请求;否则服务端进度信息可能只在请求结束时出现。
  5. 确认并发路径:上传、进度查询和取消使用同一个用户会话,并让取消接口只修改该用户有权操作的进度项。

还有一个容易忽略的边界:上传进度信息是在脚本执行前写入 Session 的。不要在应用代码中临时切换 Session 名称,也不要假设自定义 Session handler 一定能接管这部分进度数据。遇到“查询接口永远为空”时,应先对照 PHP 配置和服务器请求路径。

把取消动作做成可回退的运行手册

我更倾向于把取消当成一个状态变更,而不是删除动作。建议业务记录至少保留上传批次标识、文件名、当前状态、PHP 错误码、操作者、请求时间和清理结果。这样即使用户连续点击取消,接口也可以返回“已请求取消”或“已结束”,不会重复删除已经完成的文件。

回退路径也要明确:如果取消发生在当前文件尚未落库之前,清理临时文件并把该项记为 cancelled;如果前一个文件已经成功落库,就保留它,同时把当前及后续文件记为 cancelled;如果网络断开但 PHP 仍在接收请求,则由进度查询或后台清理任务收口孤立临时文件。不要用“删除整个批次”来模拟单文件取消。

常见问题

cancel_upload 会删除已经上传成功的文件吗?

不会。它针对当前进行中的文件和同一次请求中待处理的文件,成功完成的文件不会被这个标记移除。

为什么取消后看到的是 UPLOAD_ERR_EXTENSION?

这是 Session Upload Progress 取消路径写入 $_FILES 的错误码。业务层应把它映射为“已取消”,不要直接显示成扩展限制故障。

是不是只要前端中断 XHR 就能取消?

不能把前端断开当成服务端取消确认。真正的取消需要服务端找到进度项并设置 cancel_upload;前端中断只说明客户端不再等待响应。

为什么进度查询接口一直拿不到数据?

先检查进度开关、隐藏字段、Session ID、请求缓冲和 Session 初始化。尤其要确认取消请求传入的是隐藏字段的值,并且两个请求实际使用同一会话。

总结一下:PHP 的取消粒度已经定义得很明确。把 cancel_upload 写到正确的 Session 进度项,当前文件和待处理文件会停止,已完成文件保持不动;随后用 UPLOAD_ERR_EXTENSION 收口状态,并从请求缓冲和会话一致性两条基础链路排查“取消不生效”。

声明:本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>