Your IP : 18.117.75.102


Current Path : /home/bitrix/ext_www/easy-comfort.com.ua/local/php_interface/include/
Upload File :
Current File : /home/bitrix/ext_www/easy-comfort.com.ua/local/php_interface/include/functions.php

<?php

// Функция трассировки
function dump($var, $varDump = false, $return = false){
	static $dumpCnt;

	if(is_null($dumpCnt)){
		$dumpCnt = 0;
	}
	ob_start();

	echo '<p>';
	$style = "
			border: 1px solid #696969;
			background: #eee;
			border-radius: 3px;
			font-size: 14px;
			font-family: calibri, arial, sans-serif;
			padding: 20px;
			";
	echo '<b>DUMP #'.$dumpCnt.':</b> ';
	echo '<pre style="'.$style.'">';
	if($varDump){
		var_dump($var);
	}else{
		print_r($var);
	}
	echo '</pre>';
	echo '</p>';

	$cnt = ob_get_contents();
	ob_end_clean();
	$dumpCnt++;
	if($return){
		return $cnt;
	}else{
		echo $cnt;
	}
	return true;
}

function cdump($var){
	echo "<script>";
	echo "console.log(".json_encode($var).");";
	echo "</script>";
}

/**
 * @param $n
 * @param $forms
 * @return mixed
 * Возвращает слово с нужным окончанием в зависимости от числа перед словом
 */
function plural($n, $forms){
	return $n % 10 == 1 && $n % 100 != 11 ? $forms[0] : ($n % 10 >= 2 && $n % 10 <= 4 &&
	($n % 100 < 10 || $n % 100 >= 20) ? $forms[1] : $forms[2]);
}


/* Аналог ResizeImageGet, только с Upscale */
class CWPFile extends CAllFile {
	public static function ResizeImageGet($file, $arSize, $resizeType = BX_RESIZE_IMAGE_PROPORTIONAL, $bInitSizes = false, $arFilters = false, $bImmediate = false, $jpgQuality = false)
	{
		if (!is_array($file) && intval($file) > 0)
		{
			$file = CFile::GetFileArray($file);
		}

		if (!is_array($file) || !array_key_exists("FILE_NAME", $file) || strlen($file["FILE_NAME"]) <= 0)
			return false;

		if ($resizeType !== BX_RESIZE_IMAGE_EXACT && $resizeType !== BX_RESIZE_IMAGE_PROPORTIONAL_ALT)
			$resizeType = BX_RESIZE_IMAGE_PROPORTIONAL;

		if (!is_array($arSize))
			$arSize = array();
		if (!array_key_exists("width", $arSize) || intval($arSize["width"]) <= 0)
			$arSize["width"] = 0;
		if (!array_key_exists("height", $arSize) || intval($arSize["height"]) <= 0)
			$arSize["height"] = 0;
		$arSize["width"] = intval($arSize["width"]);
		$arSize["height"] = intval($arSize["height"]);

		$uploadDirName = COption::GetOptionString("main", "upload_dir", "upload");

		$imageFile = "/".$uploadDirName."/".$file["SUBDIR"]."/".$file["FILE_NAME"];
		$arImageSize = false;
		$bFilters = is_array($arFilters) && !empty($arFilters);

		/*
		if (
			($arSize["width"] <= 0 || $arSize["width"] >= $file["WIDTH"])
			&& ($arSize["height"] <= 0 || $arSize["height"] >= $file["HEIGHT"])
		)
		{
			if($bFilters)
			{
				//Only filters. Leave size unchanged
				$arSize["width"] = $file["WIDTH"];
				$arSize["height"] = $file["HEIGHT"];
				$resizeType = BX_RESIZE_IMAGE_PROPORTIONAL;
			}
			else
			{
				global $arCloudImageSizeCache;
				$arCloudImageSizeCache[$file["SRC"]] = array($file["WIDTH"], $file["HEIGHT"]);

				return array(
					"src" => $file["SRC"],
					"width" => intval($file["WIDTH"]),
					"height" => intval($file["HEIGHT"]),
					"size" => $file["FILE_SIZE"],
				);
			}
		} */

		$io = CBXVirtualIo::GetInstance();
		$cacheImageFile = "/".$uploadDirName."/resize_cache/".$file["SUBDIR"]."/".$arSize["width"]."_".$arSize["height"]."_".$resizeType.(is_array($arFilters)? md5(serialize($arFilters)): "")."/".$file["FILE_NAME"];

		$cacheImageFileCheck = $cacheImageFile;
		if ($file["CONTENT_TYPE"] == "image/bmp")
			$cacheImageFileCheck .= ".jpg";

		static $cache = array();
		$cache_id = $cacheImageFileCheck;
		if(isset($cache[$cache_id]))
		{
			return $cache[$cache_id];
		}
		elseif (!file_exists($io->GetPhysicalName($_SERVER["DOCUMENT_ROOT"].$cacheImageFileCheck)))
		{
			/****************************** QUOTA ******************************/
			$bDiskQuota = true;
			if (COption::GetOptionInt("main", "disk_space") > 0)
			{
				$quota = new CDiskQuota();
				$bDiskQuota = $quota->checkDiskQuota($file);
			}
			/****************************** QUOTA ******************************/

			if ($bDiskQuota)
			{
				if(!is_array($arFilters))
					$arFilters = array(
						array("name" => "sharpen", "precision" => 15),
					);

				$sourceImageFile = $_SERVER["DOCUMENT_ROOT"].$imageFile;
				$cacheImageFileTmp = $_SERVER["DOCUMENT_ROOT"].$cacheImageFile;
				$bNeedResize = true;
				$callbackData = null;

				foreach(GetModuleEvents("main", "OnBeforeResizeImage", true) as $arEvent)
				{
					if(ExecuteModuleEventEx($arEvent, array(
						$file,
						array($arSize, $resizeType, array(), false, $arFilters, $bImmediate),
						&$callbackData,
						&$bNeedResize,
						&$sourceImageFile,
						&$cacheImageFileTmp,
					)))
						break;
				}

				if ($bNeedResize && CFile::ResizeImageFile($sourceImageFile, $cacheImageFileTmp, $arSize, $resizeType, array(), $jpgQuality, $arFilters))
				{
					$cacheImageFile = substr($cacheImageFileTmp, strlen($_SERVER["DOCUMENT_ROOT"]));

					/****************************** QUOTA ******************************/
					if (COption::GetOptionInt("main", "disk_space") > 0)
						CDiskQuota::updateDiskQuota("file", filesize($io->GetPhysicalName($cacheImageFileTmp)), "insert");
					/****************************** QUOTA ******************************/
				}
				else
				{
					$cacheImageFile = $imageFile;
				}

				foreach(GetModuleEvents("main", "OnAfterResizeImage", true) as $arEvent)
				{
					if(ExecuteModuleEventEx($arEvent, array(
						$file,
						array($arSize, $resizeType, array(), false, $arFilters),
						&$callbackData,
						&$cacheImageFile,
						&$cacheImageFileTmp,
						&$arImageSize,
					)))
						break;
				}
			}
			else
			{
				$cacheImageFile = $imageFile;
			}

			$cacheImageFileCheck = $cacheImageFile;
		}

		if ($bInitSizes && !is_array($arImageSize))
		{
			$arImageSize = CFile::GetImageSize($_SERVER["DOCUMENT_ROOT"].$cacheImageFileCheck);

			$f = $io->GetFile($_SERVER["DOCUMENT_ROOT"].$cacheImageFileCheck);
			$arImageSize[2] = $f->GetFileSize();
		}

		$cache[$cache_id] = array(
			"src" => $cacheImageFileCheck,
			"width" => intval($arImageSize[0]),
			"height" => intval($arImageSize[1]),
			"size" => $arImageSize[2],
		);
		return $cache[$cache_id];
	}
}


