Bitrix-D7 23.9
 
Загрузка...
Поиск...
Не найдено
loader.php
1<?php
2
3namespace Bitrix\Main;
4
6
11class Loader
12{
16 const SAFE_MODE = false;
17
18 const BITRIX_HOLDER = "bitrix";
19 const LOCAL_HOLDER = "local";
20
21 protected static $safeModeModules = ["main" => true, "fileman" => true];
22 protected static $loadedModules = ["main" => true];
23 protected static $semiloadedModules = [];
24 protected static $modulesHolders = ["main" => self::BITRIX_HOLDER];
25 protected static $sharewareModules = [];
26
31 protected static $namespaces = [];
32
44 const MODULE_DEMO = 2;
49
50 protected static $autoLoadClasses = [];
51
55 protected static $requireThrowException = true;
56
58 const ALPHA_LOWER = "qwertyuioplkjhgfdsazxcvbnm";
60 const ALPHA_UPPER = "QWERTYUIOPLKJHGFDSAZXCVBNM";
61
69 public static function includeModule($moduleName)
70 {
71 if (!is_string($moduleName) || $moduleName == "")
72 {
73 throw new LoaderException("Empty module name");
74 }
75 if (preg_match("#[^a-zA-Z0-9._]#", $moduleName))
76 {
77 throw new LoaderException(sprintf("Module name '%s' is not correct", $moduleName));
78 }
79
80 $moduleName = strtolower($moduleName);
81
82 if (self::SAFE_MODE)
83 {
84 if (!isset(self::$safeModeModules[$moduleName]))
85 {
86 return false;
87 }
88 }
89
90 if (isset(self::$loadedModules[$moduleName]))
91 {
92 return self::$loadedModules[$moduleName];
93 }
94
95 if (isset(self::$semiloadedModules[$moduleName]))
96 {
97 trigger_error("Module '".$moduleName."' is in loading progress", E_USER_WARNING);
98 }
99
100 $arInstalledModules = ModuleManager::getInstalledModules();
101 if (!isset($arInstalledModules[$moduleName]))
102 {
103 return (self::$loadedModules[$moduleName] = false);
104 }
105
106 $documentRoot = self::getDocumentRoot();
107
108 $moduleHolder = self::LOCAL_HOLDER;
109 $pathToInclude = $documentRoot."/".$moduleHolder."/modules/".$moduleName;
110 if (!file_exists($pathToInclude))
111 {
112 $moduleHolder = self::BITRIX_HOLDER;
113 $pathToInclude = $documentRoot."/".$moduleHolder."/modules/".$moduleName;
114 if (!file_exists($pathToInclude))
115 {
116 return (self::$loadedModules[$moduleName] = false);
117 }
118 }
119
120 //register a PSR-4 base folder for the module
121 if (strpos($moduleName, ".") !== false)
122 {
123 //partner's module
124 $baseName = str_replace(".", "\\", ucwords($moduleName, "."));
125 }
126 else
127 {
128 //bitrix's module
129 $baseName = "Bitrix\\".ucfirst($moduleName);
130 }
131 self::registerNamespace($baseName, $documentRoot."/".$moduleHolder."/modules/".$moduleName."/lib");
132
133 self::$modulesHolders[$moduleName] = $moduleHolder;
134
135 if (class_exists('\Dev\Main\Migrator\ModuleUpdater'))
136 {
137 \Dev\Main\Migrator\ModuleUpdater::checkUpdates($moduleName, $pathToInclude);
138 }
139
140 $res = true;
141 if (file_exists($pathToInclude."/include.php"))
142 {
143 //recursion control
144 self::$semiloadedModules[$moduleName] = true;
145
146 $res = self::includeModuleInternal($pathToInclude."/include.php");
147
148 unset(self::$semiloadedModules[$moduleName]);
149 }
150
151 self::$loadedModules[$moduleName] = ($res !== false);
152
153 if (!self::$loadedModules[$moduleName])
154 {
155 //unregister the namespace if "include" fails
156 self::unregisterNamespace($baseName);
157 }
158 else
159 {
160 ServiceLocator::getInstance()->registerByModuleSettings($moduleName);
161 }
162
163 return self::$loadedModules[$moduleName];
164 }
165
174 public static function requireModule($moduleName)
175 {
176 $included = self::includeModule($moduleName);
177
178 if (!$included && self::$requireThrowException)
179 {
180 throw new LoaderException("Required module `{$moduleName}` was not found");
181 }
182
183 return $included;
184 }
185
186 private static function includeModuleInternal($path)
187 {
189 global $DB, $MESS;
190 return include_once($path);
191 }
192
202 public static function includeSharewareModule($moduleName)
203 {
204 if (isset(self::$sharewareModules[$moduleName]))
205 {
206 return self::$sharewareModules[$moduleName];
207 }
208
209 $module = str_replace(".", "_", $moduleName);
210
211 if (self::includeModule($moduleName))
212 {
213 if (defined($module."_DEMO") && constant($module."_DEMO") == "Y")
214 {
215 self::$sharewareModules[$moduleName] = self::MODULE_DEMO;
216 }
217 else
218 {
219 self::$sharewareModules[$moduleName] = self::MODULE_INSTALLED;
220 }
221
222 return self::$sharewareModules[$moduleName];
223 }
224
225 if (defined($module."_DEMO") && constant($module."_DEMO") == "Y")
226 {
227 return (self::$sharewareModules[$moduleName] = self::MODULE_DEMO_EXPIRED);
228 }
229
230 return (self::$sharewareModules[$moduleName] = self::MODULE_NOT_FOUND);
231 }
232
233 public static function clearModuleCache($moduleName)
234 {
235 if (!is_string($moduleName) || $moduleName == "")
236 {
237 throw new LoaderException("Empty module name");
238 }
239
240 if ($moduleName !== "main")
241 {
242 unset(self::$loadedModules[$moduleName]);
243 unset(self::$modulesHolders[$moduleName]);
244 }
245
246 unset(self::$sharewareModules[$moduleName]);
247 }
248
254 public static function getDocumentRoot()
255 {
256 static $documentRoot = null;
257 if ($documentRoot === null)
258 {
259 $documentRoot = rtrim($_SERVER["DOCUMENT_ROOT"], "/\\");
260 }
261 return $documentRoot;
262 }
263
273 public static function registerAutoLoadClasses($moduleName, array $classes)
274 {
275 if (empty($classes))
276 {
277 return;
278 }
279 if (($moduleName !== null) && empty($moduleName))
280 {
281 throw new LoaderException(sprintf("Module name '%s' is not correct", $moduleName));
282 }
283
284 foreach ($classes as $class => $file)
285 {
286 $class = ltrim($class, "\\");
287 $class = strtolower($class);
288
289 self::$autoLoadClasses[$class] = [
290 "module" => $moduleName,
291 "file" => $file,
292 ];
293 }
294 }
295
303 public static function registerNamespace($namespace, $path)
304 {
305 $namespace = trim($namespace, "\\")."\\";
306 $namespace = strtolower($namespace);
307
308 $path = rtrim($path, "/\\");
309 $depth = substr_count(rtrim($namespace, "\\"), "\\");
310
311 self::$namespaces[$namespace][] = [
312 "path" => $path,
313 "depth" => $depth,
314 ];
315 }
316
321 public static function unregisterNamespace($namespace)
322 {
323 $namespace = trim($namespace, "\\")."\\";
324 $namespace = strtolower($namespace);
325
326 unset(self::$namespaces[$namespace]);
327 }
328
333 public static function registerHandler(callable $handler)
334 {
335 \spl_autoload_register($handler);
336 }
337
344 public static function autoLoad($className)
345 {
346 // fix web env
347 $className = ltrim($className, "\\");
348
349 $classLower = strtolower($className);
350
351 static $documentRoot = null;
352 if ($documentRoot === null)
353 {
354 $documentRoot = self::getDocumentRoot();
355 }
356
357 //optimization via direct paths
358 if (isset(self::$autoLoadClasses[$classLower]))
359 {
360 $pathInfo = self::$autoLoadClasses[$classLower];
361 if ($pathInfo["module"] != "")
362 {
363 $module = $pathInfo["module"];
364 $holder = (self::$modulesHolders[$module] ?? self::BITRIX_HOLDER);
365
366 $filePath = (defined('REPOSITORY_ROOT') && $holder === self::BITRIX_HOLDER)
367 ? REPOSITORY_ROOT
368 : "{$documentRoot}/{$holder}/modules";
369
370 $filePath .= '/'.$module."/".$pathInfo["file"];
371
372 require_once($filePath);
373 }
374 else
375 {
376 require_once($documentRoot.$pathInfo["file"]);
377 }
378 return;
379 }
380
381 if (preg_match("#[^\\\\/a-zA-Z0-9_]#", $className))
382 {
383 return;
384 }
385
386 $tryFiles = [[
387 "real" => $className,
388 "lower" => $classLower,
389 ]];
390
391 if (substr($classLower, -5) == "table")
392 {
393 // old *Table stored in reserved files
394 $tryFiles[] = [
395 "real" => substr($className, 0, -5),
396 "lower" => substr($classLower, 0, -5),
397 ];
398 }
399
400 foreach ($tryFiles as $classInfo)
401 {
402 $classParts = explode("\\", $classInfo["lower"]);
403
404 //remove class name
405 array_pop($classParts);
406
407 while (!empty($classParts))
408 {
409 //go from the end
410 $namespace = implode("\\", $classParts)."\\";
411
412 if (isset(self::$namespaces[$namespace]))
413 {
414 //found
415 foreach (self::$namespaces[$namespace] as $namespaceLocation)
416 {
417 $depth = $namespaceLocation["depth"];
418 $path = $namespaceLocation["path"];
419
420 $fileParts = explode("\\", $classInfo["real"]);
421
422 for ($i=0; $i <= $depth; $i++)
423 {
424 array_shift($fileParts);
425 }
426
427 $classPath = implode("/", $fileParts);
428
429 $classPathLower = strtolower($classPath);
430
431 // final path lower case
432 $filePath = $path.'/'.$classPathLower.".php";
433
434 if (file_exists($filePath))
435 {
436 require_once($filePath);
437 break 3;
438 }
439
440 // final path original case
441 $filePath = $path.'/'.$classPath.".php";
442
443 if (file_exists($filePath))
444 {
445 require_once($filePath);
446 break 3;
447 }
448 }
449 }
450
451 //try the shorter namespace
452 array_pop($classParts);
453 }
454 }
455 }
456
462 public static function requireClass($className)
463 {
464 $file = ltrim($className, "\\"); // fix web env
465 $file = strtolower($file);
466
467 if (preg_match("#[^\\\\/a-zA-Z0-9_]#", $file))
468 return;
469
470 $tryFiles = [$file];
471
472 if (substr($file, -5) == "table")
473 {
474 // old *Table stored in reserved files
475 $tryFiles[] = substr($file, 0, -5);
476 }
477
478 foreach ($tryFiles as $file)
479 {
480 $file = str_replace('\\', '/', $file);
481 $arFile = explode("/", $file);
482
483 if ($arFile[0] === "bitrix")
484 {
485 array_shift($arFile);
486
487 if (empty($arFile))
488 {
489 break;
490 }
491
492 $module = array_shift($arFile);
493 if ($module == null || empty($arFile))
494 {
495 break;
496 }
497 }
498 else
499 {
500 $module1 = array_shift($arFile);
501 $module2 = array_shift($arFile);
502
503 if ($module1 == null || $module2 == null || empty($arFile))
504 {
505 break;
506 }
507
508 $module = $module1.".".$module2;
509 }
510
511 if (!self::includeModule($module))
512 {
513 throw new LoaderException(sprintf(
514 "There is no `%s` class, module `%s` is unavailable", $className, $module
515 ));
516 }
517 }
518
519 self::autoLoad($className);
520 }
521
529 public static function getLocal($path, $root = null)
530 {
531 if ($root === null)
532 {
533 $root = self::getDocumentRoot();
534 }
535
536 if (file_exists($root."/local/".$path))
537 {
538 return $root."/local/".$path;
539 }
540 elseif (file_exists($root."/bitrix/".$path))
541 {
542 return $root."/bitrix/".$path;
543 }
544 else
545 {
546 return false;
547 }
548 }
549
557 public static function getPersonal($path)
558 {
559 $root = self::getDocumentRoot();
560 $personal = ($_SERVER["BX_PERSONAL_ROOT"] ?? "");
561
562 if ($personal <> '' && file_exists($root.$personal."/".$path))
563 {
564 return $root.$personal."/".$path;
565 }
566
567 return self::getLocal($path, $root);
568 }
569
576 {
577 self::$requireThrowException = (bool) $requireThrowException;
578 }
579}
580
581class LoaderException extends \Exception
582{
583 public function __construct($message = "", $code = 0, \Exception $previous = null)
584 {
585 parent::__construct($message, $code, $previous);
586 }
587}
__construct($message="", $code=0, \Exception $previous=null)
Definition loader.php:583
static $modulesHolders
Definition loader.php:24
const MODULE_INSTALLED
Definition loader.php:40
static $sharewareModules
Definition loader.php:25
static requireModule($moduleName)
Definition loader.php:174
static getDocumentRoot()
Definition loader.php:254
static includeModule($moduleName)
Definition loader.php:69
const MODULE_DEMO_EXPIRED
Definition loader.php:48
static clearModuleCache($moduleName)
Definition loader.php:233
static $namespaces
Definition loader.php:31
static registerHandler(callable $handler)
Definition loader.php:333
static registerAutoLoadClasses($moduleName, array $classes)
Definition loader.php:273
static unregisterNamespace($namespace)
Definition loader.php:321
static registerNamespace($namespace, $path)
Definition loader.php:303
static $autoLoadClasses
Definition loader.php:50
static $loadedModules
Definition loader.php:22
const MODULE_NOT_FOUND
Definition loader.php:36
static includeSharewareModule($moduleName)
Definition loader.php:202
static $safeModeModules
Definition loader.php:21
static $semiloadedModules
Definition loader.php:23
static getLocal($path, $root=null)
Definition loader.php:529
static setRequireThrowException($requireThrowException)
Definition loader.php:575
static getPersonal($path)
Definition loader.php:557
static requireClass($className)
Definition loader.php:462
const BITRIX_HOLDER
Definition loader.php:18
static autoLoad($className)
Definition loader.php:344
static $requireThrowException
Definition loader.php:55