Your IP : 3.15.145.156


Current Path : /var/www/www-root/data/www.catalog.monolith-realty.ru/bitrix/modules/main/lib/
Upload File :
Current File : /var/www/www-root/data/www.catalog.monolith-realty.ru/bitrix/modules/main/lib/urlrewriter.php

<?php
namespace Bitrix\Main;

use Bitrix\Main\Component;
use Bitrix\Main\Config;
use Bitrix\Main\IO;

class UrlRewriter
{
	const DEFAULT_SORT = 100;

	protected static function loadRules($siteId)
	{
		$site = SiteTable::getRow(array("filter" => array("=LID" => $siteId), "cache" => array("ttl" => 3600)));
		$docRoot = $site["DOC_ROOT"];

		if (!empty($docRoot))
			$docRoot = IO\Path::normalize($docRoot);
		else
			$docRoot = Application::getDocumentRoot();

		$arUrlRewrite = array();

		if (IO\File::isFileExists($docRoot."/urlrewrite.php"))
			include($docRoot."/urlrewrite.php");

		foreach ($arUrlRewrite as &$rule)
		{
			if (!isset($rule["SORT"]))
				$rule["SORT"] = self::DEFAULT_SORT;
		}

		return $arUrlRewrite;
	}

	protected static function saveRules($siteId, array $arUrlRewrite)
	{
		$site = SiteTable::getRow(array("filter" => array("=LID" => $siteId), "cache" => array("ttl" => 3600)));
		$docRoot = $site["DOC_ROOT"];

		if (!empty($docRoot))
			$docRoot = IO\Path::normalize($docRoot);
		else
			$docRoot = Application::getDocumentRoot();

		$data = var_export($arUrlRewrite, true);

		$event = new Event("main", "onUrlRewriteSaveRules", [
			$siteId,
			$docRoot,
			$arUrlRewrite
		]);
		$event->send();

		$filename = $docRoot . "/urlrewrite.php";
		IO\File::putFileContents($filename, "<"."?php\n\$arUrlRewrite=".$data.";\n");
		Application::resetAccelerator($filename);
	}

	public static function getList($siteId, $arFilter = array(), $arOrder = array())
	{
		if (empty($siteId))
			throw new ArgumentNullException("siteId");

		$arUrlRewrite = static::loadRules($siteId);

		$arResult = array();
		$arResultKeys = self::filterRules($arUrlRewrite, $arFilter);
		foreach ($arResultKeys as $key)
			$arResult[] = $arUrlRewrite[$key];

		if (!empty($arOrder) && !empty($arResult))
		{
			$arOrderKeys = array_keys($arOrder);
			$orderBy = array_shift($arOrderKeys);
			$orderDir = $arOrder[$orderBy];

			$orderBy = mb_strtoupper($orderBy);
			$orderDir = mb_strtoupper($orderDir);

			$orderDir = (($orderDir == "DESC") ? SORT_DESC : SORT_ASC);

			$ar = array();
			foreach ($arResult as $key => $row)
				$ar[$key] = $row[$orderBy];

			array_multisort($ar, $orderDir, $arResult);
		}

		return $arResult;
	}

	protected static function filterRules(array $arUrlRewrite, array $arFilter)
	{
		$arResultKeys = array();

		foreach ($arUrlRewrite as $keyRule => $arRule)
		{
			$isMatched = true;
			foreach ($arFilter as $keyFilter => $valueFilter)
			{
				$isNegative = false;
				if (mb_substr($keyFilter, 0, 1) === "!")
				{
					$isNegative = true;
					$keyFilter = mb_substr($keyFilter, 1);
				}

				if ($keyFilter === 'QUERY')
					$isMatchedTmp = preg_match($arRule["CONDITION"], $valueFilter);
				elseif ($keyFilter === 'CONDITION')
					$isMatchedTmp = ($arRule["CONDITION"] == $valueFilter);
				elseif ($keyFilter === 'ID')
					$isMatchedTmp = (isset($arRule["ID"]) && ($arRule["ID"] == $valueFilter));
				elseif ($keyFilter === 'PATH')
					$isMatchedTmp = ($arRule["PATH"] == $valueFilter);
				else
					throw new ArgumentException("arFilter");

				$isMatched = ($isNegative xor $isMatchedTmp);

				if (!$isMatched)
					break;
			}

			if ($isMatched)
				$arResultKeys[] = $keyRule;
		}

		return $arResultKeys;
	}

