403Webshell
Server IP : 80.87.202.40  /  Your IP : 216.73.216.169
Web Server : Apache
System : Linux rospirotorg.ru 5.14.0-539.el9.x86_64 #1 SMP PREEMPT_DYNAMIC Thu Dec 5 22:26:13 UTC 2024 x86_64
User : bitrix ( 600)
PHP Version : 8.2.27
Disable Function : NONE
MySQL : OFF |  cURL : ON |  WGET : ON |  Perl : ON |  Python : OFF |  Sudo : ON |  Pkexec : ON
Directory :  /home/bitrix/ext_www/rospirotorg.ru/bitrix/modules/clouds/classes/general/

Upload File :
current_dir [ Writeable] document_root [ Writeable]

 

Command :


[ Back ]     

Current File : /home/bitrix/ext_www/rospirotorg.ru/bitrix/modules/clouds/classes/general/storage.php
<?php
IncludeModuleLangFile(__FILE__);

class CCloudStorage
{
	const FILE_SKIPPED = 0;
	const FILE_MOVED = 1;
	const FILE_PARTLY_UPLOADED = 2;
	const FILE_UPLOAD_ERROR = 3;

	public static $part_size = 0;
	public static $part_count = 0;

	private static $_services = /*.(array[string]CCloudStorageService).*/
		null;

	public static $file_skip_reason = '';

	/**
	 * @return void
	 */
	public static function _init()
	{
		if (!isset(self::$_services))
		{
			/* @var CCloudStorageService $obService */
			$obService = null;
			self::$_services = /*.(array[string]CCloudStorageService).*/ [];
			foreach (GetModuleEvents('clouds', 'OnGetStorageService', true) as $arEvent)
			{
				$obService = ExecuteModuleEventEx($arEvent);
				if (is_object($obService))
				{
					self::$_services[$obService->GetID()] = $obService;
				}
			}
		}
	}

	/**
	 * @param string $ID
	 * @return CCloudStorageService
	 */
	public static function GetServiceByID($ID)
	{
		self::_init();
		if (array_key_exists($ID, self::$_services))
		{
			return self::$_services[$ID];
		}
		else
		{
			return null;
		}
	}

	/**
	 * @return array[string]CCloudStorageService
	 */
	public static function GetServiceList()
	{
		self::_init();
		return self::$_services;
	}

	/**
	 * @param string $ID
	 * @return array[string]string|false
	 */
	public static function GetServiceLocationList($ID)
	{
		$obService = CCloudStorage::GetServiceByID($ID);
		if (is_object($obService))
		{
			return $obService->GetLocationList();
		}
		else
		{
			return /*.(array[string]string).*/
				[];
		}
	}

	/**
	 * @param string $ID
	 * @return string
	 */
	public static function GetServiceDescription($ID)
	{
		$obService = CCloudStorage::GetServiceByID($ID);
		if (is_object($obService))
		{
			return $obService->GetName();
		}
		else
		{
			return '';
		}
	}

	/**
	 * @param array [string]string $arFile
	 * @param string $strFileName
	 * @return CCloudStorageBucket
	 */
	public static function FindBucketForFile($arFile, $strFileName)
	{
		if (array_key_exists('size', $arFile) && $arFile['size'] > 0)
		{
			$file_size = intval($arFile['size']);
		}
		elseif (array_key_exists('FILE_SIZE', $arFile) && $arFile['FILE_SIZE'] > 0)
		{
			$file_size = intval($arFile['FILE_SIZE']);
		}
		else
		{
			$file_size = intval($arFile['file_size']);
		}

		self::$file_skip_reason = '';
		$activeCounter = 0;
		$writableCounter = 0;
		foreach (CCloudStorageBucket::GetAllBuckets() as $bucket)
		{
			if ($bucket['ACTIVE'] !== 'Y')
			{
				continue;
			}
			$activeCounter++;

			if ($bucket['READ_ONLY'] === 'Y')
			{
				continue;
			}
			$writableCounter++;

			foreach ($bucket['FILE_RULES_COMPILED'] as $rule)
			{
				if ($rule['MODULE_MASK'] != '')
				{
					$bMatchModule = (preg_match($rule['MODULE_MASK'], $arFile['MODULE_ID']) > 0);
				}
				else
				{
					$bMatchModule = true;
				}

				if ($rule['EXTENTION_MASK'] != '')
				{
					$bMatchExtention =
						(preg_match($rule['EXTENTION_MASK'], $strFileName) > 0)
						|| (preg_match($rule['EXTENTION_MASK'], $arFile['ORIGINAL_NAME']) > 0);
				}
				else
				{
					$bMatchExtention = true;
				}

				if ($rule['SIZE_ARRAY'])
				{
					$bMatchSize = false;
					foreach ($rule['SIZE_ARRAY'] as $size)
					{
						if (
							($file_size >= $size[0])
							&& ($size[1] === 0.0 || $file_size <= $size[1])
						)
						{
							$bMatchSize = true;
						}
					}
				}
				else
				{
					$bMatchSize = true;
				}

				if (!$bMatchModule)
				{
					self::$file_skip_reason = 'NO_FILE_MODULE_MATCH';
				}
				elseif (!$bMatchExtention)
				{
					self::$file_skip_reason = 'NO_FILE_EXTENTION_MATCH';
				}
				elseif (!$bMatchSize)
				{
					self::$file_skip_reason = 'NO_FILE_SIZE_MATCH';
				}

				if ($bMatchModule && $bMatchExtention && $bMatchSize)
				{
					return new CCloudStorageBucket(intval($bucket['ID']));
				}
			}
		}

		if (!$activeCounter)
		{
			self::$file_skip_reason = 'NO_ACTIVE_BUCKETS';
		}
		elseif (!$writableCounter)
		{
			self::$file_skip_reason = 'NO_WRITABLE_BUCKETS';
		}

		return null;
	}

	public static function GetImageSize($path)
	{
		$io = CBXVirtualIo::GetInstance();
		$path = $io->GetPhysicalName($path);

		$image = new \Bitrix\Main\File\Image($path);

		if (($info = $image->getInfo(false)) !== null)
		{
			return [
				0 => $info->getWidth(),
				1 => $info->getHeight(),
				2 => $info->getFormat(),
				3 => $info->getAttributes(),
				'mime' => $info->getMime(),
			];
		}

		return false;
	}