// Возвращает уменьшенную картинку. Размеры картинок задаются в settings.php
// Пример: $arImage = resizeImageGet($arProperties['IMAGE'], 'CATALOG_ITEM_LIST');
// В ответе массив из 'SRC', 'WIDTH', 'HEIGHT';

function resizeImageGet($file, $sizeName){
	global $arImageSizes;
	if(isset($arImageSizes[$sizeName])){
		if(is_array($arImageSizes[$sizeName]['FILTER'])){
			$filters = $arImageSizes[$sizeName]['FILTER'];
		}else{
			switch ($arImageSizes[$sizeName]['FILTER']){
				case 'nosharp':
					$filters = Array(
						"name" => "sharpen",
						"precision" => 0
					);
					break;
				default:
					$filters = false;
			}
		}

		return CWPFile::ResizeImageGet(
			$file,
			array("width" => $arImageSizes[$sizeName]['WIDTH'], "height" => $arImageSizes[$sizeName]['HEIGHT']),
			$arImageSizes[$sizeName]['RESIZE'],
			true,
			$filters
		);
	}else{
		return CWPFile::ResizeImageGet(
			$file,
			array("width" => "1000", "height" => "1000"),
			BX_RESIZE_IMAGE_PROPORTIONAL,
			true
		);
	}
}

function resizeImageGetSrc($file, $sizeName){
	$file = resizeImageGet($file, $sizeName);
	if(!$file['src'] || !file_exists($_SERVER['DOCUMENT_ROOT'].$file['src'])){
		return SITE_TEMPLATE_PATH.NO_PHOTO_SRC;
	}

	return $file['src'];
}

/**
 * @param $file
 * @param $sizeName
 * @return array
 * Шаг 1. Обрезает/Уменьшает картинку по параметрам
 * При отсутствии картинки действие из шага 1 будет применено к стандартной картинке no_photo.png
 * Используется класс CWPFile, в котором переопределена функция ResizeImageGet, которая умеет увеличивать.
 */
function resizeImgInfo($file, $sizeName){
	global $arImageSizes;

    if (!is_array($file))
        $file = CFile::GetFileArray($file);
	$size = $arImageSizes[$sizeName];

	if(empty($file) || !file_exists($_SERVER['DOCUMENT_ROOT'].urldecode($file['SRC']))) {

		
		$filePath = $_SERVER['DOCUMENT_ROOT'].SITE_TEMPLATE_PATH.NO_PHOTO_SRC;

		$fileName = $size['WIDTH'] . 'x' . $size['HEIGHT'] . $size['RESIZE'] . basename($filePath);
		$fileNameRetina = $size['WIDTH'] . 'x' . $size['HEIGHT'] . $size['RESIZE'] . '@2x' . basename($filePath);

		$tmpImage = $_SERVER['DOCUMENT_ROOT'] . '/upload/tmp/' . $fileName;
		$tmpImageRetina = $_SERVER['DOCUMENT_ROOT'] . '/upload/tmp/' . $fileNameRetina;

        if(!file_exists($tmpImage)) {
            CFile::ResizeImageFile(
                $filePath,
                $tmpImage,
                array("width" => $size['WIDTH'], "height" => $size['HEIGHT']),
                $size['RESIZE']
            );
        }

        if(!file_exists($tmpImageRetina)) {
            CFile::ResizeImageFile(
                $filePath,
                $tmpImageRetina,
                array("width" => ($size['WIDTH'] * 2), "height" => ($size['HEIGHT']) * 2),
                $size['RESIZE']
            );
        }

        $arRet = array(
			'regularFile' => array(
				"src" => '/upload/tmp/' . $fileName
			),
			'retinaFile' => array(
				"src" => '/upload/tmp/' . $fileNameRetina
			)
		);

        if($size['DIMENSIONS'] == 'N'){
        	$arRet['dontSetDimension'] = true;
        }

		return $arRet;
	}

	if(isset($size)){
		if(is_array($size['FILTER'])){
			$filters = $size['FILTER'];
		}else{
			switch ($size['FILTER']){
				case 'nosharp':
					$filters = Array(
						"name" => "sharpen",
						"precision" => 0
					);
					break;
				default:
					$filters = false;
			}
		}

		$regularFile = CWPFile::ResizeImageGet(
			$file,
			array("width" => $size['WIDTH'], "height" => $size['HEIGHT']),
			$size['RESIZE'],
			true,
			$filters
		);
		if($size['RETINA']=="N"){
			$retinaFile = false;
		}else{
			$retinaFile = CWPFile::ResizeImageGet(
				$file,
				array("width" => ($size['WIDTH']*2), "height" => ($size['HEIGHT'])*2),
				$size['RESIZE'],
				true,
				$filters
			);
		}
	}else{
		$regularFile = CWPFile::ResizeImageGet(
			$file,
			array("width" => "500", "height" => "500"),
			BX_RESIZE_IMAGE_PROPORTIONAL,
			true
		);
		$retinaFile = CWPFile::ResizeImageGet(
			$file,
			array("width" => "1000", "height" => "1000"),
			BX_RESIZE_IMAGE_PROPORTIONAL,
			true
		);
	}

	$arRet = array(
		'regularFile' => $regularFile,
		'retinaFile' => $retinaFile,
	);

	if($size['DIMENSIONS'] == 'N'){
    	$arRet['dontSetDimensions'] = true;
    }

	return $arRet;
}