	protected static function recordsCompare($a, $b)
	{
		$sortA = isset($a["SORT"]) ? intval($a["SORT"]) : self::DEFAULT_SORT;
		$sortB = isset($b["SORT"]) ? intval($b["SORT"]) : self::DEFAULT_SORT;

		if ($sortA > $sortB)
			return 1;
		elseif ($sortA < $sortB)
			return -1;

		$lenA = mb_strlen($a["CONDITION"]);
		$lenB = mb_strlen($b["CONDITION"]);
		if ($lenA < $lenB)
			return 1;
		elseif ($lenA > $lenB)
			return -1;
		else
			return 0;
	}

	public static function add($siteId, $arFields)
	{
		if (empty($siteId))
			throw new ArgumentNullException("siteId");

		$arUrlRewrite = static::loadRules($siteId);

		// if rule is exist � return
		foreach ($arUrlRewrite as $rule)
		{
			if ($arFields["CONDITION"] == $rule["CONDITION"])
			{
				return;
			}
		}

		$arUrlRewrite[] = array(
			"CONDITION" => $arFields["CONDITION"],
			"RULE" => $arFields["RULE"],
			"ID" => $arFields["ID"],
			"PATH" => $arFields["PATH"],
			"SORT" => isset($arFields["SORT"]) ? intval($arFields["SORT"]) : self::DEFAULT_SORT,
		);

		uasort($arUrlRewrite, array('\Bitrix\Main\UrlRewriter', "recordsCompare"));

		static::saveRules($siteId, $arUrlRewrite);
	}

	public static function update($siteId, $arFilter, $arFields)
	{
		if (empty($siteId))
			throw new ArgumentNullException("siteId");

		$arUrlRewrite = static::loadRules($siteId);

		$arResultKeys = self::filterRules($arUrlRewrite, $arFilter);
		foreach ($arResultKeys as $key)
		{
			if (array_key_exists("CONDITION", $arFields))
				$arUrlRewrite[$key]["CONDITION"] = $arFields["CONDITION"];
			if (array_key_exists("RULE", $arFields))
				$arUrlRewrite[$key]["RULE"] = $arFields["RULE"];
			if (array_key_exists("ID", $arFields))
				$arUrlRewrite[$key]["ID"] = $arFields["ID"];
			if (array_key_exists("PATH", $arFields))
				$arUrlRewrite[$key]["PATH"] = $arFields["PATH"];
			if (array_key_exists("SORT", $arFields))
				$arUrlRewrite[$key]["SORT"] = intval($arFields["SORT"]);
		}

		uasort($arUrlRewrite, array('\Bitrix\Main\UrlRewriter', "recordsCompare"));

		static::saveRules($siteId, $arUrlRewrite);
	}

	public static function delete($siteId, $arFilter)
	{
		if (empty($siteId))
			throw new ArgumentNullException("siteId");

		$arUrlRewrite = static::loadRules($siteId);

		$arResultKeys = self::filterRules($arUrlRewrite, $arFilter);
		foreach ($arResultKeys as $key)
			unset($arUrlRewrite[$key]);

		uasort($arUrlRewrite, array('\Bitrix\Main\UrlRewriter', "recordsCompare"));

		static::saveRules($siteId, $arUrlRewrite);
	}

