如何使用 PHP-Curl 将大文件上传到 Onedrive

How Upload large files to Onedrive using PHP-Curl

我需要将大于 4MB 的文件上传到 onedrive 帐户。我正在尝试 PHP 并为此卷曲。有没有人试过这个选项,请帮我解决这个问题。

$url='https://graph.microsoft.com/v1.0/me/drive/root:/filename:/createUploadSession';

    $data= '{}';
    $header = array('Content-Type: json',
        "Cache-Control: no-cache",
        "Pragma: no-cache",
        "Authorization: bearer {Access Token}");
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_POST, TRUE);
        curl_setopt($ch, CURLOPT_HTTPHEADER, $header );
        curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);

从结果中获取上传URL,

    $graph_url = $result['uploadUrl'];
    $fragSize = 320 * 1024;
    $file = file_get_contents($filename_location);
    $fileSize = strlen($file);
    $numFragments = ceil($fileSize / $fragSize);
    $bytesRemaining = $fileSize;
    $i = 0;
    $ch = curl_init($graph_url);
    while ($i < $numFragments) {
        $chunkSize = $numBytes = $fragSize;
        $start = $i * $fragSize;
        $end = $i * $fragSize + $chunkSize - 1;
        $offset = $i * $fragSize;
        if ($bytesRemaining < $chunkSize) {
            $chunkSize = $numBytes = $bytesRemaining;
            $end = $fileSize - 1;
        }
        if ($stream = fopen($filename_location, 'r')) {
            // get contents using offset
            $data = stream_get_contents($stream, $chunkSize, $offset);
            fclose($stream);
        }

        $content_range = " bytes " . $start . "-" . $end . "/" . $fileSize;
        $headers = array(
            "Content-Length: $numBytes",
            "Content-Range:$content_range"
        );
        curl_setopt($ch, CURLOPT_URL, $graph_url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, constant('CURL_SSL_VERIFYPEER_STATUS'));
        curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "PUT");
        curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
        $server_output = curl_exec($ch);
        $info = curl_getinfo($ch);

        $bytesRemaining = $bytesRemaining - $chunkSize;
        $i++;
    }

当你传递最后一组数据时,它应该是正确的数据字节。否则上传会话将失败。

您的申请需要:

  • 创建上传session
  • 上传字节到上传session

请参阅 OneDrive 开发中心的上传大文件并上传 session 文档页面:https://docs.microsoft.com/en-us/onedrive/developer/rest-api/api/driveitem_createuploadsession#create-an-upload-session 详细了解每个步骤的请求类型以及 JSON 或预期的 http 响应代码。

从 PHP 功能的角度来看,您需要:

  1. 确定上传文件的属性(文件大小、文件名)
  2. 通过 curl 发送 post 数据以创建上传 session(有关 #1 的示例代码片段,请参阅标题为 SEND POST FROM CURL in this blog post 的部分。)
  3. 将来自 JSON 响应的 uploadUrl 解析为 php 变量
  4. 通过 cURL 将二进制内容发送到上面提取的 uploadURL(请参阅标题为 Send the binary contents via cURL in this blog post 的部分(发送整个文件或部分块 - 应考虑文件大小和 connection/bandwidth确定方法)
  5. 解析响应 header(http 响应代码)并有条件地:
    • 如果失败则使用预期的字节范围重试(HTTP 416 请求范围不可满足的响应代码)
    • 如果传输字节 ranges/partials(202 Accepted 的响应代码),则继续下一个字节范围 - 参考 "Resuming an in-progress upload"
    • complete/return/exit 功能失效(HTTP 200 OKHTTP 201 Created 的响应代码)
    • 在任何 50x 响应上,发送 GET 请求(参考 "Resuming an in-progress upload")以确定发送什么 next/how 以恢复

如果检测到文件名冲突(HTTP/1.1 409 Conflict 的响应代码):

  1. Send a DELETE request using curl command 取消上传 session(您应该得到 HTTP/1.1 204 No Content.
  2. 的响应代码
  3. Resolve/handle名称冲突
  4. 重启进程

这段代码对我有用:

<?php

$fileName="myfile.zip";
$filename_location=realpath($fileName);

$token="{access token}";
$ch = curl_init();
$url="https://graph.microsoft.com/v1.0/me/drive/root:/api/$fileName:/createUploadSession";
curl_setopt($ch, CURLOPT_URL,$url );
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
$data= '{
    "item": {
        "@microsoft.graph.conflictBehavior": "rename",
        "description": "description",
        "fileSystemInfo": { "@odata.type": "microsoft.graph.fileSystemInfo" },
        "name": "'.$fileName.'"
  }
}';
    $header = array(
        'Content-Type: application/json',
        "Cache-Control: no-cache",
        "Pragma: no-cache",
        "Authorization: bearer $token");
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_POST, TRUE);
        curl_setopt($ch, CURLOPT_HTTPHEADER, $header );
        curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);

$result = json_decode(curl_exec($ch)) ;


$graph_url = $result->uploadUrl;


    $fragSize = 320 * 1024;
    $file = file_get_contents($filename_location);
    $fileSize = strlen($file);
    $numFragments = ceil($fileSize / $fragSize);
    $bytesRemaining = $fileSize;
    $i = 0;
    $ch = curl_init($graph_url);
    while ($i < $numFragments) {
        $chunkSize = $numBytes = $fragSize;
        $start = $i * $fragSize;
        $end = $i * $fragSize + $chunkSize - 1;
        $offset = $i * $fragSize;
        if ($bytesRemaining < $chunkSize) {
            $chunkSize = $numBytes = $bytesRemaining;
            $end = $fileSize - 1;
        }
        if ($stream = fopen($filename_location, 'r')) {
            // get contents using offset
            $data = stream_get_contents($stream, $chunkSize, $offset);
            fclose($stream);
        }

        $content_range = " bytes " . $start . "-" . $end . "/" . $fileSize;
        $headers = array(
            "Content-Length: $numBytes",
            "Content-Range:$content_range"
        );
        curl_setopt($ch, CURLOPT_URL, $graph_url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
        curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "PUT");
        curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
        $server_output = curl_exec($ch);
        $info = curl_getinfo($ch);
        $bytesRemaining = $bytesRemaining - $chunkSize;
        $i++;
    }

?>