Bitrix-D7 23.9
 
Загрузка...
Поиск...
Не найдено
urlrewriter.php
1<?php
2namespace Bitrix\Main;
3
7
9{
10 const DEFAULT_SORT = 100;
11
12 protected static function loadRules($siteId)
13 {
14 $site = SiteTable::getRow(array("filter" => array("=LID" => $siteId), "cache" => array("ttl" => 3600)));
15 $docRoot = $site["DOC_ROOT"];
16
17 if (!empty($docRoot))
18 $docRoot = IO\Path::normalize($docRoot);
19 else
21
22 $arUrlRewrite = array();
23
24 if (IO\File::isFileExists($docRoot."/urlrewrite.php"))
25 include($docRoot."/urlrewrite.php");
26
27 foreach ($arUrlRewrite as &$rule)
28 {
29 if (!isset($rule["SORT"]))
30 $rule["SORT"] = self::DEFAULT_SORT;
31 }
32
33 return $arUrlRewrite;
34 }
35
36 protected static function saveRules($siteId, array $arUrlRewrite)
37 {
38 $site = SiteTable::getRow(array("filter" => array("=LID" => $siteId), "cache" => array("ttl" => 3600)));
39 $docRoot = $site["DOC_ROOT"];
40
41 if (!empty($docRoot))
42 $docRoot = IO\Path::normalize($docRoot);
43 else
45
46 $data = var_export($arUrlRewrite, true);
47
48 $event = new Event("main", "onUrlRewriteSaveRules", [
49 $siteId,
50 $docRoot,
51 $arUrlRewrite
52 ]);
53 $event->send();
54
55 $filename = $docRoot . "/urlrewrite.php";
56 IO\File::putFileContents($filename, "<"."?php\n\$arUrlRewrite=".$data.";\n");
58 }
59
60 public static function getList($siteId, $arFilter = array(), $arOrder = array())
61 {
62 if (empty($siteId))
63 throw new ArgumentNullException("siteId");
64
65 $arUrlRewrite = static::loadRules($siteId);
66
67 $arResult = array();
68 $arResultKeys = self::filterRules($arUrlRewrite, $arFilter);
69 foreach ($arResultKeys as $key)
70 $arResult[] = $arUrlRewrite[$key];
71
72 if (!empty($arOrder) && !empty($arResult))
73 {
74 $arOrderKeys = array_keys($arOrder);
75 $orderBy = array_shift($arOrderKeys);
76 $orderDir = $arOrder[$orderBy];
77
78 $orderBy = mb_strtoupper($orderBy);
79 $orderDir = mb_strtoupper($orderDir);
80
81 $orderDir = (($orderDir == "DESC") ? SORT_DESC : SORT_ASC);
82
83 $ar = array();
84 foreach ($arResult as $key => $row)
85 $ar[$key] = $row[$orderBy];
86
87 array_multisort($ar, $orderDir, $arResult);
88 }
89
90 return $arResult;
91 }
92
93 protected static function filterRules(array $arUrlRewrite, array $arFilter)
94 {
95 $arResultKeys = array();
96
97 foreach ($arUrlRewrite as $keyRule => $arRule)
98 {
99 $isMatched = true;
100 foreach ($arFilter as $keyFilter => $valueFilter)
101 {
102 $isNegative = false;
103 if (mb_substr($keyFilter, 0, 1) === "!")
104 {
105 $isNegative = true;
106 $keyFilter = mb_substr($keyFilter, 1);
107 }
108
109 if ($keyFilter === 'QUERY')
110 $isMatchedTmp = preg_match($arRule["CONDITION"], $valueFilter);
111 elseif ($keyFilter === 'CONDITION')
112 $isMatchedTmp = ($arRule["CONDITION"] == $valueFilter);
113 elseif ($keyFilter === 'ID')
114 $isMatchedTmp = (isset($arRule["ID"]) && ($arRule["ID"] == $valueFilter));
115 elseif ($keyFilter === 'PATH')
116 $isMatchedTmp = ($arRule["PATH"] == $valueFilter);
117 else
118 throw new ArgumentException("arFilter");
119
120 $isMatched = ($isNegative xor $isMatchedTmp);
121
122 if (!$isMatched)
123 break;
124 }
125
126 if ($isMatched)
127 $arResultKeys[] = $keyRule;
128 }
129
130 return $arResultKeys;
131 }
132
133 protected static function recordsCompare($a, $b)
134 {
135 $sortA = isset($a["SORT"]) ? intval($a["SORT"]) : self::DEFAULT_SORT;
136 $sortB = isset($b["SORT"]) ? intval($b["SORT"]) : self::DEFAULT_SORT;
137
138 if ($sortA > $sortB)
139 return 1;
140 elseif ($sortA < $sortB)
141 return -1;
142
143 $lenA = mb_strlen($a["CONDITION"]);
144 $lenB = mb_strlen($b["CONDITION"]);
145 if ($lenA < $lenB)
146 return 1;
147 elseif ($lenA > $lenB)
148 return -1;
149 else
150 return 0;
151 }
152
153 public static function add($siteId, $arFields)
154 {
155 if (empty($siteId))
156 throw new ArgumentNullException("siteId");
157
158 $arUrlRewrite = static::loadRules($siteId);
159
160 // if rule is exist return
161 foreach ($arUrlRewrite as $rule)
162 {
163 if ($arFields["CONDITION"] == $rule["CONDITION"])
164 {
165 return;
166 }
167 }
168
169 $arUrlRewrite[] = array(
170 "CONDITION" => $arFields["CONDITION"],
171 "RULE" => $arFields["RULE"],
172 "ID" => $arFields["ID"],
173 "PATH" => $arFields["PATH"],
174 "SORT" => isset($arFields["SORT"]) ? intval($arFields["SORT"]) : self::DEFAULT_SORT,
175 );
176
177 uasort($arUrlRewrite, array('\Bitrix\Main\UrlRewriter', "recordsCompare"));
178
179 static::saveRules($siteId, $arUrlRewrite);
180 }
181
182 public static function update($siteId, $arFilter, $arFields)
183 {
184 if (empty($siteId))
185 throw new ArgumentNullException("siteId");
186
187 $arUrlRewrite = static::loadRules($siteId);
188
189 $arResultKeys = self::filterRules($arUrlRewrite, $arFilter);
190 foreach ($arResultKeys as $key)
191 {
192 if (array_key_exists("CONDITION", $arFields))
193 $arUrlRewrite[$key]["CONDITION"] = $arFields["CONDITION"];
194 if (array_key_exists("RULE", $arFields))
195 $arUrlRewrite[$key]["RULE"] = $arFields["RULE"];
196 if (array_key_exists("ID", $arFields))
197 $arUrlRewrite[$key]["ID"] = $arFields["ID"];
198 if (array_key_exists("PATH", $arFields))
199 $arUrlRewrite[$key]["PATH"] = $arFields["PATH"];
200 if (array_key_exists("SORT", $arFields))
201 $arUrlRewrite[$key]["SORT"] = intval($arFields["SORT"]);
202 }
203
204 uasort($arUrlRewrite, array('\Bitrix\Main\UrlRewriter', "recordsCompare"));
205
206 static::saveRules($siteId, $arUrlRewrite);
207 }
208
209 public static function delete($siteId, $arFilter)
210 {
211 if (empty($siteId))
212 throw new ArgumentNullException("siteId");
213
214 $arUrlRewrite = static::loadRules($siteId);
215
216 $arResultKeys = self::filterRules($arUrlRewrite, $arFilter);
217 foreach ($arResultKeys as $key)
218 unset($arUrlRewrite[$key]);
219
220 uasort($arUrlRewrite, array('\Bitrix\Main\UrlRewriter', "recordsCompare"));
221
222 static::saveRules($siteId, $arUrlRewrite);
223 }
224
225 public static function reindexAll($maxExecutionTime = 0, $ns = array())
226 {
227 @set_time_limit(0);
228 if (!is_array($ns))
229 $ns = array();
230
231 if ($maxExecutionTime <= 0)
232 {
233 $nsOld = $ns;
234 $ns = array(
235 "CLEAR" => "N",
236 "ID" => "",
237 "FLG" => "",
238 "SESS_ID" => md5(uniqid("")),
239 "max_execution_time" => $nsOld["max_execution_time"],
240 "stepped" => $nsOld["stepped"],
241 "max_file_size" => $nsOld["max_file_size"]
242 );
243
244 if (!empty($nsOld["SITE_ID"]))
245 $ns["SITE_ID"] = $nsOld["SITE_ID"];
246 }
247 $ns["CNT"] = intval($ns["CNT"] ?? 0);
248
249 $arSites = array();
250 $filterRootPath = "";
251
252 $db = SiteTable::getList(
253 array(
254 "select" => array("LID", "DOC_ROOT", "DIR"),
255 "filter" => array("=ACTIVE" => "Y"),
256 )
257 );
258 while ($ar = $db->fetch())
259 {
260 if (empty($ar["DOC_ROOT"]))
261 $ar["DOC_ROOT"] = Application::getDocumentRoot();
262
263 $arSites[] = array(
264 "site_id" => $ar["LID"],
265 "root" => $ar["DOC_ROOT"],
266 "path" => IO\Path::combine($ar["DOC_ROOT"], $ar["DIR"])
267 );
268
269 if (!empty($ns["SITE_ID"]) && $ns["SITE_ID"] == $ar["LID"])
270 $filterRootPath = $ar["DOC_ROOT"];
271 }
272
273 if (!empty($ns["SITE_ID"]) && !empty($filterRootPath))
274 {
275 $arSitesTmp = array();
276 $arKeys = array_keys($arSites);
277 foreach ($arKeys as $key)
278 {
279 if ($arSites[$key]["root"] == $filterRootPath)
280 $arSitesTmp[] = $arSites[$key];
281 }
282 $arSites = $arSitesTmp;
283 }
284
285 uasort($arSites,
286 function($a, $b)
287 {
288 $la = mb_strlen($a["path"]);
289 $lb = mb_strlen($b["path"]);
290 if ($la == $lb)
291 {
292 if ($a["site_id"] == $b["site_id"])
293 return 0;
294 else
295 return ($a["site_id"] > $b["site_id"]) ? -1 : 1;
296 }
297 return ($la > $lb) ? -1 : 1;
298 }
299 );
300
301 if ($ns["CLEAR"] != "Y")
302 {
303 $arAlreadyDeleted = array();
304 foreach ($arSites as $site)
305 {
306 Component\ParametersTable::deleteBySiteId($site["site_id"]);
307 if (!in_array($site["root"], $arAlreadyDeleted))
308 {
309 static::delete(
310 $site["site_id"],
311 array("!ID" => "")
312 );
313 $arAlreadyDeleted[] = $site["root"];
314 }
315 }
316 }
317 $ns["CLEAR"] = "Y";
318
319 clearstatcache();
320
321 $arAlreadyParsed = array();
322 foreach ($arSites as $site)
323 {
324 if (in_array($site["root"], $arAlreadyParsed))
325 continue;
326 $arAlreadyParsed[] = $site["root"];
327
328 if ($maxExecutionTime > 0 && !empty($ns["FLG"])
329 && mb_substr($ns["ID"]."/", 0, mb_strlen($site["root"]."/")) != $site["root"]."/")
330 {
331 continue;
332 }
333
334 static::recursiveReindex($site["root"], "/", $arSites, $maxExecutionTime, $ns);
335
336 if ($maxExecutionTime > 0 && !empty($ns["FLG"]))
337 return $ns;
338 }
339
340 return $ns["CNT"];
341 }
342
343 protected static function recursiveReindex($rootPath, $path, $arSites, $maxExecutionTime, &$ns)
344 {
345 $pathAbs = IO\Path::combine($rootPath, $path);
346
347 $siteId = "";
348 foreach ($arSites as $site)
349 {
350 if (mb_substr($pathAbs."/", 0, mb_strlen($site["path"]."/")) == $site["path"]."/")
351 {
352 $siteId = $site["site_id"];
353 break;
354 }
355 }
356 if (empty($siteId))
357 return 0;
358
359 $dir = new IO\Directory($pathAbs, $siteId);
360 if (!$dir->isExists())
361 return 0;
362
363 $arChildren = $dir->getChildren();
364 foreach ($arChildren as $child)
365 {
366 if ($child->isDirectory())
367 {
368 if ($child->isSystem())
369 continue;
370
371 //this is not first step and we had stopped here, so go on to reindex
372 if ($maxExecutionTime <= 0
373 || $ns["FLG"] == ''
374 || mb_substr($ns["ID"]."/", 0, mb_strlen($child->getPath()."/")) == $child->getPath()."/"
375 )
376 {
377 if (static::recursiveReindex($rootPath, mb_substr($child->getPath(), mb_strlen($rootPath)), $arSites, $maxExecutionTime, $ns) === false)
378 return false;
379 }
380 else //all done
381 {
382 continue;
383 }
384 }
385 else
386 {
387 //not the first step and we found last file from previos one
388 if ($maxExecutionTime > 0 && $ns["FLG"] <> ''
389 && $ns["ID"] == $child->getPath())
390 {
391 $ns["FLG"] = "";
392 }
393 elseif (empty($ns["FLG"]))
394 {
395 $ID = static::reindexFile($siteId, $rootPath, mb_substr($child->getPath(), mb_strlen($rootPath)), $ns["max_file_size"]);
396 if ($ID)
397 $ns["CNT"] = intval($ns["CNT"]) + 1;
398 }
399
400 if ($maxExecutionTime > 0
401 && (microtime(true) - START_EXEC_TIME > $maxExecutionTime))
402 {
403 $ns["FLG"] = "Y";
404 $ns["ID"] = $child->getPath();
405 return false;
406 }
407 }
408 }
409 return true;
410 }
411
412 public static function reindexFile($siteId, $rootPath, $path, $maxFileSize = 0)
413 {
414 $pathAbs = IO\Path::combine($rootPath, $path);
415
416 if (!static::checkPath($pathAbs))
417 return 0;
418
419 $file = new IO\File($pathAbs);
420 if ($maxFileSize > 0 && $file->getSize() > $maxFileSize * 1024)
421 return 0;
422
423 $fileSrc = $file->getContents();
424
425 if (!$fileSrc || $fileSrc == "")
426 return 0;
427
428 $arComponents = \PHPParser::parseScript($fileSrc);
429
430 for ($i = 0, $cnt = count($arComponents); $i < $cnt; $i++)
431 {
432 $sef = (is_array($arComponents[$i]["DATA"]["PARAMS"]) && $arComponents[$i]["DATA"]["PARAMS"]["SEF_MODE"] == "Y");
433
434 Component\ParametersTable::add(
435 array(
436 'SITE_ID' => $siteId,
437 'COMPONENT_NAME' => $arComponents[$i]["DATA"]["COMPONENT_NAME"],
438 'TEMPLATE_NAME' => $arComponents[$i]["DATA"]["TEMPLATE_NAME"],
439 'REAL_PATH' => $path,
440 'SEF_MODE' => ($sef? Component\ParametersTable::SEF_MODE : Component\ParametersTable::NOT_SEF_MODE),
441 'SEF_FOLDER' => ($sef? $arComponents[$i]["DATA"]["PARAMS"]["SEF_FOLDER"] : null),
442 'START_CHAR' => $arComponents[$i]["START"],
443 'END_CHAR' => $arComponents[$i]["END"],
444 'PARAMETERS' => serialize($arComponents[$i]["DATA"]["PARAMS"]),
445 )
446 );
447
448 if ($sef)
449 {
450 if (array_key_exists("SEF_RULE", $arComponents[$i]["DATA"]["PARAMS"]))
451 {
452 $ruleMaker = new UrlRewriterRuleMaker;
453 $ruleMaker->process($arComponents[$i]["DATA"]["PARAMS"]["SEF_RULE"]);
454
455 $arFields = array(
456 "CONDITION" => $ruleMaker->getCondition(),
457 "RULE" => $ruleMaker->getRule(),
458 "ID" => $arComponents[$i]["DATA"]["COMPONENT_NAME"],
459 "PATH" => $path,
460 "SORT" => self::DEFAULT_SORT,
461 );
462 }
463 else
464 {
465 $arFields = array(
466 "CONDITION" => "#^".$arComponents[$i]["DATA"]["PARAMS"]["SEF_FOLDER"]."#",
467 "RULE" => "",
468 "ID" => $arComponents[$i]["DATA"]["COMPONENT_NAME"],
469 "PATH" => $path,
470 "SORT" => self::DEFAULT_SORT,
471 );
472 }
473
474 static::add($siteId, $arFields);
475 }
476 }
477
478 return true;
479 }
480
481 public static function checkPath($path)
482 {
483 static $searchMasksCache = false;
484 if (is_array($searchMasksCache))
485 {
486 $arExc = $searchMasksCache["exc"];
487 $arInc = $searchMasksCache["inc"];
488 }
489 else
490 {
491 $arExc = array();
492 $arInc = array();
493
494 $inc = Config\Option::get("main", "urlrewrite_include_mask", "*.php");
495 $inc = str_replace("'", "\\'", str_replace("*", ".*?", str_replace("?", ".", str_replace(".", "\\.", str_replace("\\", "/", $inc)))));
496 $arIncTmp = explode(";", $inc);
497 foreach ($arIncTmp as $preg_mask)
498 if (trim($preg_mask) <> '')
499 $arInc[] = "'^".trim($preg_mask)."$'";
500
501 $exc = Config\Option::get("main", "urlrewrite_exclude_mask", "/bitrix/*;");
502 $exc = str_replace("'", "\\'", str_replace("*", ".*?", str_replace("?", ".", str_replace(".", "\\.", str_replace("\\", "/", $exc)))));
503 $arExcTmp = explode(";", $exc);
504 foreach ($arExcTmp as $preg_mask)
505 if (trim($preg_mask) <> '')
506 $arExc[] = "'^".trim($preg_mask)."$'";
507
508 $searchMasksCache = array("exc" => $arExc, "inc" => $arInc);
509 }
510
511 $file = IO\Path::getName($path);
512 if (mb_substr($file, 0, 1) === ".")
513 return 0;
514
515 foreach ($arExc as $preg_mask)
516 if (preg_match($preg_mask, $path))
517 return false;
518
519 foreach ($arInc as $preg_mask)
520 if (preg_match($preg_mask, $path))
521 return true;
522
523 return false;
524 }
525}
526
535{
536 protected $condition = "";
537 protected $variables = array();
538 protected $rule = "";
539
545 public function process($sefRule)
546 {
547 $this->rule = "";
548 $this->variables = array();
549 $this->condition = "#^".preg_replace_callback("/(#[a-zA-Z0-9_]+#)/", array($this, "_callback"), $sefRule)."\\??(.*)#";
550 $i = 0;
551 foreach ($this->variables as $variableName)
552 {
553 $i++;
554 if ($this->rule)
555 $this->rule .= "&";
556 $this->rule .= $variableName."=\$".$i;
557 }
558 $i++;
559 $this->rule .= "&\$".$i;
560 }
561
567 public function getCondition()
568 {
569 return $this->condition;
570 }
571
577 public function getRule()
578 {
579 return $this->rule;
580 }
581
589 protected function _callback(array $match)
590 {
591 $this->variables[] = trim($match[0], "#");
592 if (mb_substr($match[0], -6) == "_PATH#")
593 {
594 return "(.+?)";
595 }
596 else
597 {
598 return "([^/]+?)";
599 }
600 }
601}
static resetAccelerator(string $filename=null)
static getRow(array $parameters)
static getList(array $parameters=array())
static recordsCompare($a, $b)
static getList($siteId, $arFilter=array(), $arOrder=array())
static filterRules(array $arUrlRewrite, array $arFilter)
static reindexAll($maxExecutionTime=0, $ns=array())
static reindexFile($siteId, $rootPath, $path, $maxFileSize=0)
static saveRules($siteId, array $arUrlRewrite)
static recursiveReindex($rootPath, $path, $arSites, $maxExecutionTime, &$ns)
static loadRules($siteId)
static add($siteId, $arFields)
static update($siteId, $arFilter, $arFields)