	/**
	 * @param array [string]string $arFile
	 * @param array [string]string $arResizeParams
	 * @param array [string]mixed $callbackData
	 * @param bool $bNeedResize
	 * @param array [string]string $sourceImageFile
	 * @param array [string]string $cacheImageFileTmp
	 * @return bool
	 */
	public static function OnBeforeResizeImage($arFile, $arResizeParams, &$callbackData, &$bNeedResize, &$sourceImageFile, &$cacheImageFileTmp)
	{
		$callbackData = null;

		if (intval($arFile['HANDLER_ID']) <= 0)
		{
			return false;
		}

		$obSourceBucket = new CCloudStorageBucket(intval($arFile['HANDLER_ID']));
		if (!$obSourceBucket->Init())
		{
			return false;
		}

		$callbackData = /*.(array[string]mixed).*/
			[];
		$callbackData['obSourceBucket'] = $obSourceBucket;

		//Assume target bucket same as source
		$callbackData['obTargetBucket'] = $obTargetBucket = $obSourceBucket;

		//if original file bucket is read only
		if ($obSourceBucket->READ_ONLY === 'Y') //Try to find bucket with write rights
		{
			$bucket = CCloudStorage::FindBucketForFile($arFile, $arFile['FILE_NAME']);
			if (!is_object($bucket))
			{
				return false;
			}
			if ($bucket->Init())
			{
				$callbackData['obTargetBucket'] = $obTargetBucket = $bucket;
			}
		}

		if (!$arFile['SRC'])
		{
			$arFile['SRC'] = $obSourceBucket->GetFileSRC($arFile, false);
		}

		if (defined('BX_MOBILE') && constant('BX_MOBILE') === true)
		{
			$bImmediate = true;
		}
		else
		{
			$bImmediate = $arResizeParams[5];
		}

		$callbackData['bImmediate'] = $bImmediate;
		$callbackData['cacheID'] = $arFile['ID'] . '/' . md5(serialize($arResizeParams));
		$callbackData['cacheOBJ'] = new CPHPCache;
		$callbackData['fileDIR'] = '/' . 'resize_cache/' . $callbackData['cacheID'] . '/' . $arFile['SUBDIR'];
		$callbackData['fileNAME'] = $arFile['FILE_NAME'];
		$callbackData['fileURL'] = $callbackData['fileDIR'] . '/' . $callbackData['fileNAME'];

		$result = true;
		if ($callbackData['cacheOBJ']->StartDataCache(CACHED_clouds_file_resize, $callbackData['cacheID'], 'clouds'))
		{
			$cacheImageFile = $obTargetBucket->GetFileSRC($callbackData['fileURL'], false);
			$arDestinationSize = [];

			//Check if it is cache file was deleted, but there was a successful resize
			$delayInfo = $bImmediate ? false : CCloudStorage::ResizeImageFileGet($cacheImageFile);
			if (is_array($delayInfo) && ($delayInfo['ERROR_CODE'] < 10))
			{
				$callbackData['cacheSTARTED'] = true;
				if ($arFile['FILE_SIZE'] > 1)
				{
					$callbackData['fileSize'] = $arFile['FILE_SIZE'];
				}
				$bNeedResize = false;
				$result = true;
			}
			//Check if it is cache file was deleted, but not the file in the cloud
			elseif ($fs = $obTargetBucket->FileExists($callbackData['fileURL']))
			{
				//If file was resized before the fact was registered
				if (COption::GetOptionString('clouds', 'delayed_resize') === 'Y')
				{
					CCloudStorage::ResizeImageFileAdd(
						$arDestinationSize,
						$arFile,
						$cacheImageFile,
						$arResizeParams,
						9 //already where
					);
				}

				$callbackData['cacheSTARTED'] = true;
				if ($fs > 1)
				{
					$callbackData['fileSize'] = $fs;
				}
				$bNeedResize = false;
				$result = true;
			}
			else
			{
				$callbackData['tmpFile'] = CFile::GetTempName('', $arFile['FILE_NAME']);
				$callbackData['tmpFile'] = preg_replace('#[\\\\/]+#', '/', $callbackData['tmpFile']);

				if (
					!$bImmediate
					&& COption::GetOptionString('clouds', 'delayed_resize') === 'Y'
					&& CCloudStorage::ResizeImageFileDelay(
						$arDestinationSize,
						$arFile,
						$cacheImageFile,
						$arResizeParams
					)
				)
				{
					$callbackData['cacheSTARTED'] = false;
					$bNeedResize = false;
					$callbackData['cacheOBJ']->AbortDataCache();
					$callbackData['cacheVARS'] = [
						'cacheImageFile' => $cacheImageFile,
						'width' => $arDestinationSize['width'],
						'height' => $arDestinationSize['height'],
						'size' => null,
					];
					$result = true;
				}
				elseif ($obSourceBucket->DownloadToFile($arFile, $callbackData['tmpFile']))
				{
					$callbackData['cacheSTARTED'] = true;
					$bNeedResize = true;
					$sourceImageFile = $callbackData['tmpFile'];
					$cacheImageFileTmp = CFile::GetTempName('', $arFile['FILE_NAME']);
					$result = true;
				}
				else
				{
					$callbackData['cacheSTARTED'] = false;
					$bNeedResize = false;
					$callbackData['cacheOBJ']->AbortDataCache();
					$result = false;
				}
			}
		}
		else
		{
			$callbackData['cacheSTARTED'] = false;
			$callbackData['cacheVARS'] = $callbackData['cacheOBJ']->GetVars();
			$bNeedResize = false;
			$result = true;
		}

		return $result;
	}

	public static function OnAfterResizeImage($arFile, $arResizeParams, &$callbackData, &$cacheImageFile, &$cacheImageFileTmp, &$arImageSize)
	{
		global $arCloudImageSizeCache;
		$io = CBXVirtualIo::GetInstance();

		if (!is_array($callbackData))
		{
			return false;
		}

		if ($callbackData['cacheSTARTED'])
		{
			/** @var CCloudStorageBucket $obTargetBucket */
			$obTargetBucket = $callbackData['obTargetBucket'];
			/** @var CPHPCache $cacheOBJ */
			$cacheOBJ = $callbackData['cacheOBJ'];

			if (isset($callbackData['tmpFile'])) //have to upload to the cloud
			{
				$arFileToStore = CFile::MakeFileArray($io->GetPhysicalName($cacheImageFileTmp));
				if (!$arFileToStore)
				{
					$cacheOBJ->AbortDataCache();

					$tmpFile = $io->GetPhysicalName($callbackData['tmpFile']);
					unlink($tmpFile);
					@rmdir(mb_substr($tmpFile, 0, -mb_strlen(bx_basename($tmpFile))));

					unlink($cacheImageFileTmp);
					@rmdir(mb_substr($cacheImageFileTmp, 0, -mb_strlen(bx_basename($cacheImageFileTmp))));

					$obSourceBucket = new CCloudStorageBucket(intval($arFile['HANDLER_ID']));
					if ($obSourceBucket->Init())
					{
						$cacheImageFile = $obSourceBucket->GetFileSRC($arFile, false);
					}

					return false;
				}

				if (!preg_match('/^image\\//', $arFileToStore['type']))
				{
					$arFileToStore['type'] = $arFile['CONTENT_TYPE'];
				}

				if ($obTargetBucket->SaveFile($callbackData['fileURL'], $arFileToStore))
				{
					$cacheImageFile = $obTargetBucket->GetFileSRC($callbackData['fileURL'], false);

					$arImageSize = static::GetImageSize($cacheImageFileTmp);
					$arImageSize[2] = filesize($io->GetPhysicalName($cacheImageFileTmp));
					$iFileSize = filesize($arFileToStore['tmp_name']);

					if (!is_array($arImageSize))
					{
						$arImageSize = [0, 0];
					}
					$cacheOBJ->EndDataCache([
						'cacheImageFile' => $cacheImageFile,
						'width' => $arImageSize[0],
						'height' => $arImageSize[1],
						'size' => $arImageSize[2],
					]);

					$tmpFile = $io->GetPhysicalName($callbackData['tmpFile']);
					unlink($tmpFile);
					@rmdir(mb_substr($tmpFile, 0, -mb_strlen(bx_basename($tmpFile))));

					$arCloudImageSizeCache[$cacheImageFile] = $arImageSize;

					$obTargetBucket->IncFileCounter($iFileSize);

					if (
						COption::GetOptionString('clouds', 'delayed_resize') === 'Y'
						&& !is_array(CCloudStorage::ResizeImageFileGet($cacheImageFile))
					)
					{
						$arDestinationSize = [];
						CCloudStorage::ResizeImageFileAdd(
							$arDestinationSize,
							$arFile,
							$cacheImageFile,
							$arResizeParams,
							9 //already there
						);
					}
				}
				else
				{
					$cacheOBJ->AbortDataCache();

					$tmpFile = $io->GetPhysicalName($callbackData['tmpFile']);
					unlink($tmpFile);
					@rmdir(mb_substr($tmpFile, 0, -mb_strlen(bx_basename($tmpFile))));

					unlink($cacheImageFileTmp);
					@rmdir(mb_substr($cacheImageFileTmp, 0, -mb_strlen(bx_basename($cacheImageFileTmp))));

					$obSourceBucket = new CCloudStorageBucket(intval($arFile['HANDLER_ID']));
					if ($obSourceBucket->Init())
					{
						$cacheImageFile = $obSourceBucket->GetFileSRC($arFile, false);
					}

					return false;
				}
			}
			else //the file is already in the cloud
			{
				$source = new \Bitrix\Main\File\Image\Rectangle($arFile['WIDTH'], $arFile['HEIGHT']);
				$destination = new \Bitrix\Main\File\Image\Rectangle($arResizeParams[0]['width'], $arResizeParams[0]['height']);
				$source->resize($destination, $arResizeParams[1]);
				$cacheImageFile = $obTargetBucket->GetFileSRC($callbackData['fileURL'], false);
				$arImageSize = [
					$destination->getWidth(),
					$destination->getHeight(),
					$callbackData['fileSize'] ?? $obTargetBucket->GetFileSize($callbackData['fileURL']),
				];
				$cacheOBJ->EndDataCache([
					'cacheImageFile' => $cacheImageFile,
					'width' => $arImageSize[0],
					'height' => $arImageSize[1],
					'size' => $arImageSize[2],
				]);

				$arCloudImageSizeCache[$cacheImageFile] = $arImageSize;
			}
		}
		elseif (is_array($callbackData['cacheVARS']))
		{
			$cacheImageFile = $callbackData['cacheVARS']['cacheImageFile'];
			$arImageSize = [
				$callbackData['cacheVARS']['width'],
				$callbackData['cacheVARS']['height'],
				$callbackData['cacheVARS']['size'],
			];
			$arCloudImageSizeCache[$cacheImageFile] = $arImageSize;
		}
		else
		{
			return false;
		}

		$delayedResize = $callbackData['bImmediate'] ? false : COption::GetOptionString('clouds', 'delayed_resize') === 'Y';
		foreach (GetModuleEvents('clouds', 'OnAfterResizeImage', true) as $arEvent)
		{
			$cacheImageFileBefore = $cacheImageFile;
			ExecuteModuleEventEx($arEvent, [$delayedResize, &$cacheImageFile]);
			if ($cacheImageFile !== $cacheImageFileBefore && $cacheImageFile)
			{
				$arCloudImageSizeCache[$cacheImageFile] = $arCloudImageSizeCache[$cacheImageFileBefore];
			}
		}

		return true;
	}