//Функция для вывода тега изображений. Остальные deprecated, используйте её.
function resizeImgTag($file, $sizeName, $htmlParams=array()){

	if (!is_array($file))
		$file = CFile::GetFileArray($file);

	$imgInfo = resizeImgInfo($file, $sizeName);
	$tagParams = array(
		'src' => $imgInfo['regularFile']['src']
	);
	//Если мы передаём дитейл или превью, для него уже есть альты и тайтлы
	if(array_key_exists('ALT', $file)){
		$tagParams['alt'] = $file['ALT'];
	}
	if(array_key_exists('TITLE', $file)){
		$tagParams['title'] = $file['TITLE'];
	}

	//Совмещаем сгенерированное и то, что передали. Теоретически можно всё сгенерированное переопределить.
	$tagParams = array_merge($tagParams, $htmlParams);

	if(!array_key_exists('alt',$tagParams)){
		//Ну и ай-яй. Невалидно без альта
		$tagParams['alt'] = ' ';
	}

	if($imgInfo['retinaFile']!==false){
		$tagParams['data-at2x'] = $imgInfo['retinaFile']['src'];
	}else{
		$tagParams['data-no-retina'] = "";
	}

	// Не устанавливать размеры JS-ом при замене на retina-изображение
	if($imgInfo['dontSetDimensions']){
		$tagParams['data-no-resize'] = "";
	}

	$strTagParams = '';
	foreach($tagParams as $key=>$item) {
		$strTagParams .= ' '.$key.'="'.$item.'"';
	}

	$htmlTag ='<img '.trim($strTagParams).'>';
	return $htmlTag;
}

//Функция для вывода только Src изображения.
function resizeImgSrc($file, $sizeName){
	$imgInfo = resizeImgInfo($file, $sizeName);
	return $imgInfo['regularFile']['src'];
}

/**
 * @param $sectionId
 * @param $arFilter
 * @param $arParams
 * @return array|bool
 * Возвращает ближайший родительский раздел, который не является псевдоразделом
 */
function getClosestNotPseudoSection($sectionId, $arFilter, $arParams){
	if($sectionId){
		$resInside = CIBlockSection::GetList(
			array(),
			array(
				'IBLOCK_ID' => $arParams['IBLOCK_ID'],
				'ID' => $sectionId,
				'ACTIVE' => 'Y',
				'!UF_PSEUDO_SECTION' => false
			),
			true,
			array(
				'ID',
				'IBLOCK_ID',
				'CODE',
				'IBLOCK_SECTION_ID',
				'UF_PSEUDO_SECTION'
			)
		);
		if($obInside = $resInside->GetNext()){
			$sectionValue = unserialize(htmlspecialchars_decode($obInside['UF_PSEUDO_SECTION']));
			if(count($sectionValue) > 0){
				if($sectionValue['is_pseudosection'] == 'Y'){
					$obCond = new CCCatalogCondTree();
					$obCond->Init(BT_COND_MODE_GENERATE, BT_COND_BUILD_CATALOG, array());
					$conditions = $obCond->Parse($sectionValue['rule']);
					$strEval = $obCond->Generate($conditions, array());
					$strEval = preg_replace('/([\"\'])\\1+/', '$1', $strEval);
					$arFilterInside = array();
					eval('$arFilterInside = '.$strEval);
					foreach($arFilterInside as $fKey => $arFElem){
						$arFilter[] = array(
							'PROP_ID' => preg_replace("/\D/", "", $fKey),
		                    'PROP_VALUE' => $arFElem
						);
					}
					$sectionId = $obInside['IBLOCK_SECTION_ID'];
					$functionReturn = getClosestNotPseudoSection($sectionId, $arFilter, $arParams);
					if($functionReturn){
						$sectionId = $functionReturn['SECTION_ID'];
						$arFilter = array_merge($arFilter, $functionReturn['FILTER']);
					}
					return array('SECTION_ID' => $sectionId, 'FILTER' => $arFilter);
				}
			}
		}
	}
	return false;
}


