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

PHP实现≤4MB字节范围文件拆分的方案咨询(适配Outlook上传)

我之前做过类似的Outlook大附件上传需求,用PHP实现文件拆分上传的核心其实就是按字节范围分片读取文件,然后配合Graph的上传会话接口逐个上传分片。给你整理了一套完整的方案,包含代码示例和关键注意点:

PHP实现Outlook大附件分片上传方案

核心思路

  • 先确定单块最大尺寸:建议设为3.8MB(3984588字节),留足HTTP头的额外空间,避免触发4MB的邮件服务器限制
  • 通过filesize()获取文件总大小,计算需要拆分的分片数量
  • 逐片读取文件的字节范围,构造符合Graph要求的Content-Range请求头,上传每个分片
  • 所有分片上传完成后,调用上传会话接口完成整个附件的上传

代码实现步骤

1. 定义基础配置

// 单块最大字节数(3.8MB,预留缓冲避免超4MB)
define('CHUNK_SIZE', 3984588); 
// 从Graph创建上传会话后得到的上传URL
$uploadUrl = "你的上传会话URL";
// 要上传的文件路径
$filePath = "/path/to/your/large/file.pdf";

2. 初始化文件与分片参数

// 以二进制模式打开文件,避免内容损坏
$fileHandle = fopen($filePath, 'rb');
if (!$fileHandle) {
    die("无法打开文件,请检查路径或权限");
}

// 获取文件总大小
$fileSize = filesize($filePath);
// 计算总分片数(向上取整)
$totalChunks = ceil($fileSize / CHUNK_SIZE);

3. 循环上传每个分片

for ($chunkIndex = 0; $chunkIndex < $totalChunks; $chunkIndex++) {
    // 计算当前分片的字节起始和结束位置
    $startByte = $chunkIndex * CHUNK_SIZE;
    $endByte = min(($chunkIndex + 1) * CHUNK_SIZE - 1, $fileSize - 1);
    
    // 定位到当前分片的起始位置
    fseek($fileHandle, $startByte);
    // 读取当前分片内容
    $chunkContent = fread($fileHandle, CHUNK_SIZE);
    
    // 构造请求头,Content-Range是Graph要求的必填项
    $headers = [
        "Content-Type: application/octet-stream",
        "Content-Range: bytes $startByte-$endByte/$fileSize"
    ];
    
    // 用CURL发送POST请求上传分片
    $ch = curl_init($uploadUrl);
    curl_setopt($ch, CURLOPT_POST, true);
    curl_setopt($ch, CURLOPT_POSTFIELDS, $chunkContent);
    curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true); // 生产环境务必开启
    
    $response = curl_exec($ch);
    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);
    
    // Graph返回202表示分片上传成功,最后一块可能返回201
    if (!in_array($httpCode, [202, 201])) {
        die("第{$chunkIndex+1}块上传失败,HTTP状态码:$httpCode,响应内容:$response");
    }
    
    echo "第{$chunkIndex+1}/{$totalChunks}块上传成功\n";
}

4. 完成上传会话(可选,部分场景最后一块上传后自动完成)

如果所有分片上传后未自动触发完成,需要发送收尾请求:

$finalHeaders = [
    "Content-Range: bytes */$fileSize"
];

$ch = curl_init($uploadUrl);
curl_setopt($ch, CURLOPT_PUT, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, $finalHeaders);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);

$finalResponse = curl_exec($ch);
$finalHttpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

if ($finalHttpCode == 201) {
    echo "文件上传完成!";
} else {
    die("上传会话收尾失败,HTTP状态码:$finalHttpCode,响应内容:$finalResponse");
}

// 关闭文件句柄
fclose($fileHandle);

关键注意事项

  • 分片大小选择:绝对不要设为刚好4MB,HTTP请求头会占用额外字节,导致单请求总大小超过限制,建议预留10%-20%的缓冲
  • 二进制读取:必须用'rb'模式打开文件,避免Windows系统下的换行符转换导致文件内容损坏
  • 重试机制:建议给分片上传添加重试逻辑(比如失败后重试3次),避免网络波动导致上传失败
  • 状态记录:如果是超大文件,建议记录每个分片的上传状态,避免中断后重新上传所有分片
  • SSL验证:生产环境请保持CURLOPT_SSL_VERIFYPEER为true,避免安全风险

内容的提问来源于stack exchange,提问作者Oliver

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.08 21:07:56