	public static function reindexAll($maxExecutionTime = 0, $ns = array())
	{
		@set_time_limit(0);
		if (!is_array($ns))
			$ns = array();

		if ($maxExecutionTime <= 0)
		{
			$nsOld = $ns;
			$ns = array(
				"CLEAR" => "N",
				"ID" => "",
				"FLG" => "",
				"SESS_ID" => md5(uniqid("")),
				"max_execution_time" => $nsOld["max_execution_time"],
				"stepped" => $nsOld["stepped"],
				"max_file_size" => $nsOld["max_file_size"]
			);

			if (!empty($nsOld["SITE_ID"]))
				$ns["SITE_ID"] = $nsOld["SITE_ID"];
		}
		$ns["CNT"] = intval($ns["CNT"] ?? 0);

		$arSites = array();
		$filterRootPath = "";

		$db = SiteTable::getList(
			array(
				"select" => array("LID", "DOC_ROOT", "DIR"),
				"filter" => array("=ACTIVE" => "Y"),
			)
		);
		while ($ar = $db->fetch())
		{
			if (empty($ar["DOC_ROOT"]))
				$ar["DOC_ROOT"] = Application::getDocumentRoot();

			$arSites[] = array(
				"site_id" => $ar["LID"],
				"root" => $ar["DOC_ROOT"],
				"path" => IO\Path::combine($ar["DOC_ROOT"], $ar["DIR"])
			);

			if (!empty($ns["SITE_ID"]) && $ns["SITE_ID"] == $ar["LID"])
				$filterRootPath = $ar["DOC_ROOT"];
		}

		if (!empty($ns["SITE_ID"]) && !empty($filterRootPath))
		{
			$arSitesTmp = array();
			$arKeys = array_keys($arSites);
			foreach ($arKeys as $key)
			{
				if ($arSites[$key]["root"] == $filterRootPath)
					$arSitesTmp[] = $arSites[$key];
			}
			$arSites = $arSitesTmp;
		}

		uasort($arSites,
			function($a, $b)
			{
				$la = mb_strlen($a["path"]);
				$lb = mb_strlen($b["path"]);
				if ($la == $lb)
				{
					if ($a["site_id"] == $b["site_id"])
						return 0;
					else
						return ($a["site_id"] > $b["site_id"]) ? -1 : 1;
				}
				return ($la > $lb) ? -1 : 1;
			}
		);

		if ($ns["CLEAR"] != "Y")
		{
			$arAlreadyDeleted = array();
			foreach ($arSites as $site)
			{
				Component\ParametersTable::deleteBySiteId($site["site_id"]);
				if (!in_array($site["root"], $arAlreadyDeleted))
				{
					static::delete(
						$site["site_id"],
						array("!ID" => "")
					);
					$arAlreadyDeleted[] = $site["root"];
				}
			}
		}
		$ns["CLEAR"] = "Y";

		clearstatcache();

		$arAlreadyParsed = array();
		foreach ($arSites as $site)
		{
			if (in_array($site["root"], $arAlreadyParsed))
				continue;
			$arAlreadyParsed[] = $site["root"];

			if ($maxExecutionTime > 0 && !empty($ns["FLG"])
				&& mb_substr($ns["ID"]."/", 0, mb_strlen($site["root"]."/")) != $site["root"]."/")
			{
				continue;
			}

			static::recursiveReindex($site["root"], "/", $arSites, $maxExecutionTime, $ns);

			if ($maxExecutionTime > 0 && !empty($ns["FLG"]))
				return $ns;
		}

		return $ns["CNT"];
	}

