| Current Path : /var/www/homesaver/www/bitrix/modules/clouds/classes/general/ |
| Current File : /var/www/homesaver/www/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 = '';
protected static $lockId = '';
/**
* @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'] <> '')
{
if (is_callable(['CFile', 'lockFileHash']))
{
static::$lockId = CFile::lockFileHash($size, $arFile['FILE_HASH'], $bucket->ID);
}
$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']
);
if (static::$lockId)
{
CFile::unlockFileHash(static::$lockId);
static::$lockId = '';
}
}
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']);
}
}
}