// Каноничный URL для ссылки.
// $element может принимать на вход ID элемента, массив элемента($arItem), массив элементов ($arResult['ITEMS'])
function getCanonicalLink($element, $detailPageTemplate = false){

	//Если у нас массив $arResult['ITEMS'], то эта переменная пригодится
	$elementsTable = array();
	$return = $element;
	$elementId = false;

	//Узнаём, что же у нас на входе
	if(is_int($element) || !is_array($element)){ // просто айди
		if(intval($element) > 0){
			$elementId = $element;
			$handler = 'id';
		}else{
			return $element;
		}
	}elseif(is_array($element)){ // массив одного элемента
		if(array_key_exists('ID', $element)){
			$elementId = intval($element['ID']);
			if($elementId > 0){
				$handler = 'item';
			}else{
				return $element;
			}
		}elseif(array_key_exists('ID', $element[key($element)])){ // массив $arResult['ITEMS']
			$handler = 'items';
			foreach($element as $key => $value){
				$elementId[] = $value['ID'];
				$elementsTable[$value['ID']] = $key;
			}
		}else{
			return $element;
		}
	}else{
		return $element;
	}

	//Массив для кэша URL инфоблока
	$cachedIblocks = array();
	$paramDetailPageTemplate = $detailPageTemplate;

	$dbRes = CIBlockElement::GetList(
		array("SORT" => "ASC"),
		$arFilter = array("ID" => $elementId),
		false,
		false,
		array(
			"CODE",
            "DETAIL_PAGE_URL",
            "PROPERTY_CANONICAL_SECTION",
            "IBLOCK_SECTION_ID"
		)
	);

	// Если указан каноничный раздел, то строим ссылку на основе него
	while($arRes = $dbRes->GetNext()){
		$detailPageUrl = $arRes['DETAIL_PAGE_URL'];

		//Если раздел деактивировали или удалили
		if($arRes["PROPERTY_CANONICAL_SECTION_VALUE"]){
			$dbSection = CIBlockSection::GetByID(intval($arRes["PROPERTY_CANONICAL_SECTION_VALUE"]));
			if($arSection = $dbSection->GetNext()){
				if($arSection['ACTIVE'] != 'Y'){
					$arRes["PROPERTY_CANONICAL_SECTION_VALUE"] = false;
				}
			}else{
				$arRes["PROPERTY_CANONICAL_SECTION_VALUE"] = false;
			}
		}

		//Если свойства CANONICAL_SECTION нет как такового — используем новый функционал "Основной раздел"
		if(!isset($arRes["PROPERTY_CANONICAL_SECTION_VALUE"])){
			$arRes["PROPERTY_CANONICAL_SECTION_VALUE"] = $arRes['IBLOCK_SECTION_ID'];
		}

		//Если раздела ещё нет, но свойство CANONICAL_SECTION вообще есть
		if(!$arRes["PROPERTY_CANONICAL_SECTION_VALUE"]){
			$arList = array();
			// Ищем самый глубокий из непсевдоразделов элемента и привязываем его
			$db_old_groups = CIBlockElement::GetElementGroups(
				intval($arRes['ID']),
				false,
				array(
					"ID",
					"IBLOCK_SECTION_ID",
					"IBLOCK_ID",
					"NAME",
					"DEPTH_LEVEL"
				)
			);
			while($ar_group = $db_old_groups->Fetch()){
				if($ar_group['ACTIVE'] != 'Y'){
					continue;
				}
				$arUF = $GLOBALS["USER_FIELD_MANAGER"]->GetUserFields("IBLOCK_".intval($ar_group["IBLOCK_ID"]).
					"_SECTION", $ar_group["ID"]);
				$UF_PS = $arUF["UF_PSEUDO_SECTION"]["VALUE"];
				if(strlen($UF_PS) > 0){
					$arUF_PS = unserialize($UF_PS);
					if($arUF_PS["is_pseudosection"] == "Y"){
						continue;
					}
				}
				$arList[$ar_group["ID"]] = array('ID' => $ar_group["ID"],
				                                 'PARENT' => intval($ar_group["IBLOCK_SECTION_ID"]),
				                                 'NAME' => $ar_group["NAME"],
				                                 'DEPTH_LEVEL' => $ar_group["DEPTH_LEVEL"]);
			}
			$sort_arr = array();
			foreach($arList as $uniqueId => $row){
				foreach($row as $key => $value){
					$sort_arr[$key][$uniqueId] = $value;
				}
			}
			array_multisort($sort_arr["DEPTH_LEVEL"], SORT_DESC, $arList);
			reset($arList);
			$arNewCanonical = $arList[key($arList)];
			CIBlockElement::SetPropertyValuesEx($arRes['ID'], $arRes['IBLOCK_ID'], array("CANONICAL_SECTION" => $arNewCanonical['ID']));
			$arRes["PROPERTY_CANONICAL_SECTION_VALUE"] = $arNewCanonical['ID'];
		}

		if($arRes["PROPERTY_CANONICAL_SECTION_VALUE"]){
			$arList = array();
			$dbParents = CIBlockSection::GetNavChain(false, intval($arRes["PROPERTY_CANONICAL_SECTION_VALUE"]));
			while($arParents = $dbParents->Fetch()){
				$arList[] = $arParents['CODE'];
			}
			$sectionPath = implode('/', $arList);

			$detailPageTemplate = $paramDetailPageTemplate;

			// Если не передан параметр шаблона DETAIL_PAGE_URL, то берём из настроек инфоблока
			if(!$detailPageTemplate){
				if(array_key_exists($arRes['IBLOCK_ID'], $cachedIblocks)){
					$detailPageTemplate = $cachedIblocks[$arRes['IBLOCK_ID']]['DETAIL_PAGE_URL'];
				}else{
					$rsIblocks = CIBlock::GetList(array('ID' => 'ASC'), array('=ID' => $arRes['IBLOCK_ID']));
					if($arIblocks = $rsIblocks->GetNext()){
						$detailPageTemplate = $arIblocks['DETAIL_PAGE_URL'];
						$cachedIblocks[$arRes['IBLOCK_ID']] = array('DETAIL_PAGE_URL' => $detailPageTemplate);
					}
				}
			}

			//Строим DETAIL_PAGE_URL с нуля
			$detailPageUrl = $detailPageTemplate;
			$detailPageUrl = str_replace('#SECTION_CODE_PATH#', $sectionPath, $detailPageUrl);//Меняем код пути до нужной секции
			$detailPageUrl = str_replace('#ELEMENT_CODE#', $arRes['CODE'], $detailPageUrl);//Меняем код товара
			$detailPageUrl = str_replace('#CODE#', $arRes['CODE'], $detailPageUrl);//Меняем код товара
			$detailPageUrl = str_replace('#ELEMENT_ID#', $arRes['ID'], $detailPageUrl);//Меняем код товара
			$detailPageUrl = str_replace('#SITE_DIR#', SITE_DIR, $detailPageUrl);//Меняем код товара
			$detailPageUrl = str_replace('//', '/', $detailPageUrl);//Меняем код товара
		}
		switch ($handler){
			case 'id':
				$return = $detailPageUrl;
				break;

			case 'item':
				$element['DETAIL_PAGE_URL'] = $detailPageUrl;
				$return = $element;
				break;

			case 'items':
				$key = $elementsTable[$arRes['ID']];
				$element[$key]['DETAIL_PAGE_URL'] = $detailPageUrl;
				$return = $element;
				break;
		}

	}

	return $return;
}


