Current Path : /home/bitrix/vorobey-clubru/bitrix/modules/main/lib/ |
Current File : /home/bitrix/vorobey-clubru/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; private static function loadRules($siteId) { $site = SiteTable::getRow(array("filter" => array("LID" => $siteId))); $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; } private static function saveRules($siteId, array $arUrlRewrite) { $site = SiteTable::getRow(array("filter" => array("LID" => $siteId))); $docRoot = $site["DOC_ROOT"]; if (!empty($docRoot)) $docRoot = IO\Path::normalize($docRoot); else $docRoot = Application::getDocumentRoot(); $data = var_export($arUrlRewrite, true); IO\File::putFileContents($docRoot."/urlrewrite.php", "<"."?php\n\$arUrlRewrite=".$data.";\n"); Application::resetAccelerator(); } 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 = strtoupper($orderBy); $orderDir = 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; } private static function filterRules(array $arUrlRewrite, array $arFilter) { $arResultKeys = array(); foreach ($arUrlRewrite as $keyRule => $arRule) { $isMatched = true; foreach ($arFilter as $keyFilter => $valueFilter) { $isNegative = false; if (substr($keyFilter, 0, 1) == "!") { $isNegative = true; $keyFilter = substr($keyFilter, 1); } if ($keyFilter == 'QUERY') $isMatchedTmp = preg_match($arRule["CONDITION"], $valueFilter); elseif ($keyFilter == 'CONDITION') $isMatchedTmp = ($arRule["CONDITION"] == $valueFilter); elseif ($keyFilter == 'ID') $isMatchedTmp = ($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; } private 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; /* $isIdA = isset($a["ID"]) && ($a["ID"] != ""); $isIdB = isset($b["ID"]) && ($b["ID"] != ""); if ($isIdA && !$isIdB) return 1; if (!$isIdA && $isIdB) return -1; */ $lenA = strlen($a["CONDITION"]); $lenB = 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); $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); Application::resetAccelerator(); } 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); Application::resetAccelerator(); } 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 ($nsOld["SITE_ID"] != "") $ns["SITE_ID"] = $nsOld["SITE_ID"]; } $ns["CNT"] = intval($ns["CNT"]); $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 ($ns["SITE_ID"] != "" && $ns["SITE_ID"] == $ar["LID"]) $filterRootPath = $ar["DOC_ROOT"]; } if ($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 = strlen($a["path"]); $lb = 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)) { UrlRewriter::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"]) && substr($ns["ID"]."/", 0, strlen($site["root"]."/")) != $site["root"]."/") { continue; } UrlRewriter::recursiveReindex($site["root"], "/", $arSites, $maxExecutionTime, $ns); if ($maxExecutionTime > 0 && !empty($ns["FLG"])) return $ns; } return $ns["CNT"]; } private static function recursiveReindex($rootPath, $path, $arSites, $maxExecutionTime = 0, &$ns) { $pathAbs = IO\Path::combine($rootPath, $path); $dir = new IO\Directory($pathAbs); if (!$dir->isExists()) return 0; $siteId = ""; foreach ($arSites as $site) { if (substr($pathAbs."/", 0, strlen($site["path"]."/")) == $site["path"]."/") { $siteId = $site["site_id"]; break; } } if (empty($siteId)) 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 || strlen($ns["FLG"]) <= 0 || (strlen($ns["FLG"]) > 0 && substr($ns["ID"]."/", 0, strlen($child->getPath()."/")) == $child->getPath()."/")) { if (UrlRewriter::recursiveReindex($rootPath, substr($child->getPath(), 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 && strlen($ns["FLG"]) > 0 && $ns["ID"] == $child->getPath()) { $ns["FLG"] = ""; } elseif (empty($ns["FLG"])) { $ID = UrlRewriter::reindexFile($siteId, $rootPath, substr($child->getPath(), strlen($rootPath)), $ns["max_file_size"]); if ($ID) $ns["CNT"] = intval($ns["CNT"]) + 1; } if ($maxExecutionTime > 0 && (getmicrotime() - START_EXEC_TIME > $maxExecutionTime)) { $ns["FLG"] = "Y"; $ns["ID"] = $child->getPath(); return false; } } } return true; } private function reindexFile($siteId, $rootPath, $path, $maxFileSize = 0) { $pathAbs = IO\Path::combine($rootPath, $path); if (!UrlRewriter::checkPath($pathAbs)) return 0; $file = new IO\File($pathAbs); if ($maxFileSize > 0 && $file->getFileSize() > $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, ); } UrlRewriter::add($siteId, $arFields); } } return true; } private 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 (strlen(trim($preg_mask)) > 0) $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 (strlen(trim($preg_mask)) > 0) $arExc[] = "'^".trim($preg_mask)."$'"; $searchMasksCache = array("exc" => $arExc, "inc" => $arInc); } $file = IO\Path::getName($path); if (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 (substr($match[0], -6) == "_PATH#") { return "(.+?)"; } else { return "([^/]+?)"; } } }