Php файл chunking - как мне сделать это правильно - PullRequest
0 голосов
/ 20 октября 2019

Я новичок в PHP-фрагментации и загрузке файлов. Мне было интересно, если кто-то может дать мне некоторое руководство о том, как сделать это правильно.

Один из моих главных вопросов, который я имею в виду при загрузке фрагментов, должен ли этот последний блок совпадать с остальными? я продолжаю получать сообщение об ошибке при попытке загрузить. Кажется, все работает нормально. Тем не менее, когда последний кусок попадает, он приостанавливается на 15 секунд, а затем выдает эту ошибку

Сведения об ошибке: PHP Неустранимая ошибка: Uncaught GuzzleHttp \ Exception \ RequestException: cURL error 56: OpenSSL SSL_read: SSL_ERROR_SYSCALL, errno 54 (см. http://curl.haxx.se/libcurl/c/libcurl-errors.html)

Мне было интересно, может ли кто-нибудь дать мне несколько советов о том, как правильно выполнить загрузку фрагментов файла

, ниже - пример моего кода на тот случай, если кто-то должен его увидеть: спасибозаранее.

ini_set('memory_limit', '1024M');
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);

require_once(__DIR__ . '/vendor/autoload.php');

use GuzzleHttp\Client;
use GuzzleHttp\Exception\GuzzleException;
use Microsoft\Graph\Exception\GraphException;
use Microsoft\Graph\Graph;
use Microsoft\Graph\Model;
use function GuzzleHttp\Psr7\stream_for;

$tenantId = 'tenantid';
$clientId = 'clientid';
$clientSecret = 'secret';

$guzzle = new Client();

$url = 'https://login.microsoftonline.com/' . $tenantId . '/oauth2/v2.0/token';

$token = json_decode($guzzle->post($url, [
    'form_params' => [
        'client_id' => $clientId,
        'scope' => 'https://graph.microsoft.com/.default',
        'client_secret' => $clientSecret,
        'grant_type' => 'client_credentials',
    ],
])->getBody()->getContents());

$accessToken = $token->access_token;

$headers = [
    'Authorization' => 'Bearer ' . $token->access_token
];

function uploadLargeFiles($accessToken) {
    $graph = new Graph();
    $graph->setAccessToken($accessToken);

    /** @var Model\UploadSession $uploadSession */
    try {
        $uploadSession = $graph->createRequest("POST",
            "/sites/SITEID/drive/items/ITEMID:/newfile.txt:/createUploadSession")
            ->addHeaders(["Content-Type" => "application/json"])
            ->attachBody([
                "item" => [
                    "@microsoft.graph.conflictBehavior" => "replace",
                ]
            ])
            ->setReturnType(Model\UploadSession::class)
            ->execute();
    } catch (GraphException $e) {
        echo "Something bad happened";
    }

    $file = __DIR__ . '/file_50mb.dat';
    $handle = fopen($file, 'r');
    $fileSize = fileSize($file);
    $fileNbByte = $fileSize - 1;
    $chunkSize = 327680*16;
    $fgetsLength = $chunkSize + 1;
    $start = 0;

    while (!feof($handle)) {
        $bytes = fread($handle, $fgetsLength);
        $end = $chunkSize + $start;
        if ($end > $fileNbByte) {
            $end = $fileNbByte;
        }
//        $stream = stream_for($bytes);

        echo "start: " . $start . "\n";
        echo "end: " . $end . "\n";
        echo "bytes " . $start . "-" . ($end - 1) . "/" . $fileSize . "\n";
        echo "chunk size: " . ($end - $start) . " bytes, " . (($end - $start) * 0.000001) . " MB" . "\n\n";

        try {
            $res = $graph->createRequest("PUT", $uploadSession->getUploadUrl())
                ->addHeaders([
                    'Connection' => "keep-alive",
                    'Content-Length' => $end - $start,
                    'Content-Range' => "bytes " . $start . "-" . ($end - 1) . "/" . $fileSize,
                    'Accept' => "*/*",
                    'Origin' => "------snip------",
                ])
                ->setReturnType(Model\UploadSession::class)
                ->attachBody($bytes)
                ->execute();
        } catch (GraphException $e) {
            echo $e;
        }

        $start = $end;
    }
}

uploadLargeFiles($accessToken);

1 Ответ

1 голос
/ 24 октября 2019

Один из моих главных вопросов, который я имею в виду при загрузке чанков, должен ли этот последний чанк совпадать с остальными?

Нет, что имеет значение, заголовок Content-Range( из документов ):

Ваше приложение должно гарантировать, что общий размер файла, указанный в заголовке Content-Range, равен одинаковому для всех запросов. Если диапазон байтов объявляет другой размер файла, запрос не будет выполнен.

В вашем примере последний диапазон байтов для заголовка Content-Range рассчитывается здесь неправильно:

if ($end > $fileNbByte) {
    $end = $fileNbByte;  
}

Вместо этого должно быть так:

if ($end > $fileNbByte) {
   $end = $fileNbByte + 1;
}
...