• Модуль: clouds
  • Путь к файлу: ~/bitrix/modules/clouds/classes/general/storage_service_s3.php
  • Класс: CCloudStorageService_S3
  • Вызов: CCloudStorageService_S3::FileCopy
function FileCopy($arBucket, $arFile, $filePath)
{
	global $APPLICATION;

	if($arBucket["PREFIX"])
	{
		if(mb_substr($filePath, 0, mb_strlen($arBucket["PREFIX"]) + 2) != "/".$arBucket["PREFIX"]."/")
			$filePath = "/".$arBucket["PREFIX"]."/".ltrim($filePath, "/");
	}

	$sourcePath = "/".$arBucket["BUCKET"]."/".($arBucket["PREFIX"]? $arBucket["PREFIX"]."/": "").($arFile["SUBDIR"]? $arFile["SUBDIR"]."/": "").$arFile["FILE_NAME"];
	$additional_headers = array();
	if($this->_public)
		$additional_headers["x-amz-acl"] = "public-read";
	$additional_headers["x-amz-copy-source"] = CCloudUtil::URLEncode($sourcePath, "UTF-8", true);
	$additional_headers["Content-Type"] = $arFile["CONTENT_TYPE"];

	if (
		defined("BX_CLOUDS_COUNTERS_DEBUG")
		&& !preg_match(BX_CLOUDS_COUNTERS_DEBUG, $filePath)
	)
	{
		CCloudsDebug::getInstance("copy")->startAction($filePath);
	}

	$this->SetLocation($arBucket["LOCATION"]);
	$this->SendRequest(
		$arBucket["SETTINGS"],
		'PUT',
		$arBucket["BUCKET"],
		CCloudUtil::URLEncode($filePath, "UTF-8", true),
		'',
		'',
		$additional_headers
	);

	if (
		defined("BX_CLOUDS_COUNTERS_DEBUG")
		&& !preg_match(BX_CLOUDS_COUNTERS_DEBUG, $filePath)
	)
	{
		CCloudsDebug::getInstance("copy")->endAction();
	}

	if (
		defined("BX_CLOUDS_COUNTERS_DEBUG")
		&& $this->status == 200
		&& !preg_match(BX_CLOUDS_COUNTERS_DEBUG, $filePath)
	)
	{
		CCloudsDebug::getInstance()->startAction(CCloudUtil::URLEncode($filePath, "UTF-8", true));
	}

	if($this->status == 200)
	{
		return $this->GetFileSRC($arBucket, $filePath);
	}
	elseif($this->checkForTokenExpiration($this->status, $this->result))
	{
		$this->tokenHasExpired = true;
		return false;
	}
	elseif (
		$this->status == 400
		&& ($e = $APPLICATION->GetException())
		&& is_object($e)
		&& preg_match("/The specified copy source is larger than the maximum allowable size for a copy source: ([0-9]+)/i", $e->GetString(), $match)
	)
	{
		$sizeLimit = $match[1];
		$this->SendRequest(
			$arBucket["SETTINGS"],
			'HEAD',
			$arBucket["BUCKET"],
			CCloudUtil::URLEncode("/".($arBucket["PREFIX"]? $arBucket["PREFIX"]."/": "").($arFile["SUBDIR"]? $arFile["SUBDIR"]."/": "").$arFile["FILE_NAME"], "UTF-8", true)
		);

		$fileSize = false;
		if($this->status == 200)
		{
			if (isset($this->headers["Content-Length"]) && $this->headers["Content-Length"] > 0)
				$fileSize = $this->headers["Content-Length"];
		}
		if (!$fileSize)
		{
			$APPLICATION->ResetException();
			if (defined("BX_CLOUDS_ERROR_DEBUG"))
			{
				AddMessage2Log($this);
			}
			return false;
		}

		//Multipart copy goes here
		$additional_headers = array();
		if($this->_public)
			$additional_headers["x-amz-acl"] = "public-read";
		$additional_headers["Content-Type"] = $arFile["CONTENT_TYPE"];

		$response = $this->SendRequest(
			$arBucket["SETTINGS"],
			'POST',
			$arBucket["BUCKET"],
			CCloudUtil::URLEncode($filePath, "UTF-8", true),
			'?uploads=',
			'',
			$additional_headers
		);

		if(
			$this->status == 200
			&& is_array($response)
			&& isset($response["InitiateMultipartUploadResult"])
			&& is_array($response["InitiateMultipartUploadResult"])
			&& isset($response["InitiateMultipartUploadResult"]["#"])
			&& is_array($response["InitiateMultipartUploadResult"]["#"])
			&& isset($response["InitiateMultipartUploadResult"]["#"]["UploadId"])
			&& is_array($response["InitiateMultipartUploadResult"]["#"]["UploadId"])
			&& isset($response["InitiateMultipartUploadResult"]["#"]["UploadId"][0])
			&& is_array($response["InitiateMultipartUploadResult"]["#"]["UploadId"][0])
			&& isset($response["InitiateMultipartUploadResult"]["#"]["UploadId"][0]["#"])
			&& is_string($response["InitiateMultipartUploadResult"]["#"]["UploadId"][0]["#"])
		)
		{
			$uploadId = $response["InitiateMultipartUploadResult"]["#"]["UploadId"][0]["#"];
			$parts = array();
		}
		else
		{
			$APPLICATION->ResetException();
			if (defined("BX_CLOUDS_ERROR_DEBUG"))
			{
				AddMessage2Log($this);
			}
			return false;
		}

		$pos = 0;
		$part_no = 0;
		while ($pos < $fileSize)
		{
			$additional_headers = array();
			$additional_headers["x-amz-copy-source"] = CCloudUtil::URLEncode("/".$arBucket["BUCKET"]."/".($arBucket["PREFIX"]? $arBucket["PREFIX"]."/": "").($arFile["SUBDIR"]? $arFile["SUBDIR"]."/": "").$arFile["FILE_NAME"], "UTF-8", true);
			$additional_headers["x-amz-copy-source-range"] = "bytes=".$pos."-".(min($fileSize, $pos + $sizeLimit) - 1);

			$response = $this->SendRequest(
				$arBucket["SETTINGS"],
				'PUT',
				$arBucket["BUCKET"],
				CCloudUtil::URLEncode($filePath, "UTF-8", true),
				'?partNumber='.($part_no + 1).'&uploadId='.rawurlencode($uploadId),
				'',
				$additional_headers
			);

			if(
				$this->status == 200
				&& is_array($response)
				&& isset($response["CopyPartResult"])
				&& is_array($response["CopyPartResult"])
				&& isset($response["CopyPartResult"]["#"])
				&& is_array($response["CopyPartResult"]["#"])
				&& isset($response["CopyPartResult"]["#"]["ETag"])
				&& is_array($response["CopyPartResult"]["#"]["ETag"])
				&& isset($response["CopyPartResult"]["#"]["ETag"][0])
				&& is_array($response["CopyPartResult"]["#"]["ETag"][0])
				&& isset($response["CopyPartResult"]["#"]["ETag"][0]["#"])
				&& is_string($response["CopyPartResult"]["#"]["ETag"][0]["#"])
			)
			{
				$parts[$part_no] = trim($response["CopyPartResult"]["#"]["ETag"][0]["#"], '"');
			}
			else
			{
				$APPLICATION->ResetException();
				if (defined("BX_CLOUDS_ERROR_DEBUG"))
				{
					AddMessage2Log($this);
				}
				return false;
			}
			$part_no++;
			$pos += $sizeLimit;
		}

		ksort($parts);
		$data = "";
		foreach($parts as $PartNumber => $ETag)
		{
			$data .= "".($PartNumber+1)."".$ETag."n";
		}

		$this->SendRequest(
			$arBucket["SETTINGS"],
			'POST',
			$arBucket["BUCKET"],
			CCloudUtil::URLEncode($filePath, "UTF-8", true),
			'?uploadId='.rawurlencode($uploadId),
			"".$data.""
		);

		if($this->status == 200)
		{
			return $this->GetFileSRC($arBucket, $filePath);
		}

		$APPLICATION->ResetException();
		if (defined("BX_CLOUDS_ERROR_DEBUG"))
		{
			AddMessage2Log($this);
		}
		return false;
	}
	else//if($this->status == 404)
	{
		$APPLICATION->ResetException();
		if (defined("BX_CLOUDS_ERROR_DEBUG"))
		{
			AddMessage2Log($this);
		}
		return false;
	}
}