• Модуль: webdav
  • Путь к файлу: ~/bitrix/modules/webdav/classes/editdocgoogle.php
  • Класс: CWebDavEditDocGoogle
  • Вызов: CWebDavEditDocGoogle::publicByResumableUpload
public function publicByResumableUpload($fileData, &$lastStatus)
{
	$accessToken = $this->getAccessToken();
	$convert = is_null($fileData['convert'])? true : (bool)$fileData['convert'];
	$mimeType = $fileData['mimeType'];
	$fileSrc = $fileData['src'];
	$fileSize = $fileData['size'] = $fileData['size']? $fileData['size']: filesize($fileSrc);
	$chunkSize = 40 * 256 * 1024; // Chunk size restriction: All chunks must be a multiple of 256 KB (256 x 1024 bytes) in size except for the final chunk that completes the upload
	$location = $this->createFile($fileData);
	if(!$location)
	{
		return false;
	}

	$lastResponseCode = false;
	$finalOutput = null;
	$lastRange = false;
	$transactionCounter = 0;
	$doExponentialBackoff = false;
	$exponentialBackoffCounter = 0;
	$response = array();
	while ($lastResponseCode === false || $lastResponseCode == '308')
	{
		$transactionCounter++;

		if ($doExponentialBackoff)
		{
			$sleepFor = pow(2, $exponentialBackoffCounter);
			sleep($sleepFor);
			usleep(rand(0, 1000));
			$exponentialBackoffCounter++;
			if ($exponentialBackoffCounter > 5)
			{
				$lastStatus = $response['code'];
				return false;
			}
		}

		// determining what range is next
		$rangeStart = 0;
		$rangeEnd   = min($chunkSize, $fileSize - 1);
		if ($lastRange !== false)
		{
			$lastRange  = explode('-', $lastRange);
			$rangeStart = (int)$lastRange[1] + 1;
			$rangeEnd   = min($rangeStart + $chunkSize, $fileSize - 1);
		}

		$http = new CHTTP();
		$http->http_timeout = 10;
		$arUrl = $http->ParseURL($location);
		$http->SetAdditionalHeaders(array(
			"Authorization" => "Bearer {$accessToken}",
			"Content-Length" => (string)($rangeEnd - $rangeStart + 1),
			"Content-Type" => $mimeType,
			"Content-Range" => "bytes {$rangeStart}-{$rangeEnd}/{$fileSize}",
		));
		$postContentType = '';
		$toSendContent = file_get_contents($fileSrc, false, null, $rangeStart, ($rangeEnd - $rangeStart + 1));
		if($http->Query('PUT', $arUrl['host'], $arUrl['port'], $arUrl['path_query'], $toSendContent, $arUrl['proto'], $postContentType))
		{
			$response['code'] = $http->status;
			$response['headers']['range'] = $http->headers['Range'];
		}

		$doExponentialBackoff = false;
		if (isset($response['code']))
		{
			// checking for expired credentials
			if ($response['code'] == "401")
			{ // todo: make sure that we also got an invalid credential response
				//$access_token       = get_access_token(true);
				$lastResponseCode = false;
			}
			else if ($response['code'] == "308")
			{
				$lastResponseCode = $response['code'];
				$lastRange = $response['headers']['range'];
				// todo: verify x-range-md5 header to be sure
				$exponentialBackoffCounter = 0;
			}
			else if ($response['code'] == "503")
			{ // Google's letting us know we should retry
				$doExponentialBackoff = true;
				$lastResponseCode     = false;
			}
			else
			{
				if ($response['code'] == "200")
				{ // we are done!
					$lastResponseCode = $response['code'];
				}
				else
				{
					$lastStatus = $response['code'];
					return false;
				}
			}
		}
		else
		{
			$doExponentialBackoff = true;
			$lastResponseCode     = false;
		}
	}

	if ($lastResponseCode != "200")
	{
		$lastStatus = $response['code'];
		return false;
	}
	$finalOutput = json_decode($http->result);

	return array('link' => $finalOutput->alternateLink, 'id' => $finalOutput->id);
}