	protected static function recursiveReindex($rootPath, $path, $arSites, $maxExecutionTime, &$ns)
	{
		$pathAbs = IO\Path::combine($rootPath, $path);

		$siteId = "";
		foreach ($arSites as $site)
		{
			if (mb_substr($pathAbs."/", 0, mb_strlen($site["path"]."/")) == $site["path"]."/")
			{
				$siteId = $site["site_id"];
				break;
			}
		}
		if (empty($siteId))
			return 0;

		$dir = new IO\Directory($pathAbs, $siteId);
		if (!$dir->isExists())
			return 0;

		$arChildren = $dir->getChildren();
		foreach ($arChildren as $child)
		{
			if ($child->isDirectory())
			{
				if ($child->isSystem())
					continue;

				//this is not first step and we had stopped here, so go on to reindex
				if ($maxExecutionTime <= 0
					|| $ns["FLG"] == ''
					|| mb_substr($ns["ID"]."/", 0, mb_strlen($child->getPath()."/")) == $child->getPath()."/"
				)
				{
					if (static::recursiveReindex($rootPath, mb_substr($child->getPath(), mb_strlen($rootPath)), $arSites, $maxExecutionTime, $ns) === false)
						return false;
				}
				else //all done
				{
					continue;
				}
			}
			else
			{
				//not the first step and we found last file from previos one
				if ($maxExecutionTime > 0 && $ns["FLG"] <> ''
					&& $ns["ID"] == $child->getPath())
				{
					$ns["FLG"] = "";
				}
				elseif (empty($ns["FLG"]))
				{
					$ID = static::reindexFile($siteId, $rootPath, mb_substr($child->getPath(), mb_strlen($rootPath)), $ns["max_file_size"]);
					if ($ID)
						$ns["CNT"] = intval($ns["CNT"]) + 1;
				}

				if ($maxExecutionTime > 0
					&& (microtime(true) - START_EXEC_TIME > $maxExecutionTime))
				{
					$ns["FLG"] = "Y";
					$ns["ID"] = $child->getPath();
					return false;
				}
			}
		}
		return true;
	}

	public static function reindexFile($siteId, $rootPath, $path, $maxFileSize = 0)
	{
		$pathAbs = IO\Path::combine($rootPath, $path);

		if (!static::checkPath($pathAbs))
			return 0;

		$file = new IO\File($pathAbs);
		if ($maxFileSize > 0 && $file->getSize() > $maxFileSize * 1024)
			return 0;

		$fileSrc = $file->getContents();

		if (!$fileSrc || $fileSrc == "")
			return 0;

		$arComponents = \PHPParser::parseScript($fileSrc);

		for ($i = 0, $cnt = count($arComponents); $i < $cnt; $i++)
		{
			$sef = (is_array($arComponents[$i]["DATA"]["PARAMS"]) && $arComponents[$i]["DATA"]["PARAMS"]["SEF_MODE"] == "Y");

			Component\ParametersTable::add(
				array(
					'SITE_ID' => $siteId,
					'COMPONENT_NAME' => $arComponents[$i]["DATA"]["COMPONENT_NAME"],
					'TEMPLATE_NAME' => $arComponents[$i]["DATA"]["TEMPLATE_NAME"],
					'REAL_PATH' => $path,
					'SEF_MODE' => ($sef? Component\ParametersTable::SEF_MODE : Component\ParametersTable::NOT_SEF_MODE),
					'SEF_FOLDER' => ($sef? $arComponents[$i]["DATA"]["PARAMS"]["SEF_FOLDER"] : null),
					'START_CHAR' => $arComponents[$i]["START"],
					'END_CHAR' => $arComponents[$i]["END"],
					'PARAMETERS' => serialize($arComponents[$i]["DATA"]["PARAMS"]),
				)
			);

			if ($sef)
			{
				if (array_key_exists("SEF_RULE", $arComponents[$i]["DATA"]["PARAMS"]))
				{
					$ruleMaker = new UrlRewriterRuleMaker;
					$ruleMaker->process($arComponents[$i]["DATA"]["PARAMS"]["SEF_RULE"]);

					$arFields = array(
						"CONDITION" => $ruleMaker->getCondition(),
						"RULE" => $ruleMaker->getRule(),
						"ID" => $arComponents[$i]["DATA"]["COMPONENT_NAME"],
						"PATH" => $path,
						"SORT" => self::DEFAULT_SORT,
					);
				}
				else
				{
					$arFields = array(
						"CONDITION" => "#^".$arComponents[$i]["DATA"]["PARAMS"]["SEF_FOLDER"]."#",
						"RULE" => "",
						"ID" => $arComponents[$i]["DATA"]["COMPONENT_NAME"],
						"PATH" => $path,
						"SORT" => self::DEFAULT_SORT,
					);
				}

				static::add($siteId, $arFields);
			}
		}

		return true;
	}