// Показывает время выполнения до текущего момента

function dumptime($text = ''){
	$time = microtime(true) - START_SCRIPT_TIME;
	dump(sprintf($text.' %.4F сек.', $time));
}

// Работает как GetMessage(), только принимает на вход количество товара
// Необходимы строки в файле языка PLURAL_СВОЙСТВО_ONE, PLURAL_СВОЙСТВО_TWO, PLURAL_СВОЙСТВО_FIVE
// Например:
// $MESS['PLURAL_ITEM_ONE'] = 'товар';
// $MESS['PLURAL_ITEM_TWO'] = 'товара';
// $MESS['PLURAL_ITEM_MANY'] = 'товаров';
function GetMessagePlural($cnt, $name, $aReplace = null){
	global $MESS;
	if(isset($MESS['PLURAL_'.$name.'_ONE']) && isset($MESS['PLURAL_'.$name.'_TWO']) &&
		isset($MESS['PLURAL_'.$name.'_MANY'])
	){
		$forms = array($MESS['PLURAL_'.$name.'_ONE'], $MESS['PLURAL_'.$name.'_TWO'], $MESS['PLURAL_'.$name.'_MANY']);
		$s = plural($cnt, $forms);
		if($aReplace !== null && is_array($aReplace)){
			foreach($aReplace as $search => $replace){
				$s = str_replace($search, $replace, $s);
			}
		}

		return $s;
	}

	return \Bitrix\Main\Localization\Loc::getMessage($name, $aReplace);
}


function getComponentTemplates($dir, $componentName, $vendor = "bitrix"){
	$templatesList = array(".default" => ".default");
	$templates = glob($dir."/".$vendor."/".$componentName."/*", GLOB_ONLYDIR);
	foreach($templates as $key => $value){
		$name = substr($value, strrpos($value, '/') + 1);
		$templatesList[$name] = $name;
	}
	$templates = CComponentUtil::GetTemplatesList($vendor.":".$componentName, $_GET["template_id"]);
	foreach($templates as $key => $value){
		if(isset($templatesList[$value['NAME']]) || $value['NAME'] == '.default'){
			continue;
		} // Those aren't available from here
		if($value['TEMPLATE'] == ""){
			$value['TEMPLATE'] = "__bitrix__";
		}
		$templatesList[$value['NAME']] = $value['NAME']." (".$value['TEMPLATE'].")";
	}

	return $templatesList;
}

function getCompareProperties($iblock_id){
	CModule::IncludeModule("iblock");
	global $arCompareExcludeProperties;
	$props = array();
	$res = CIBlock::GetProperties($iblock_id);
	while($r = $res->Fetch()){
		if(array_search($r["CODE"], $arCompareExcludeProperties) === false){
			$props[] = $r["CODE"];
		}
	}

	return $props;
}


//Подготавливаем свойства для фильтра псевдоразделов
if(!function_exists('preparePropsForPseudosectionFilter')){
	function preparePropsForPseudosectionFilter($arElement){

		//Приводим все значения к массиву
		foreach($arElement['PROPERTIES'] as $key => $value){
			// Для свойства список.
			if(is_array($value['VALUE_ENUM_ID'])){
				$arElement['PROPERTY_'.$value['ID'].'_VALUE'] = $value['VALUE_ENUM_ID'];
			}else{
				if(is_array($value['VALUE'])){
					$arElement['PROPERTY_'.$value['ID'].'_VALUE'] = $value['VALUE'];
				}else{
					if(isset($value['VALUE_ENUM_ID'])){
						$arElement['PROPERTY_'.$value['ID'].'_VALUE'] = array($value['VALUE_ENUM_ID']);
					}else{
						$arElement['PROPERTY_'.$value['ID'].'_VALUE'] = array($value['VALUE']);
					}
				}
			}
		}

		//Если какие-нибудь свойства потерялись
		foreach($arElement as $key => $value){
			if(
				mb_strpos($key, 'PROPERTY_') !== false
				&& mb_strpos($key, '_VALUE') === false
				&& !array_key_exists($key.'_VALUE', $arElement)
				&& mb_strpos($key, '~') !== 0
			){
				if(!is_array($value)){
					$arElement[$key.'_VALUE'] = array($value);
				}
			}
		}

		return $arElement;
	}
}