	public static function ResizeImageFileGet($destinationFile)
	{
		global $DB;
		$destinationFile = preg_replace('/^https?:/i', '', $destinationFile);
		$destinationFile = CCloudUtil::URLEncode($destinationFile, 'UTF-8', true);
		$q = $DB->Query('
			select
				ID
				,ERROR_CODE
				,FILE_ID
				,' . $DB->DateToCharFunction('TIMESTAMP_X', 'FULL') . " TIMESTAMP_X
			from b_clouds_file_resize
			where TO_PATH = '" . $DB->ForSql($destinationFile) . "'
		");
		$a = $q->Fetch();
		return $a;
	}

	public static function ResizeImageFileAdd(&$arDestinationSize, $sourceFile, $destinationFile, $arResizeParams, $errorCode = 0)
	{
		global $DB;
		$destinationFile = preg_replace('/^https?:/i', '', $destinationFile);
		$destinationFile = CCloudUtil::URLEncode($destinationFile, 'UTF-8', true);
		$q = $DB->Query('
			select
				ID
				,ERROR_CODE
				,PARAMS
				,' . $DB->DateToCharFunction('TIMESTAMP_X', 'FULL') . " TIMESTAMP_X
			from b_clouds_file_resize
			where TO_PATH = '" . $DB->ForSql($destinationFile) . "'
		");

		$a = $q->Fetch();
		if ($a && $a['ERROR_CODE'] >= 10 && $a['ERROR_CODE'] < 20)
		{
			$DB->Query('DELETE from b_clouds_file_resize WHERE ID = ' . $a['ID']);
			$a = false;
		}

		if (!$a)
		{
			$arResizeParams['type'] = $sourceFile['CONTENT_TYPE'];
			$DB->Add('b_clouds_file_resize', [
				'~TIMESTAMP_X' => $DB->CurrentTimeFunction(),
				'ERROR_CODE' => intval($errorCode),
				'PARAMS' => serialize($arResizeParams),
				'FROM_PATH' => CCloudUtil::URLEncode($sourceFile['SRC'], 'UTF-8', true),
				'TO_PATH' => $destinationFile,
				'FILE_ID' => $sourceFile['ID'],
			]);
		}
	}

	public static function ResizeImageFileDelay(&$arDestinationSize, $sourceFile, $destinationFile, $arResizeParams)
	{
		global $DB;
		$destinationFile = preg_replace('/^https?:/i', '', $destinationFile);
		$destinationFile = CCloudUtil::URLEncode($destinationFile, 'UTF-8', true);
		$q = $DB->Query('
			select
				ID
				,ERROR_CODE
				,PARAMS
				,' . $DB->DateToCharFunction('TIMESTAMP_X', 'FULL') . " TIMESTAMP_X
			from b_clouds_file_resize
			where TO_PATH = '" . $DB->ForSql($destinationFile) . "'
		");
		if ($resize = $q->Fetch())
		{
			if ($resize['ERROR_CODE'] < 10)
			{
				$arResizeParams = unserialize($resize['PARAMS'], ['allowed_classes' => false]);
				$id = $resize['ID'];
			}
//Give it a try
			elseif (
				$resize['ERROR_CODE'] >= 10
				&& $resize['ERROR_CODE'] < 20
				&& (MakeTimeStamp($resize['TIMESTAMP_X']) + 300/*5min*/) < (time() + CTimeZone::GetOffset())
			)
			{
				$DB->Query('
					UPDATE b_clouds_file_resize
					SET ERROR_CODE = 1
					WHERE ID=' . $resize['ID'] . '
				');
				$arResizeParams = unserialize($resize['PARAMS'], ['allowed_classes' => false]);
				$id = $resize['ID'];
			}
			else
			{
				return false;
			}
		}
		else
		{
			$id = 0;
		}

		$arSize = $arResizeParams[0];
		$resizeType = $arResizeParams[1];
		$arWaterMark = $arResizeParams[2];
		// $jpgQuality = $arResizeParams[3];
		$arFilters = $arResizeParams[4];

		$source = new \Bitrix\Main\File\Image\Rectangle($sourceFile['WIDTH'], $sourceFile['HEIGHT']);
		$destination = new \Bitrix\Main\File\Image\Rectangle($arSize['width'], $arSize['height']);
		$bNeedCreatePicture = $source->resize($destination, $resizeType);
		$bNeedCreatePicture |= is_array($arWaterMark) && !empty($arWaterMark);
		$bNeedCreatePicture |= is_array($arFilters) && !empty($arFilters);

		if ($bNeedCreatePicture)
		{
			if ($id <= 0)
			{
				$arResizeParams['type'] = $sourceFile['CONTENT_TYPE'];
				$id = $DB->Add('b_clouds_file_resize', [
					'~TIMESTAMP_X' => $DB->CurrentTimeFunction(),
					'ERROR_CODE' => 2,
					'PARAMS' => serialize($arResizeParams),
					'FROM_PATH' => CCloudUtil::URLEncode($sourceFile['SRC'], 'UTF-8', true),
					'TO_PATH' => $destinationFile,
					'FILE_ID' => $sourceFile['ID'],
				]);
			}

			return $id > 0;
		}
		else
		{
			return false;
		}
	}

	/**
	 * @param CCloudStorageBucket $obBucket
	 * @param string $path
	 * @return bool
	 */
	public static function ResizeImageFileCheck($obBucket, $path)
	{
		global $DB;
		$io = CBXVirtualIo::GetInstance();

		$path = preg_replace('/^https?:/i', '', $path);
		$path = CCloudUtil::URLEncode($path, 'UTF-8', true);
		$q = $DB->Query('
			select
				ID
				,ERROR_CODE
				,TO_PATH
				,FROM_PATH
				,PARAMS
				,' . $DB->DateToCharFunction('TIMESTAMP_X', 'FULL') . " TIMESTAMP_X
			from b_clouds_file_resize
			where TO_PATH = '" . $DB->ForSql($path) . "'
		");
		$task = $q->Fetch();
		if (!$task)
		{
			return false;
		}

		//File in the Sky with Diamonds
		if ($task['ERROR_CODE'] == 9)
		{
			return true;
		}

		//Fatal error
		if ($task['ERROR_CODE'] >= 20)
		{
			return false;
		}

		//Recoverable error
		if ($task['ERROR_CODE'] >= 10 && $task['ERROR_CODE'] < 20)
		{
			if ((MakeTimeStamp($task['TIMESTAMP_X']) + 300/*5min*/) > (time() + CTimeZone::GetOffset()))
			{
				return false;
			}
		}

		$DB->Query('
			UPDATE b_clouds_file_resize
			SET ERROR_CODE = 11
			WHERE ID = ' . $task['ID'] . '
		');

		$tmpFile = CFile::MakeFileArray($task['FROM_PATH']);
		// if (!is_array($tmpFile) || !file_exists($tmpFile["tmp_name"]))
		// {
		// 	$tmpFile = CFile::MakeFileArray(\Bitrix\Main\Web\Uri::urnEncode($task["FROM_PATH"], "UTF-8"));
		// }

		if (!is_array($tmpFile) || !file_exists($tmpFile['tmp_name']))
		{
			$DB->Query('
				UPDATE b_clouds_file_resize
				SET ERROR_CODE = 22
				WHERE ID = ' . $task['ID'] . '
			');
			return false;
		}

		$arResizeParams = unserialize($task['PARAMS'], ['allowed_classes' => false]);
		if (!is_array($arResizeParams))
		{
			$DB->Query('
				UPDATE b_clouds_file_resize
				SET ERROR_CODE = 23
				WHERE ID = ' . $task['ID'] . '
			');
			return false;
		}

		$DB->Query('
			UPDATE b_clouds_file_resize
			SET ERROR_CODE = 14
			WHERE ID = ' . $task['ID'] . '
		');

		$arSize = $arResizeParams[0];
		$resizeType = $arResizeParams[1];
		$arWaterMark = $arResizeParams[2];
		$jpgQuality = $arResizeParams[3];
		$arFilters = $arResizeParams[4];

		$from_path = $io->GetLogicalName($tmpFile['tmp_name']);
		$to_path = rawurldecode($task['TO_PATH']);
		$to_path = CFile::GetTempName('', bx_basename($to_path));

		if (!CFile::ResizeImageFile($from_path, $to_path, $arSize, $resizeType, $arWaterMark, $jpgQuality, $arFilters))
		{
			$DB->Query('
				UPDATE b_clouds_file_resize
				SET ERROR_CODE = 25
				WHERE ID = ' . $task['ID'] . '
			');
			return false;
		}

		$DB->Query('
			UPDATE b_clouds_file_resize
			SET ERROR_CODE = 16
			WHERE ID = ' . $task['ID'] . '
		');

		$fileToStore = CFile::MakeFileArray($io->GetPhysicalName($to_path));
		if ($arResizeParams['type'] && !preg_match('/^image\\//', $fileToStore['type']))
		{
			$fileToStore['type'] = $arResizeParams['type'];
		}

		$baseURL = preg_replace('/^https?:/i', '', $obBucket->GetFileSRC('/'));
		$pathToStore = mb_substr($task['TO_PATH'], mb_strlen($baseURL) - 1);
		$pathToStore = rawurldecode($pathToStore);
		if (!$obBucket->SaveFile($pathToStore, $fileToStore))
		{
			$DB->Query('
				UPDATE b_clouds_file_resize
				SET ERROR_CODE = 27
				WHERE ID = ' . $task['ID'] . '
			');
			return false;
		}
		$obBucket->IncFileCounter($fileToStore['size']);
		$DB->Query('
			UPDATE b_clouds_file_resize
			SET ERROR_CODE = 9
			WHERE ID = ' . $task['ID']
		);

		return true;
	}

	public static function OnMakeFileArray($arSourceFile, &$arDestination)
	{
		if (!is_array($arSourceFile))
		{
			$file = $arSourceFile;
			if (mb_substr($file, 0, mb_strlen($_SERVER['DOCUMENT_ROOT'])) == $_SERVER['DOCUMENT_ROOT'])
			{
				$file = ltrim(mb_substr($file, mb_strlen($_SERVER['DOCUMENT_ROOT'])), '/');
			}

			if (!preg_match('#^https?://#', $file))
			{
				return false;
			}

			$bucket = CCloudStorage::FindBucketByFile($file);
			if (!is_object($bucket))
			{
				return false;
			}

			$filePath = mb_substr($file, mb_strlen($bucket->GetFileSRC('/')) - 1);
			$filePath = rawurldecode($filePath);

			$io = CBXVirtualIo::GetInstance();
			$target = CFile::GetTempName('', bx_basename($filePath));
			$target = preg_replace('#[\\\\/]+#', '/', $target);

			if ($bucket->DownloadToFile($filePath, $target))
			{
				$arDestination = $io->GetPhysicalName($target);
			}

			return true;
		}
		else
		{
			if ($arSourceFile['HANDLER_ID'] <= 0)
			{
				return false;
			}

			$bucket = new CCloudStorageBucket($arSourceFile['HANDLER_ID']);
			if (!$bucket->Init())
			{
				return false;
			}

			$target = CFile::GetTempName('', $arSourceFile['FILE_NAME']);
			$target = preg_replace('#[\\\\/]+#', '/', $target);

			if ($bucket->DownloadToFile($arSourceFile, $target))
			{
				$arDestination['name'] = ($arSourceFile['ORIGINAL_NAME'] <> '' ? $arSourceFile['ORIGINAL_NAME'] : $arSourceFile['FILE_NAME']);
				$arDestination['size'] = $arSourceFile['FILE_SIZE'];
				$arDestination['type'] = $arSourceFile['CONTENT_TYPE'];
				$arDestination['description'] = $arSourceFile['DESCRIPTION'];
				$arDestination['tmp_name'] = $target;
			}

			return true;
		}
	}

	public static function OnFileDelete($arFile)
	{
		global $DB;

		if ($arFile['HANDLER_ID'] <= 0)
		{
			return false;
		}

		$bucket = new CCloudStorageBucket($arFile['HANDLER_ID']);
		if ((!$bucket->Init()) || ($bucket->READ_ONLY === 'Y'))
		{
			return false;
		}

		$result = $bucket->DeleteFile('/' . $arFile['SUBDIR'] . '/' . $arFile['FILE_NAME']);
		if ($result)
		{
			$bucket->DecFileCounter($arFile['FILE_SIZE']);
		}

		$path = '/resize_cache/' . $arFile['ID'] . '/';
		$arCloudFiles = $bucket->ListFiles($path, true);
		if (is_array($arCloudFiles['file']))
		{
			$delete_size = 0;
			foreach ($arCloudFiles['file'] as $i => $file_name)
			{
				$tmp = $bucket->DeleteFile($path . $file_name);
				if ($tmp)
				{
					$bucket->DecFileCounter($arCloudFiles['file_size'][$i]);
					$delete_size += $arCloudFiles['file_size'][$i];
				}
			}
			/****************************** QUOTA ******************************/
			if ($delete_size > 0 && COption::GetOptionInt('main', 'disk_space') > 0)
			{
				CDiskQuota::updateDiskQuota('file', $delete_size, 'delete');
			}
			/****************************** QUOTA ******************************/
		}

		$DB->Query('
			DELETE FROM b_clouds_file_resize
			WHERE FILE_ID = ' . intval($arFile['ID']) . '
		', true);

		\Bitrix\Clouds\FileHashTable::deleteByFilePath($bucket->ID, '/' . $arFile['SUBDIR'] . '/' . $arFile['FILE_NAME']);

		return $result;
	}

	public static function DeleteDirFilesEx($path)
	{
		$path = rtrim($path, '/') . '/';
		foreach (CCloudStorageBucket::GetAllBuckets() as $bucket)
		{
			$obBucket = new CCloudStorageBucket($bucket['ID']);
			if (
				$obBucket->Init()
				&& ($obBucket->READ_ONLY === 'N')
				&& ($obBucket->ACTIVE === 'Y')
			)
			{
				$arCloudFiles = $obBucket->ListFiles($path, true);
				if (is_array($arCloudFiles['file']))
				{
					foreach ($arCloudFiles['file'] as $i => $file_name)
					{
						$tmp = $obBucket->DeleteFile($path . $file_name);
						if ($tmp)
						{
							$obBucket->DecFileCounter($arCloudFiles['file_size'][$i]);
						}
					}
				}
			}
		}
	}

	public static function OnFileCopy(&$arFile, $newPath = '')
	{
		if ($arFile['HANDLER_ID'] <= 0)
		{
			return false;
		}

		$bucket = new CCloudStorageBucket($arFile['HANDLER_ID']);
		if (!$bucket->Init())
		{
			return false;
		}

		if ($bucket->READ_ONLY === 'Y')
		{
			return false;
		}

		$filePath = '';
		$newName = '';

		if ($newPath !== '')
		{
			$filePath = '/' . trim(str_replace('//', '/', $newPath), '/');
		}
		else
		{
			$strFileExt = strrchr($arFile['FILE_NAME'], '.');
			while (true)
			{
				$newName = md5(uniqid(mt_rand(), true)) . $strFileExt;
				$filePath = '/' . $arFile['SUBDIR'] . '/' . $newName;
				if (!$bucket->FileExists($filePath))
				{
					break;
				}
			}
		}

		if ($newPath === '')
		{
			if ($arFile['EXTERNAL_ID'] == '')
			{
				$arFile['EXTERNAL_ID'] = md5(mt_rand());
			}

			\Bitrix\Clouds\FileSaveTable::startFileOperation(
				$bucket->ID
				,$arFile['SUBDIR']
				,$newName
				,$arFile['EXTERNAL_ID']
			);
		}

		$result = $bucket->FileCopy($arFile, $filePath);

		if ($result)
		{
			$copySize = $arFile['FILE_SIZE'];
			$bucket->IncFileCounter($copySize);
			\Bitrix\Clouds\FileSaveTable::setFileSize(
				$bucket->ID
				,$arFile['SUBDIR']
				,$newName
				,$copySize
			);

			if ($newPath !== '')
			{
				$arFile['FILE_NAME'] = bx_basename($filePath);
				$arFile['SUBDIR'] = mb_substr($filePath, 1, -(mb_strlen(bx_basename($filePath)) + 1));
			}
			else
			{
				$arFile['FILE_NAME'] = $newName;
			}
		}

		return $result;
	}

	public static function OnGetFileSRC($arFile)
	{
		if ($arFile['HANDLER_ID'] <= 0)
		{
			return false;
		}

		$bucket = new CCloudStorageBucket($arFile['HANDLER_ID']);
		if ($bucket->Init())
		{
			return $bucket->GetFileSRC($arFile, false);
		}

		return false;
	}

	protected static function _delete_file($file)
	{
		if (is_array($file))
		{
			CCloudStorage::OnFileDelete($file);
		}
		elseif (is_string($file) && file_exists($file))
		{
			unlink($file);
			@rmdir(mb_substr($file, 0, -mb_strlen(bx_basename($file))));
		}
	}

	public static function MoveFile($arFile, $obTargetBucket)
	{
		$io = CBXVirtualIo::GetInstance();
		self::$file_skip_reason = '';

		//Try to find suitable bucket for the file
		$bucket = CCloudStorage::FindBucketForFile($arFile, $arFile['FILE_NAME']);
		if (!is_object($bucket))
		{
			return CCloudStorage::FILE_SKIPPED;
		}

		if (!$bucket->Init())
		{
			self::$file_skip_reason = 'FAILED_TO_INIT_BUCKET';
			return CCloudStorage::FILE_SKIPPED;
		}

		//Check if this is same bucket as the target
		if ($bucket->ID != $obTargetBucket->ID)
		{
			self::$file_skip_reason = 'FOUND_BUCKET_DOES_NOT_MATCH_TARGET';
			return CCloudStorage::FILE_SKIPPED;
		}

		$filePath = '/' . $arFile['SUBDIR'] . '/' . $arFile['FILE_NAME'];
		$filePath = preg_replace('#[\\\\/]+#', '/', $filePath);

		if ($bucket->FileExists($filePath))
		{
			self::$file_skip_reason = 'CLOUD_FILE_EXISTS';
			return CCloudStorage::FILE_SKIPPED;
		}

		if ($arFile['FILE_SIZE'] > $bucket->getService()->GetMinUploadPartSize())
		{
			$obUpload = new CCloudStorageUpload($filePath);
			if (!$obUpload->isStarted())
			{
				if ($arFile['HANDLER_ID'])
				{
					$ar = [];
					if (!CCloudStorage::OnMakeFileArray($arFile, $ar))
					{
						self::$file_skip_reason = 'FAILED_TO_DOWNLOAD_FILE_1';
						return CCloudStorage::FILE_SKIPPED;
					}

					if (!isset($ar['tmp_name']))
					{
						self::$file_skip_reason = 'FAILED_TO_DOWNLOAD_FILE_2';
						return CCloudStorage::FILE_SKIPPED;
					}
				}
				else
				{
					$ar = CFile::MakeFileArray($arFile['ID']);
					if (!isset($ar['tmp_name']))
					{
						self::$file_skip_reason = 'FAILED_TO_GET_SOURCE_FILE_INFO_1';
						return CCloudStorage::FILE_SKIPPED;
					}
				}

				$temp_file = CTempFile::GetDirectoryName(2, 'clouds') . bx_basename($arFile['FILE_NAME']);
				$temp_fileX = $io->GetPhysicalName($temp_file);
				CheckDirPath($temp_fileX);

				if (file_exists($ar['tmp_name']))
				{
					$sourceFile = $ar['tmp_name'];
				}
				elseif (file_exists($io->GetPhysicalName($ar['tmp_name'])))
				{
					$sourceFile = $io->GetPhysicalName($ar['tmp_name']);
				}
				else
				{
					self::$file_skip_reason = 'FAILED_TO_FIND_SOURCE_FILE';
					return CCloudStorage::FILE_SKIPPED;
				}

				if (!copy($sourceFile, $temp_fileX))
				{
					self::$file_skip_reason = 'FAILED_TO_COPY_SOURCE_FILE';
					return CCloudStorage::FILE_SKIPPED;
				}

				if ($obUpload->Start($bucket->ID, $arFile['FILE_SIZE'], $arFile['CONTENT_TYPE'], $temp_file))
				{
					return CCloudStorage::FILE_PARTLY_UPLOADED;
				}
				else
				{
					self::$file_skip_reason = 'FAILED_TO_START_UPLOAD';
					return CCloudStorage::FILE_SKIPPED;
				}
			}
			else
			{
				$temp_file = $obUpload->getTempFileName();
				$temp_fileX = $io->GetPhysicalName($temp_file);

				$fp = fopen($temp_fileX, 'rb');
				if (!is_resource($fp))
				{
					self::$file_skip_reason = 'FAILED_TO_READ_SOURCE_FILE';
					return CCloudStorage::FILE_SKIPPED;
				}

				$pos = $obUpload->GetPos();
				if ($pos >= filesize($temp_fileX))
				{
					if ($obUpload->Finish())
					{
						$bucket->IncFileCounter(filesize($temp_fileX));

						if ($arFile['HANDLER_ID'])
						{
							self::_delete_file($arFile);
						}
						else
						{
							$ar = CFile::MakeFileArray($arFile['ID']);
							$fileNameX = $io->GetPhysicalName($ar['tmp_name']);
							self::_delete_file($fileNameX);
						}

						return CCloudStorage::FILE_MOVED;
					}
					else
					{
						self::$file_skip_reason = 'FAILED_TO_FINISH_UPLOAD';
						return CCloudStorage::FILE_SKIPPED;
					}
				}

				fseek($fp, $pos);
				self::$part_count = $obUpload->GetPartCount();
				self::$part_size = $obUpload->getPartSize();
				$part = fread($fp, self::$part_size);
				while ($obUpload->hasRetries())
				{
					if ($obUpload->Next($part))
					{
						return CCloudStorage::FILE_PARTLY_UPLOADED;
					}
				}

				self::$file_skip_reason = 'FAILED_TO_UPLOAD_FILE_CHUNK';
				return CCloudStorage::FILE_SKIPPED;
			}
		}
		else
		{
			if ($arFile['HANDLER_ID'])
			{
				$ar = [];
				if (!CCloudStorage::OnMakeFileArray($arFile, $ar))
				{
					self::$file_skip_reason = 'FAILED_TO_DOWNLOAD_FILE_3';
					return CCloudStorage::FILE_SKIPPED;
				}

				if (!isset($ar['tmp_name']))
				{
					self::$file_skip_reason = 'FAILED_TO_DOWNLOAD_FILE_4';
					return CCloudStorage::FILE_SKIPPED;
				}
			}
			else
			{
				$ar = CFile::MakeFileArray($arFile['ID']);
				if (!isset($ar['tmp_name']))
				{
					self::$file_skip_reason = 'FAILED_TO_GET_SOURCE_FILE_INFO_2';
					return CCloudStorage::FILE_SKIPPED;
				}
			}

			$res = $bucket->SaveFile($filePath, $ar);
			if ($res)
			{
				$bucket->IncFileCounter(filesize($ar['tmp_name']));

				if ($arFile['HANDLER_ID'])
				{
					self::_delete_file($arFile);
				}
				else
				{
					self::_delete_file($ar['tmp_name']);
				}

				self::$file_skip_reason = 'FAILED_TO_UPLOAD_FILE';
				return CCloudStorage::FILE_MOVED;
			}
			else
			{
		//delete temporary copy
				if ($arFile['HANDLER_ID'])
				{
					self::_delete_file($ar['tmp_name']);
				}

				return CCloudStorage::FILE_SKIPPED;
			}
		}
	}

	public static function OnFileSave(&$arFile, $strFileName, $strSavePath, $bForceMD5 = false, $bSkipExt = false, $dirAdd = '')
	{
		if (!$arFile['tmp_name'] && !array_key_exists('content', $arFile))
		{
			return false;
		}

		if (array_key_exists('bucket', $arFile))
		{
			$bucket = $arFile['bucket'];
		}
		else
		{
			$bucket = CCloudStorage::FindBucketForFile($arFile, $strFileName);
		}

		if (!is_object($bucket))
		{
			return false;
		}

		if (!$bucket->Init())
		{
			return false;
		}

		$original = null;
		$copySize = false;
		$subDir = '';
		$filePath = '';

		if (array_key_exists('bucket', $arFile))
		{
			$newName = bx_basename($arFile['tmp_name']);

			$prefix = $bucket->GetFileSRC('/');
			$subDir = mb_substr($arFile['tmp_name'], mb_strlen($prefix));
			$subDir = mb_substr($subDir, 0, -mb_strlen($newName) - 1);
		}
		else
		{
			if (array_key_exists('content', $arFile))
			{
				$arFile['tmp_name'] = CTempFile::GetFileName(bx_basename($arFile['name']));
				CheckDirPath($arFile['tmp_name']);
				$fp = fopen($arFile['tmp_name'], 'ab');
				if ($fp)
				{
					fwrite($fp, $arFile['content']);
					fclose($fp);
				}
			}

			if (
				!$bForceMD5
				&& COption::GetOptionString('main', 'save_original_file_name', 'N') == 'Y'
			)
			{
				if (COption::GetOptionString('main', 'convert_original_file_name', 'Y') == 'Y')
				{
					$newName = CCloudStorage::translit($strFileName);
				}
				else
				{
					$newName = $strFileName;
				}
			}
			else
			{
				$strFileExt = ($bSkipExt ? '' : strrchr($strFileName, '.'));
				$newName = md5(uniqid(mt_rand(), true)) . $strFileExt;
			}

			//check for double extension vulnerability
			$newName = RemoveScriptExtension($newName);
			$dir_add = $dirAdd;

			if (empty($dir_add))
			{
				while (true)
				{
					$dir_add = md5(mt_rand());
					$dir_add = mb_substr($dir_add, 0, 3) . '/' . $dir_add;

					$subDir = trim(trim($strSavePath, '/') . '/' . $dir_add, '/');
					$filePath = '/' . $subDir . '/' . $newName;

					if (!$bucket->FileExists($filePath))
					{
						break;
					}
				}
			}
			else
			{
				$subDir = trim(trim($strSavePath, '/') . '/' . $dir_add, '/');
				$filePath = '/' . $subDir . '/' . $newName;
			}

			if (!isset($arFile['external_id']))
			{
				$arFile['external_id'] = md5(mt_rand());
			}

			\Bitrix\Clouds\FileSaveTable::startFileOperation(
				$bucket->ID
				,$subDir
				,$newName
				,$arFile['external_id']
			);

			$targetPath = $bucket->GetFileSRC('/');
			if (mb_strpos($arFile['tmp_name'], $targetPath) === 0)
			{
				$arDbFile = [
					'SUBDIR' => '',
					'FILE_NAME' => mb_substr($arFile['tmp_name'], mb_strlen($targetPath)),
					'CONTENT_TYPE' => $arFile['type'],
				];

				//get the file hash
				$arFile['FILE_HASH'] = '';
				if (COption::GetOptionString('main', 'control_file_duplicates', 'N') === 'Y')
				{
					$info = $bucket->GetFileInfo('/' . $arDbFile['FILE_NAME']);
					if ($info)
					{
						$arFile['FILE_HASH'] = $info['hash'];
						$copySize = $info['size'];
					}
				}

				//control of duplicates
				if ($arFile['FILE_HASH'] <> '')
				{
					$original = CFile::FindDuplicate($copySize, $arFile['FILE_HASH'], $bucket->ID);
					if ($original !== null)
					{
						$arFile['original_file'] = $original;
					}
				}

				//copy only if the file is not a duplicate
				if ($original === null)
				{
					$copyPath = $bucket->FileCopy($arDbFile, $filePath);
					if (!$copyPath)
					{
						return false;
					}

					if ($copySize === false)
					{
						$info = $bucket->GetFileInfo('/' . urldecode(mb_substr($copyPath, mb_strlen($targetPath))));
						if ($info)
						{
							$copySize = $info['size'];
						}
						else
						{
							return false;
						}
					}
				}
			}
			else
			{
				if (!$bucket->SaveFile($filePath, $arFile))
				{
					return false;
				}

				//get the file hash
				$arFile['FILE_HASH'] = '';
				$size = 0;
				if (COption::GetOptionString('main', 'control_file_duplicates', 'N') === 'Y')
				{
					$info = $bucket->GetFileInfo($filePath);
					if ($info)
					{
						$arFile['FILE_HASH'] = $info['hash'];
						$size = $info['size'];
					}
				}

				//control of duplicates
				if ($arFile['FILE_HASH'] <> '')
				{
					$original = CFile::FindDuplicate($size, $arFile['FILE_HASH'], $bucket->ID);
					if ($original !== null)
					{
						$arFile['original_file'] = $original;

						//we don't need the duplicate anymore
						$bucket->DeleteFile($filePath);
					}
				}
			}
		}

		$arFile['HANDLER_ID'] = $bucket->ID;
		$arFile['WIDTH'] = 0;
		$arFile['HEIGHT'] = 0;

		if ($original === null)
		{
			$arFile['SUBDIR'] = $subDir;
			$arFile['FILE_NAME'] = $newName;
		}
		else
		{
			//points to the original's physical path
			$arFile['SUBDIR'] = $original->getFile()->getSubdir();
			$arFile['FILE_NAME'] = $original->getFile()->getFileName();
		}

		if (array_key_exists('bucket', $arFile))
		{
			$arFile['WIDTH'] = $arFile['width'];
			$arFile['HEIGHT'] = $arFile['height'];
			$arFile['size'] = $arFile['file_size'];
		}
		elseif ($copySize !== false)
		{
			$arFile['WIDTH'] = $arFile['width'];
			$arFile['HEIGHT'] = $arFile['height'];
			$arFile['size'] = $copySize;

			//if the file is a duplicate we shouldn't increase the size counter
			if ($original === null)
			{
				$bucket->IncFileCounter($copySize);
				\Bitrix\Clouds\FileSaveTable::setFileSize(
					$bucket->ID
					,$subDir
					,$newName
					,$copySize
				);
			}
		}
		else
		{
			//if the file is a duplicate we shouldn't increase the size counter
			if ($original === null)
			{
				$fileSize = filesize($arFile['tmp_name']);
				$bucket->IncFileCounter($fileSize);
				\Bitrix\Clouds\FileSaveTable::setFileSize(
					$bucket->ID
					,$subDir
					,$newName
					,$fileSize
				);
			}

			$image = new \Bitrix\Main\File\Image($arFile['tmp_name']);
			$flashEnabled = !CFile::IsImage($arFile['ORIGINAL_NAME'], $arFile['type']);
			$info = $image->getInfo($flashEnabled);
			if ($info !== null)
			{
				$arFile['WIDTH'] = $info->getWidth();
				$arFile['HEIGHT'] = $info->getHeight();
			}
		}

		if (isset($arFile['old_file']))
		{
			CFile::Delete($arFile['old_file']);
		}

		return true;
	}

	public static function OnAfterFileSave($arFile)
	{
		\Bitrix\Clouds\FileSaveTable::endFileOperation(
			$arFile['HANDLER_ID']
			,$arFile['SUBDIR']
			,$arFile['FILE_NAME']
		);
	}

	public static function OnAfterFileDeleteDuplicate($original, $duplicate)
	{
		$result = false;
		if ($original->getHandlerId() > 0)
		{
			$bucket = new CCloudStorageBucket($original->getHandlerId());
			if ($bucket->Init())
			{
				$duplicatePath = '/' . $duplicate->getSubdir() . '/' . $duplicate->getFileName();
				\Bitrix\Clouds\FileHashTable::deleteByFilePath($original->getHandlerId(), $duplicatePath);

				$result = $bucket->DeleteFile($duplicatePath, $duplicate->getFileSize());
				if ($result)
				{
					$bucket->DecFileCounter($duplicate->getFileSize());
				}
			}
		}
		return $result;
	}

	public static function CleanUp()
	{
		$buckets = [];
		$date = new \Bitrix\Main\Type\DateTime();
		$date->add('-1D');
		$savedFiles = \Bitrix\Clouds\FileSaveTable::getList([
			'filter' => [
				'<TIMESTAMP_X' => $date,
			],
			'limit' => 100, // ~10 sec
		]);
		while ($saveFile = $savedFiles->fetchObject())
		{
			$dbFile = CFile::GetList([], [
				'EXTERNAL_ID' => $saveFile->getExternalId(),
				'SUBDIR' => $saveFile->getSubdir(),
				'FILE_NAME' => $saveFile->getFileName(),
				'HANDLER_ID' => $saveFile->getBucketId(),
			]);
			if ($dbFile->Fetch())
			{
				$saveFile->delete();
			}
			else
			{
				$bucketId = $saveFile->getBucketId();
				if (!isset($buckets[$bucketId]))
				{
					$buckets[$bucketId] = new \CCloudStorageBucket($bucketId);
				}
				$bucket = $buckets[$bucketId];

				if ($bucket->Init())
				{
					$filePath = '/' . $saveFile->getSubdir() . '/' . $saveFile->getFileName();
					if ($bucket->DeleteFile($filePath))
					{
						$fileSize = $saveFile->getFileSize();
						if ($fileSize >= 0)
						{
							$bucket->DecFileCounter($fileSize);
						}
					}
					$saveFile->delete();
				}
			}
		}

		CCloudStorageUpload::CleanUp();

		return 'CCloudStorage::CleanUp();';
	}

	public static function FindBucketByFile($file_name)
	{
		foreach (CCloudStorageBucket::GetAllBuckets() as $bucket)
		{
			if ($bucket['ACTIVE'] == 'Y')
			{
				$obBucket = new CCloudStorageBucket($bucket['ID']);
				if ($obBucket->Init())
				{
					$prefix = $obBucket->GetFileSRC('/');
					if (mb_substr($file_name, 0, mb_strlen($prefix)) === $prefix)
					{
						return $obBucket;
					}
				}
			}
		}
		return false;
	}

	public static function FindFileURIByURN($urn, $log_descr = '')
	{
		foreach (CCloudStorageBucket::GetAllBuckets() as $bucket)
		{
			if ($bucket['ACTIVE'] == 'Y')
			{
				$obBucket = new CCloudStorageBucket($bucket['ID']);
				if ($obBucket->Init() && $obBucket->FileExists($urn))
				{
					$uri = $obBucket->GetFileSRC($urn);

					if ($log_descr && COption::GetOptionString('clouds', 'log_404_errors') === 'Y')
					{
						CEventLog::Log('WARNING', 'CLOUDS_404', 'clouds', $uri, $log_descr);
					}

					return $uri;
				}
			}
		}
		return '';
	}

	public static function OnBuildGlobalMenu(&$aGlobalMenu, &$aModuleMenu)
	{
		global $USER;
		if (!$USER->CanDoOperation('clouds_browse'))
		{
			return;
		}

		//When UnRegisterModuleDependences is called from module uninstall
		//cached EventHandlers may be called
		if (defined('BX_CLOUDS_UNINSTALLED'))
		{
			return;
		}

		$aMenu = [
			'parent_menu' => 'global_menu_content',
			'section' => 'clouds',
			'sort' => 150,
			'text' => GetMessage('CLO_STORAGE_MENU'),
			'title' => GetMessage('CLO_STORAGE_TITLE'),
			'icon' => 'clouds_menu_icon',
			'page_icon' => 'clouds_page_icon',
			'items_id' => 'menu_clouds',
			'items' => []
		];

		$rsBuckets = CCloudStorageBucket::GetList(['SORT' => 'DESC', 'ID' => 'ASC']);
		while ($arBucket = $rsBuckets->Fetch())
		{
			$aMenu['items'][] = [
				'text' => $arBucket['BUCKET'],
				'url' => 'clouds_file_list.php?lang=' . LANGUAGE_ID . '&bucket=' . $arBucket['ID'] . '&path=/',
				'more_url' => [
					'clouds_file_list.php?bucket=' . $arBucket['ID'],
				],
				'title' => '',
				'page_icon' => 'clouds_page_icon',
				'items_id' => 'menu_clouds_bucket_' . $arBucket['ID'],
				'module_id' => 'clouds',
				'items' => []
			];
		}

		if (!empty($aMenu['items']))
		{
			$aModuleMenu[] = $aMenu;
		}
	}

	public static function OnAdminListDisplay(&$obList)
	{
		global $USER;

		if ($obList->table_id !== 'tbl_fileman_admin')
		{
			return;
		}

		if (!is_object($USER) || !$USER->CanDoOperation('clouds_upload'))
		{
			return;
		}

		static $clouds = null;
		if (!isset($clouds))
		{
			$clouds = [];
			$rsClouds = CCloudStorageBucket::GetList(['SORT' => 'DESC', 'ID' => 'ASC']);
			while ($arStorage = $rsClouds->Fetch())
			{
				if ($arStorage['READ_ONLY'] == 'N' && $arStorage['ACTIVE'] == 'Y')
				{
					$clouds[$arStorage['ID']] = $arStorage['BUCKET'];
				}
			}
		}

		if (empty($clouds))
		{
			return;
		}

		foreach ($obList->aRows as $obRow)
		{
			if ($obRow->arRes['TYPE'] === 'F')
			{
				$ID = 'F' . $obRow->arRes['NAME'];
				$file = $obRow->arRes['NAME'];
				$path = mb_substr($obRow->arRes['ABS_PATH'], 0, -mb_strlen($file));

				$arSubMenu = [];
				foreach ($clouds as $id => $bucket)
				{
					$arSubMenu[] = [
						'TEXT' => $bucket,
						'ACTION' => $s = "if(confirm('" . GetMessage('CLO_STORAGE_UPLOAD_CONF') . "')) jsUtils.Redirect([], '" . CUtil::AddSlashes('/bitrix/admin/clouds_file_list.php?lang=' . LANGUAGE_ID . '&bucket=' . urlencode($id) . '&path=' . urlencode($path) . '&ID=' . urlencode($ID) . '&action=upload&' . bitrix_sessid_get()) . "');"
					];
				}

				$obRow->aActions[] = [
					'TEXT' => GetMessage('CLO_STORAGE_UPLOAD_MENU'),
					'MENU' => $arSubMenu,
				];
			}
		}
	}

	public static function HasActiveBuckets()
	{
		foreach (CCloudStorageBucket::GetAllBuckets() as $bucket)
		{
			if ($bucket['ACTIVE'] === 'Y')
			{
				return true;
			}
		}
		return false;
	}

	public static function OnBeforeProlog()
	{
		if (defined('BX_CHECK_SHORT_URI') && BX_CHECK_SHORT_URI)
		{
			$upload_dir = '/' . trim(COption::GetOptionString('main', 'upload_dir', 'upload'), '/') . '/';
			$request_uri = rawurldecode($_SERVER['REQUEST_URI']);

			foreach (CCloudStorageBucket::GetAllBuckets() as $arBucket)
			{
				if ($arBucket['ACTIVE'] == 'Y')
				{
					$obBucket = new CCloudStorageBucket($arBucket['ID']);
					if ($obBucket->Init())
					{
						$bucketUrl = $obBucket->GetFileSRC('/');
						$bucketPrefix = rtrim(parse_url($bucketUrl, PHP_URL_PATH), '/');
						$prefixMatch = $bucketPrefix ? '(?:' . $bucketPrefix . '|)' : '';
						$match = [];
						if (
							COption::GetOptionString('clouds', 'delayed_resize') === 'Y'
							&& preg_match('#^' . $prefixMatch . '(/resize_cache/.*$)#', $request_uri, $match)
						)
						{
							session_write_close();
							$to_file = $obBucket->GetFileSRC($match[1], false);
							if (CCloudStorage::ResizeImageFileCheck($obBucket, $to_file))
							{
								$cache_time = 3600 * 24 * 30; // 30 days
								header('Cache-Control: max-age=' . $cache_time);
								header('Expires: ' . gmdate('D, d M Y H:i:s', time() + $cache_time) . ' GMT');
								header_remove('Pragma');
								LocalRedirect(\Bitrix\Main\Web\Uri::urnEncode($to_file, 'UTF-8'), true, '301 Moved Permanently');
							}
						}
						elseif (
							!preg_match('/[?&]/', $request_uri)
							&& $obBucket->FileExists($request_uri)
						)
						{
							if (COption::GetOptionString('clouds', 'log_404_errors') === 'Y')
							{
								CEventLog::Log('WARNING', 'CLOUDS_404', 'clouds', $_SERVER['REQUEST_URI'], $_SERVER['HTTP_REFERER']);
							}
							LocalRedirect($obBucket->GetFileSRC($request_uri), true);
						}
						elseif (mb_strpos($request_uri, $upload_dir) === 0)
						{
							$check_url = mb_substr($request_uri, mb_strlen($upload_dir) - 1);
							if ($obBucket->FileExists($check_url))
							{
								if (COption::GetOptionString('clouds', 'log_404_errors') === 'Y')
								{
									CEventLog::Log('WARNING', 'CLOUDS_404', 'clouds', $_SERVER['REQUEST_URI'], $_SERVER['HTTP_REFERER']);
								}
								LocalRedirect($obBucket->GetFileSRC($check_url), true);
							}
						}
					}
				}
			}
		}
	}

	public static function GetAuditTypes()
	{
		return [
			'CLOUDS_404' => '[CLOUDS_404] ' . GetMessage('CLO_404_ON_MOVED_FILE'),
		];
	}

	public static function translit($file_name, $safe_chars = '')
	{
		return CUtil::translit($file_name, LANGUAGE_ID, [
			'safe_chars' => '-. ' . $safe_chars,
			'change_case' => false,
			'max_len' => 255,
		]);
	}

	/**
	 * @param array [string]string $arFile
	 * @return void
	 */
	public static function FixFileContentType(&$arFile)
	{
		global $DB;
		$fixedContentType = '';

		if ($arFile['CONTENT_TYPE'] === 'image/jpg')
		{
			$fixedContentType = 'image/jpeg';
		}
		else
		{
			$hexContentType = unpack('H*', $arFile['CONTENT_TYPE']);
			if (
				$hexContentType[1] === 'e0f3e4e8ee2f6d706567'
				|| $hexContentType[1] === 'd0b0d183d0b4d0b8d0be2f6d706567'
			)
			{
				$fixedContentType = 'audio/mpeg';
			}
		}

		if ($fixedContentType !== '')
		{
			$arFile['CONTENT_TYPE'] = $fixedContentType;
			$DB->Query("
				UPDATE b_file
				SET CONTENT_TYPE = '" . $DB->ForSQL($fixedContentType) . "'
				WHERE ID = " . intval($arFile['ID']) . '
			');
			CFile::CleanCache($arFile['ID']);
		}
	}
}

Youez - 2016 - github.com/yon3zu
LinuXploit