Bitrix-D7 22.6
 
Загрузка...
Поиск...
Не найдено
loader.php
1<?php
2namespace Bitrix\Main;
3
5
10class Loader
11{
15 const SAFE_MODE = false;
16
17 const BITRIX_HOLDER = "bitrix";
18 const LOCAL_HOLDER = "local";
19
20 protected static $safeModeModules = ["main" => true, "fileman" => true];
21 protected static $loadedModules = ["main" => true];
22 protected static $semiloadedModules = [];
23 protected static $modulesHolders = ["main" => self::BITRIX_HOLDER];
24 protected static $sharewareModules = [];
25
30 protected static $namespaces = [];
31
43 const MODULE_DEMO = 2;
48
49 protected static $autoLoadClasses = [];
50
54 protected static $requireThrowException = true;
55
57 const ALPHA_LOWER = "qwertyuioplkjhgfdsazxcvbnm";
59 const ALPHA_UPPER = "QWERTYUIOPLKJHGFDSAZXCVBNM";
60
68 public static function includeModule($moduleName)
69 {
70 if (!is_string($moduleName) || $moduleName == "")
71 {
72 throw new LoaderException("Empty module name");
73 }
74 if (preg_match("#[^a-zA-Z0-9._]#", $moduleName))
75 {
76 throw new LoaderException(sprintf("Module name '%s' is not correct", $moduleName));
77 }
78
79 $moduleName = strtolower($moduleName);
80
81 if (self::SAFE_MODE)
82 {
83 if (!isset(self::$safeModeModules[$moduleName]))
84 {
85 return false;
86 }
87 }
88
89 if (isset(self::$loadedModules[$moduleName]))
90 {
91 return self::$loadedModules[$moduleName];
92 }
93
94 if (isset(self::$semiloadedModules[$moduleName]))
95 {
96 trigger_error("Module '".$moduleName."' is in loading progress", E_USER_WARNING);
97 }
98
99 $arInstalledModules = ModuleManager::getInstalledModules();
100 if (!isset($arInstalledModules[$moduleName]))
101 {
102 return (self::$loadedModules[$moduleName] = false);
103 }
104
105 $documentRoot = self::getDocumentRoot();
106
107 $moduleHolder = self::LOCAL_HOLDER;
108 $pathToInclude = $documentRoot."/".$moduleHolder."/modules/".$moduleName;
109 if (!file_exists($pathToInclude))
110 {
111 $moduleHolder = self::BITRIX_HOLDER;
112 $pathToInclude = $documentRoot."/".$moduleHolder."/modules/".$moduleName;
113 if (!file_exists($pathToInclude))
114 {
115 return (self::$loadedModules[$moduleName] = false);
116 }
117 }
118
119 //register a PSR-4 base folder for the module
120 if(strpos($moduleName, ".") !== false)
121 {
122 //partner's module
123 $baseName = str_replace(".", "\\", ucwords($moduleName, "."));
124 }
125 else
126 {
127 //bitrix's module
128 $baseName = "Bitrix\\".ucfirst($moduleName);
129 }
130 self::registerNamespace($baseName, $documentRoot."/".$moduleHolder."/modules/".$moduleName."/lib");
131
132 self::$modulesHolders[$moduleName] = $moduleHolder;
133
134 $res = true;
135 if(file_exists($pathToInclude."/include.php"))
136 {
137 //recursion control
138 self::$semiloadedModules[$moduleName] = true;
139
140 $res = self::includeModuleInternal($pathToInclude."/include.php");
141
142 unset(self::$semiloadedModules[$moduleName]);
143 }
144
145 self::$loadedModules[$moduleName] = ($res !== false);
146
147 if(self::$loadedModules[$moduleName] == false)
148 {
149 //unregister the namespace if "include" fails
150 self::unregisterNamespace($baseName);
151 }
152 else
153 {
154 ServiceLocator::getInstance()->registerByModuleSettings($moduleName);
155 }
156
157 return self::$loadedModules[$moduleName];
158 }
159
168 public static function requireModule($moduleName)
169 {
170 $included = self::includeModule($moduleName);
171
172 if (!$included && self::$requireThrowException)
173 {
174 throw new LoaderException("Required module `{$moduleName}` was not found");
175 }
176
177 return $included;
178 }
179
180 private static function includeModuleInternal($path)
181 {
183 global $DB, $MESS;
184 return include_once($path);
185 }
186
196 public static function includeSharewareModule($moduleName)
197 {
198 if (isset(self::$sharewareModules[$moduleName]))
199 {
200 return self::$sharewareModules[$moduleName];
201 }
202
203 $module = str_replace(".", "_", $moduleName);
204
205 if (self::includeModule($moduleName))
206 {
207 if (defined($module."_DEMO") && constant($module."_DEMO") == "Y")
208 {
209 self::$sharewareModules[$moduleName] = self::MODULE_DEMO;
210 }
211 else
212 {
213 self::$sharewareModules[$moduleName] = self::MODULE_INSTALLED;
214 }
215
216 return self::$sharewareModules[$moduleName];
217 }
218
219 if (defined($module."_DEMO") && constant($module."_DEMO") == "Y")
220 {
221 return (self::$sharewareModules[$moduleName] = self::MODULE_DEMO_EXPIRED);
222 }
223
224 return (self::$sharewareModules[$moduleName] = self::MODULE_NOT_FOUND);
225 }
226
227 public static function clearModuleCache($moduleName)
228 {
229 if (!is_string($moduleName) || $moduleName == "")
230 {
231 throw new LoaderException("Empty module name");
232 }
233
234 if($moduleName !== "main")
235 {
236 unset(self::$loadedModules[$moduleName]);
237 unset(self::$modulesHolders[$moduleName]);
238 }
239
240 unset(self::$sharewareModules[$moduleName]);
241 }
242
248 public static function getDocumentRoot()
249 {
250 static $documentRoot = null;
251 if ($documentRoot === null)
252 {
253 $documentRoot = rtrim($_SERVER["DOCUMENT_ROOT"], "/\\");
254 }
255 return $documentRoot;
256 }
257
267 public static function registerAutoLoadClasses($moduleName, array $classes)
268 {
269 if (empty($classes))
270 {
271 return;
272 }
273 if (($moduleName !== null) && empty($moduleName))
274 {
275 throw new LoaderException(sprintf("Module name '%s' is not correct", $moduleName));
276 }
277
278 foreach ($classes as $class => $file)
279 {
280 $class = ltrim($class, "\\");
281 $class = strtolower($class);
282
283 self::$autoLoadClasses[$class] = [
284 "module" => $moduleName,
285 "file" => $file,
286 ];
287 }
288 }
289
297 public static function registerNamespace($namespace, $path)
298 {
299 $namespace = trim($namespace, "\\")."\\";
300 $namespace = strtolower($namespace);
301
302 $path = rtrim($path, "/\\");
303 $depth = substr_count(rtrim($namespace, "\\"), "\\");
304
305 self::$namespaces[$namespace][] = [
306 "path" => $path,
307 "depth" => $depth,
308 ];
309 }
310
315 public static function unregisterNamespace($namespace)
316 {
317 $namespace = trim($namespace, "\\")."\\";
318 $namespace = strtolower($namespace);
319
320 unset(self::$namespaces[$namespace]);
321 }
322
327 public static function registerHandler(callable $handler)
328 {
329 \spl_autoload_register($handler);
330 }
331
338 public static function autoLoad($className)
339 {
340 // fix web env
341 $className = ltrim($className, "\\");
342
343 $classLower = strtolower($className);
344
345 static $documentRoot = null;
346 if ($documentRoot === null)
347 {
348 $documentRoot = self::getDocumentRoot();
349 }
350
351 //optimization via direct paths
352 if (isset(self::$autoLoadClasses[$classLower]))
353 {
354 $pathInfo = self::$autoLoadClasses[$classLower];
355 if ($pathInfo["module"] != "")
356 {
357 $module = $pathInfo["module"];
358 $holder = (isset(self::$modulesHolders[$module])? self::$modulesHolders[$module] : self::BITRIX_HOLDER);
359
360 $filePath = (defined('REPOSITORY_ROOT'))
361 ? REPOSITORY_ROOT
362 : "{$documentRoot}/{$holder}/modules";
363
364 $filePath .= '/'.$module."/".$pathInfo["file"];
365
366 require_once($filePath);
367 }
368 else
369 {
370 require_once($documentRoot.$pathInfo["file"]);
371 }
372 return;
373 }
374
375 if (preg_match("#[^\\\\/a-zA-Z0-9_]#", $className))
376 {
377 return;
378 }
379
380 $tryFiles = [[
381 "real" => $className,
382 "lower" => $classLower,
383 ]];
384
385 if (substr($classLower, -5) == "table")
386 {
387 // old *Table stored in reserved files
388 $tryFiles[] = [
389 "real" => substr($className, 0, -5),
390 "lower" => substr($classLower, 0, -5),
391 ];
392 }
393
394 foreach ($tryFiles as $classInfo)
395 {
396 $classParts = explode("\\", $classInfo["lower"]);
397
398 //remove class name
399 array_pop($classParts);
400
401 while(!empty($classParts))
402 {
403 //go from the end
404 $namespace = implode("\\", $classParts)."\\";
405
406 if(isset(self::$namespaces[$namespace]))
407 {
408 //found
409 foreach (self::$namespaces[$namespace] as $namespaceLocation)
410 {
411 $depth = $namespaceLocation["depth"];
412 $path = $namespaceLocation["path"];
413
414 $fileParts = explode("\\", $classInfo["real"]);
415
416 for ($i=0; $i <= $depth; $i++)
417 {
418 array_shift($fileParts);
419 }
420
421 $classPath = implode("/", $fileParts);
422
423 $classPathLower = strtolower($classPath);
424
425 // final path lower case
426 $filePath = $path.'/'.$classPathLower.".php";
427
428 if (file_exists($filePath))
429 {
430 require_once($filePath);
431 break 3;
432 }
433
434 // final path original case
435 $filePath = $path.'/'.$classPath.".php";
436
437 if (file_exists($filePath))
438 {
439 require_once($filePath);
440 break 3;
441 }
442 }
443 }
444
445 //try the shorter namespace
446 array_pop($classParts);
447 }
448 }
449 }
450
456 public static function requireClass($className)
457 {
458 $file = ltrim($className, "\\"); // fix web env
459 $file = strtolower($file);
460
461 if (preg_match("#[^\\\\/a-zA-Z0-9_]#", $file))
462 return;
463
464 $tryFiles = [$file];
465
466 if (substr($file, -5) == "table")
467 {
468 // old *Table stored in reserved files
469 $tryFiles[] = substr($file, 0, -5);
470 }
471
472 foreach ($tryFiles as $file)
473 {
474 $file = str_replace('\\', '/', $file);
475 $arFile = explode("/", $file);
476
477 if ($arFile[0] === "bitrix")
478 {
479 array_shift($arFile);
480
481 if (empty($arFile))
482 {
483 break;
484 }
485
486 $module = array_shift($arFile);
487 if ($module == null || empty($arFile))
488 {
489 break;
490 }
491 }
492 else
493 {
494 $module1 = array_shift($arFile);
495 $module2 = array_shift($arFile);
496
497 if ($module1 == null || $module2 == null || empty($arFile))
498 {
499 break;
500 }
501
502 $module = $module1.".".$module2;
503 }
504
505 if (!self::includeModule($module))
506 {
507 throw new LoaderException(sprintf(
508 "There is no `%s` class, module `%s` is unavailable", $className, $module
509 ));
510 }
511 }
512
513 self::autoLoad($className);
514 }
515
523 public static function getLocal($path, $root = null)
524 {
525 if ($root === null)
526 {
527 $root = self::getDocumentRoot();
528 }
529
530 if (file_exists($root."/local/".$path))
531 {
532 return $root."/local/".$path;
533 }
534 elseif (file_exists($root."/bitrix/".$path))
535 {
536 return $root."/bitrix/".$path;
537 }
538 else
539 {
540 return false;
541 }
542 }
543
551 public static function getPersonal($path)
552 {
553 $root = self::getDocumentRoot();
554 $personal = (isset($_SERVER["BX_PERSONAL_ROOT"])? $_SERVER["BX_PERSONAL_ROOT"] : "");
555
556 if ($personal <> '' && file_exists($root.$personal."/".$path))
557 {
558 return $root.$personal."/".$path;
559 }
560
561 return self::getLocal($path, $root);
562 }
563
570 {
571 self::$requireThrowException = (bool) $requireThrowException;
572 }
573}
574
575class LoaderException extends \Exception
576{
577 public function __construct($message = "", $code = 0, \Exception $previous = null)
578 {
579 parent::__construct($message, $code, $previous);
580 }
581}
__construct($message="", $code=0, \Exception $previous=null)
Definition: loader.php:577
static $modulesHolders
Definition: loader.php:23
const ALPHA_UPPER
Definition: loader.php:59
const LOCAL_HOLDER
Definition: loader.php:18
const MODULE_INSTALLED
Definition: loader.php:39
static $sharewareModules
Definition: loader.php:24
static requireModule($moduleName)
Definition: loader.php:168
const ALPHA_LOWER
Definition: loader.php:57
static getDocumentRoot()
Definition: loader.php:248
static includeModule($moduleName)
Definition: loader.php:68
const MODULE_DEMO_EXPIRED
Definition: loader.php:47
static clearModuleCache($moduleName)
Definition: loader.php:227
static $namespaces
Definition: loader.php:30
static registerHandler(callable $handler)
Definition: loader.php:327
static registerAutoLoadClasses($moduleName, array $classes)
Definition: loader.php:267
static unregisterNamespace($namespace)
Definition: loader.php:315
static registerNamespace($namespace, $path)
Definition: loader.php:297
static $autoLoadClasses
Definition: loader.php:49
static $loadedModules
Definition: loader.php:21
const MODULE_NOT_FOUND
Definition: loader.php:35
static includeSharewareModule($moduleName)
Definition: loader.php:196
static $safeModeModules
Definition: loader.php:20
static $semiloadedModules
Definition: loader.php:22
static getLocal($path, $root=null)
Definition: loader.php:523
static setRequireThrowException($requireThrowException)
Definition: loader.php:569
static getPersonal($path)
Definition: loader.php:551
static requireClass($className)
Definition: loader.php:456
const MODULE_DEMO
Definition: loader.php:43
const BITRIX_HOLDER
Definition: loader.php:17
static autoLoad($className)
Definition: loader.php:338
static $requireThrowException
Definition: loader.php:54