//Привязка к псевдоразделам по айди
if(!function_exists('setPseudoSectionsToElement')){
	function setPseudoSectionsToElement($element_id){
		if(CModule::IncludeModule("iblock") && CModule::IncludeModule("catalog")){

			$MODULE_ID = "webprofy.pseudosection";
			$IBLOCK_ID = COption::GetOptionString($MODULE_ID, "IBLOCK_ID");

			$addedToSection = array();

			$cacheDir = $_SERVER['DOCUMENT_ROOT'].'/upload/custom_cache/';
			$cacheFileIblock = $cacheDir.'custom_pseudosection_admin.php';

			$message = null;

			$main_section_id = null;

			if(!is_dir($cacheDir)){
				mkdir($cacheDir, 0777, true);
			}

			// основная часть
			$handle = fopen($cacheFileIblock, "r");
			$contents = fread($handle, filesize($cacheFileIblock));
			$arSections = json_decode($contents, true);
			fclose($handle);

			$arSelect = array("ID", "IBLOCK_ID", "PROPERTY_*"); //IBLOCK_ID и ID обязательно должны быть указаны
			$arFilter = array("IBLOCK_ID" => $IBLOCK_ID, "ID" => $element_id, "ACTIVE" => "Y");
			$rsElements = CIBlockElement::GetList(array('ID' => "ASC"), $arFilter, false, false, $arSelect);

			$IBLOCK_OFFER_ID = false;

			$mxResult = CCatalogSku::GetInfoByProductIBlock($IBLOCK_ID);
			if(is_array($mxResult)){
				$IBLOCK_OFFER_ID = $mxResult['IBLOCK_ID'];
			}
			if($obElement = $rsElements->GetNextElement()){
				$arElement = $obElement->GetFields();

				$arElement['PROPERTIES'] = $obElement->GetProperties();
				$arElement = preparePropsForPseudosectionFilter($arElement);

				$db_old_groups = CIBlockElement::GetElementGroups($arElement['ID'], true, array("ID"));
				$ar_new_groups = array();
				$ar_old_groups = array();
				while($ar_group = $db_old_groups->Fetch()){
					if(!array_key_exists($ar_group["ID"], $arSections)){
						$ar_old_groups[] = $ar_group["ID"];
					}
				}
				$ar_unchanged_groups = $ar_old_groups;

				foreach($ar_old_groups as $key => $group){
					$nav = CIBlockSection::GetNavChain($IBLOCK_ID, $group);
					while($arSectionPath = $nav->GetNext()){
						$ar_old_groups[] = $arSectionPath['ID'];
					}
				}
				$ar_old_groups = array_unique($ar_old_groups);
				if($IBLOCK_OFFER_ID){
					$arElementClear = $arElement;
					$rsOffers = CIBlockElement::GetList(
						array(),
						array(
							'IBLOCK_ID' => $IBLOCK_OFFER_ID,
							'PROPERTY_CML2_LINK' => $arElement['ID'],
							"ACTIVE" => "Y"
						),
						false,
						false,
						array("ID", "IBLOCK_ID", "PROPERTY_*")
					);
					while($obOffer = $rsOffers->GetNextElement()){
						$arNewElement = $arElementClear;
						$arNewElement['PROPERTIES'] = $obOffer->GetProperties();
						$arNewElement = preparePropsForPseudosectionFilter($arNewElement);

						$arElement = array_merge($arElementClear, $arNewElement);

						ksort($arSections);

						foreach($arSections as $arSection){
							if(mb_strlen($arSection['EVAL_FILTER']) > 0){
								if(
									eval('return('.$arSection['EVAL_FILTER'].');')
									&& (
										($arSection['DISCARD_PARENT_GROUP'] == "N" &&
											array_search($arSection['SECTION_ID'], $ar_old_groups) !== false)
										|| $arSection['DISCARD_PARENT_GROUP'] == "Y"
									)
								){
									if($arSection['DISCARD_PARENT_GROUP'] == "Y"){
										$ar_old_groups[] = $arSection['ID'];
									}
									if(array_search($arSection['ID'], $ar_new_groups) === false){
										$addedToSection[] = $arElement['ID'];
										$ar_new_groups[] = $arSection['ID'];
										if(!$main_section_id){
											$main_section_id = $arSection['ID'];
										}
									}
								}
							}
						}
					}
					$ar_new_groups = array_keys(array_flip(array_merge($ar_new_groups, $ar_old_groups)));
				}
				ksort($arSections);
				foreach($arSections as $arSection){

					if(mb_strlen($arSection['EVAL_FILTER']) > 0){
						if(
							eval('return('.$arSection['EVAL_FILTER'].');')
							&& (
								($arSection['DISCARD_PARENT_GROUP'] == "N" &&
									array_search($arSection['SECTION_ID'], $ar_old_groups) !== false)
								|| $arSection['DISCARD_PARENT_GROUP'] == "Y"
							)
						){
							if($arSection['DISCARD_PARENT_GROUP'] == "Y"){
								$ar_old_groups[] = $arSection['ID'];
							}
							if((array_search($arSection['ID'], $ar_new_groups)) === false){
								$addedToSection[] = $arElement['ID'];
								$ar_new_groups[] = $arSection['ID'];
								if(!$main_section_id){
									$main_section_id = $arSection['ID'];
								}
							}
						}
					}
				}

				$ar_new_groups = array_keys(array_flip(array_merge($ar_new_groups, $ar_unchanged_groups)));

				if($ar_unchanged_groups != $ar_new_groups){
					CIBlockElement::SetElementSection($arElement['ID'], $ar_new_groups);
				}
			}
		}
	}
}

/**
 * @param $url
 * @return bool
 * Парсит урл видео с YouTube и возвращает id
 */