	public static function checkPath($path)
	{
		static $searchMasksCache = false;
		if (is_array($searchMasksCache))
		{
			$arExc = $searchMasksCache["exc"];
			$arInc = $searchMasksCache["inc"];
		}
		else
		{
			$arExc = array();
			$arInc = array();

			$inc = Config\Option::get("main", "urlrewrite_include_mask", "*.php");
			$inc = str_replace("'", "\\'", str_replace("*", ".*?", str_replace("?", ".", str_replace(".", "\\.", str_replace("\\", "/", $inc)))));
			$arIncTmp = explode(";", $inc);
			foreach ($arIncTmp as $preg_mask)
				if (trim($preg_mask) <> '')
					$arInc[] = "'^".trim($preg_mask)."$'";

			$exc = Config\Option::get("main", "urlrewrite_exclude_mask", "/bitrix/*;");
			$exc = str_replace("'", "\\'", str_replace("*", ".*?", str_replace("?", ".", str_replace(".", "\\.", str_replace("\\", "/", $exc)))));
			$arExcTmp = explode(";", $exc);
			foreach ($arExcTmp as $preg_mask)
				if (trim($preg_mask) <> '')
					$arExc[] = "'^".trim($preg_mask)."$'";

			$searchMasksCache = array("exc" => $arExc, "inc" => $arInc);
		}

		$file = IO\Path::getName($path);
		if (mb_substr($file, 0, 1) === ".")
			return 0;

		foreach ($arExc as $preg_mask)
			if (preg_match($preg_mask, $path))
				return false;

		foreach ($arInc as $preg_mask)
			if (preg_match($preg_mask, $path))
				return true;

		return false;
	}
}

/**
 * Class UrlRewriterRuleMaker
 *
 * Helper used for sef rules creation.
 *
 * @package Bitrix\Main
 */
class UrlRewriterRuleMaker
{
	protected $condition = "";
	protected $variables = array();
	protected $rule = "";

	/**
	 * @param string $sefRule SEF_RULE component parameter value.
	 *
	 * @return void
	 */
	public function process($sefRule)
	{
		$this->rule = "";
		$this->variables = array();
		$this->condition = "#^".preg_replace_callback("/(#[a-zA-Z0-9_]+#)/", array($this, "_callback"), $sefRule)."\\??(.*)#";
		$i = 0;
		foreach ($this->variables as $variableName)
		{
			$i++;
			if ($this->rule)
				$this->rule .= "&";
			$this->rule .= $variableName."=\$".$i;
		}
		$i++;
		$this->rule .= "&\$".$i;
	}

	/**
	 * Returns CONDITION field of the sef rule based on what was processed.
	 *
	 * @return string
	 */
	public function getCondition()
	{
		return $this->condition;
	}

	/**
	 * Returns RULE field of the sef rule based on what was processed.
	 *
	 * @return string
	 */
	public function getRule()
	{
		return $this->rule;
	}

	/**
	 * Internal method used for preg_replace processing.
	 *
	 * @param array $match match array.
	 *
	 * @return string
	 */
	protected function _callback(array $match)
	{
		$this->variables[] = trim($match[0], "#");
		if (mb_substr($match[0], -6) == "_PATH#")
		{
			return "(.+?)";
		}
		else
		{
			return "([^/]+?)";
		}
	}
}