function parseYouTubeUrl($url)
{
	$pattern = '#^(?:https?://)?(?:www\.)?(?:m\.)?(?:youtu\.be/|youtube\.com(?:/embed/|/v/|/watch\?v=|/watch\?.+&v=))([\w-]{11})(?:.+)?$#x';
	preg_match($pattern, $url, $matches);
	return (isset($matches[1])) ? $matches[1] : false;
}

/**
 * @param $lang
 * @param $date
 * @return string
 * Возвращает дату в строковом представлении: N дней, месяцев, часов, минут + назад
 */
function wpFormatDate($date, $lang = 'ru'){
	$date = strtotime($date);
	$cur_time = time();
	$no = $diff = $cur_time - $date;

	if($lang == 'en'){
		$seconds = array(
			'second',
			'second',
			'seconds'
		);
		$minutes = array(
			'minute',
			'minute',
			'minutes'
		);
		$hours = array(
			'hour',
			'hour',
			'hours'
		);
		$days = array(
			'day',
			'day',
			'days'
		);
		$weeks = array(
			'week',
			'week',
			'weeks'
		);
		$months = array(
			'month',
			'month',
			'months'
		);
		$years = array(
			'year',
			'year',
			'years'
		);
		$decades = array(
			'decade',
			'decade',
			'decades'
		);
	}else{
		$seconds = array(
			'секунда',
			'секунды',
			'секунд'
		);
		$minutes = array(
			'минута',
			'минуты',
			'минут'
		);
		$hours = array(
			'час',
			'часа',
			'часов'
		);
		$days = array(
			'день',
			'дня',
			'дней'
		);
		$weeks = array(
			'неделя',
			'недели',
			'недель'
		);
		$months = array(
			'месяц',
			'месяца',
			'месяцев'
		);
		$years = array(
			'год',
			'года',
			'лет'
		);
		$decades = array(
			'десятилетие',
			'десятилетия',
			'десятилетий'
		);
	}


	$phrase = array(
		$seconds,
		$minutes,
		$hours,
		$days,
		$weeks,
		$months,
		$years,
		$decades
	);
	$length = array(
		1,
		60,
		3600,
		86400,
		604800,
		2630880,
		31570560,
		315705600
	);

	for($i = sizeof($length) - 1; ($i >= 0) && (($no = $diff / $length[$i]) <= 1); $i--){
		;
	}
	if($i < 0){
		$i = 0;
	}

	$no = floor($no);
	$value = sprintf("%d %s ", $no, plural($no, $phrase[$i]));

	if($lang == 'en'){
		return $value.' ago';
	}else{
		return $value.' назад';
	}
}


/**
 * Возвращает отформатированный текст строки для выбранной валюты без вывода самой цены.
 * @param string $currency
 * @return string
 */
function formatCurrencyString($currency){
	$formatDescription = CCurrencyLang::GetFormatDescription($currency);
	return preg_replace('/(^|[^&])#/', '', $formatDescription['FORMAT_STRING']);
}


/**
 * Замена функции CUtil::translit. Полная её копия с использованием мультибайтовых строковых функций.
 * @param string $str
 * @param string $lang
 * @param array $params
 * @return string
 */
function translit($str, $lang, $params = array()){
	static $search = array();

	if(!isset($search[$lang])){
		$mess = IncludeModuleLangFile($_SERVER["DOCUMENT_ROOT"]."/bitrix/modules/main/js_core_translit.php", $lang, true);
		$trans_from = explode(",", $mess["TRANS_FROM"]);
		$trans_to = explode(",", $mess["TRANS_TO"]);
		foreach($trans_from as $i => $from){
			$search[$lang][$from] = $trans_to[$i];
		}
	}

	$defaultParams = array(
		"max_len" => 100,
		"change_case" => 'L', // 'L' - toLower, 'U' - toUpper, false - do not change
		"replace_space" => '_',
		"replace_other" => '_',
		"delete_repeat_replace" => true,
		"safe_chars" => '',
	);
	foreach($defaultParams as $key => $value){
		if(!array_key_exists($key, $params)){
			$params[$key] = $value;
		}
	}

	$len = mb_strlen($str);
	$str_new = '';
	$last_chr_new = '';

	for($i = 0; $i < $len; $i++){
		$chr = mb_substr($str, $i, 1);

		if(preg_match("/[a-zA-Z0-9]/".BX_UTF_PCRE_MODIFIER, $chr) || strpos($params["safe_chars"], $chr) !== false){
			$chr_new = $chr;
		}elseif(preg_match("/\\s/".BX_UTF_PCRE_MODIFIER, $chr)){
			if(
				!$params["delete_repeat_replace"]
				||
				($i > 0 && $last_chr_new != $params["replace_space"])
			){
				$chr_new = $params["replace_space"];
			}else{
				$chr_new = '';
			}
		}else{
			if(array_key_exists($chr, $search[$lang])){
				$chr_new = $search[$lang][$chr];
			}else{
				if(
					!$params["delete_repeat_replace"]
					||
					($i > 0 && $i != $len - 1 && $last_chr_new != $params["replace_other"])
				){
					$chr_new = $params["replace_other"];
				}else{
					$chr_new = '';
				}
			}
		}

		if(strlen($chr_new)){
			if($params["change_case"] == "L" || $params["change_case"] == "l"){
				$chr_new = mbToLower($chr_new);
			}elseif($params["change_case"] == "U" || $params["change_case"] == "u"){
				$chr_new = mbToUpper($chr_new);
			}

			$str_new .= $chr_new;
			$last_chr_new = $chr_new;
		}

		if(mb_strlen($str_new) >= $params["max_len"]){
			break;
		}
	}

	return $str_new;
}

/**
 * Замена функции ToUpper. Полная её копия с использованием мультибайтовых строковых функций.
 * @param $str
 * @param bool $lang
 * @return string
 */
function mbToUpper($str, $lang = false){
	static $lower = array();
	static $upper = array();
	if(!defined("BX_CUSTOM_TO_UPPER_FUNC")){
		if(defined("BX_UTF")){
			return mb_strtoupper($str);
		}else{
			if($lang === false){
				$lang = LANGUAGE_ID;
			}
			if(!isset($lower[$lang])){
				$arMsg = IncludeModuleLangFile(__FILE__, $lang, true);
				$lower[$lang] = $arMsg["ABC_LOWER"];
				$upper[$lang] = $arMsg["ABC_UPPER"];
			}
			return mb_strtoupper(strtr($str, $lower[$lang], $upper[$lang]));
		}
	}else{
		$func = BX_CUSTOM_TO_UPPER_FUNC;
		return $func($str);
	}
}

/**
 * Замена функции ToLower. Полная её копия с использованием мультибайтовых строковых функций.
 * @param $str
 * @param bool $lang
 * @return string
 */
function mbToLower($str, $lang = false){
	static $lower = array();
	static $upper = array();
	if(!defined("BX_CUSTOM_TO_LOWER_FUNC")){
		if(defined("BX_UTF")){
			return mb_strtolower($str);
		}else{
			if($lang === false){
				$lang = LANGUAGE_ID;
			}
			if(!isset($lower[$lang])){
				$arMsg = IncludeModuleLangFile(__FILE__, $lang, true);
				$lower[$lang] = $arMsg["ABC_LOWER"];
				$upper[$lang] = $arMsg["ABC_UPPER"];
			}
			return mb_strtolower(strtr($str, $upper[$lang], $lower[$lang]));
		}
	}else{
		$func = BX_CUSTOM_TO_LOWER_FUNC;
		return $func($str);
	}
}


function wp_get_script_url(){
	$script_url = NULL;

	if(!empty($_SERVER['SCRIPT_URL'])) {
		$script_url = $_SERVER['SCRIPT_URL'];
	} elseif(!empty($_SERVER['REDIRECT_URL'])) {
		$script_url = $_SERVER['REDIRECT_URL'];
	} elseif(!empty($_SERVER['REQUEST_URI'])) {
		$p = parse_url($_SERVER['REQUEST_URI']);
		$script_url = $p['path'];
	}

	return $script_url;
}

function IncludeGlobalLangFile(){
	global $MESS;
	$langPath = $_SERVER['DOCUMENT_ROOT'] . SITE_TEMPLATE_PATH . '/lang/' . LANGUAGE_ID . '/main.php';
	if(!file_exists($langPath)){
		$langPath = $_SERVER['DOCUMENT_ROOT'] .'/.default/lang/' . LANGUAGE_ID . '/main.php';
	}
	if(file_exists($langPath)){
		include $langPath;
	}
}

/**
 * Добавляет переменные из языкового файла для использования в js через BX.Message();
 * @param string $lang путь к языковому файлу
 * @param bool $bReturn возвращать результат или нет
 * @param mixed $arAdditionalMess массив дополнительных языковых переменных
 * @return string
 *
 * Для использования языковых файлов в js шаблона компонента необходимо в компонент эпилоге выполнить функцию
 * loadJsLanguageFile(__FILE__);
 */
function loadJsLanguageFile($lang, $bReturn = false, $arAdditionalMess = false){

	$jsMsg = '';

	if($lang){
		$lang_filename = $_SERVER['DOCUMENT_ROOT'].str_replace("/lang/".LANGUAGE_ID."/", "/", $lang);
		$mess_lang = \Bitrix\Main\Localization\Loc::loadLanguageFile($lang_filename);

		if(!empty($mess_lang)){
			$jsMsg = '(window.BX||top.BX).message('.CUtil::PhpToJSObject($mess_lang, false).');';
		}
	}

	if(is_array($arAdditionalMess)){
		$jsMsg = '(window.BX||top.BX).message('.CUtil::PhpToJSObject($arAdditionalMess, false).');'.$jsMsg;
	}

	if($jsMsg !== ''){
		$jsMsg = '<script type="text/javascript">'.$jsMsg.'</script>';
		if($bReturn){
			return $jsMsg."\r\n";
		}else{
			\Bitrix\Main\Page\Asset::getInstance()->addString($jsMsg, true, 'AFTER_CSS');
		}
	}

	return $jsMsg;
}

function gaParseCookie() {
	$cid ='';
	if (isset($_COOKIE['_ga'])) {
		list($version,$domainDepth, $cid1, $cid2) = preg_split('[\.]', $_COOKIE["_ga"],4);
		$contents = array('version' => $version, 'domainDepth' => $domainDepth, 'cid' => $cid1.'.'.$cid2);
		$cid = $contents['cid'];
	}
	return $cid;
}

function debugf($mess, $label = '', $file = false){
	if(!$file){
		$file = $_SERVER['DOCUMENT_ROOT'] . '/debug.log';
	}
	$message = print_r($mess, true);
	error_log('' . $label."\n".$message.'' . "\n", 3, $file);
}

/**
 * @param $code
 * @return int|bool
 * Возвращает ID инфоблока по его коду или false
 */
if(!function_exists('getIblockIdByCode')) {
    function getIblockIdByCode($code) {
        if (CModule::IncludeModule("iblock") && isset($code) && !empty($code)) {
            $res = CIBlock::GetList(array(), array("CODE" => $code), false);
            if ($ar_res = $res->Fetch()) {
                return $ar_res['ID'];
            }
        }

        return false;
    }
}

function getManualItem(){
    $result = [];
    $items = CIBlockElement::GetList([],
        [
            'ACTIVE'=>'Y',
            'IBLOCK_ID' => CATALOG_IBLOCK_ID,
            '!PROPERTY_' . PROPERTY_MANUAL_FILE_CODE => false
        ],
        false,
        false,
        ['ID','IBLOCK_ID']);
    while($item = $items->GetNext()){
        $result[] = $item['ID'];
    }
    return $result;
}