PageRenderTime 54ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/bitrix/modules/main/lib/loader.php

https://gitlab.com/Rad1calDreamer/honey
PHP | 383 lines | 279 code | 46 blank | 58 comment | 44 complexity | 6e0032bf2bdc366a8a0cfd47b542cb60 MD5 | raw file
  1. <?php
  2. namespace Bitrix\Main;
  3. /**
  4. * Class Loader loads required files, classes and modules. It is the only class which is included directly.
  5. * @package Bitrix\Main
  6. */
  7. final class Loader
  8. {
  9. /**
  10. * Can be used to prevent loading all modules except main and fileman
  11. */
  12. const SAFE_MODE = false;
  13. const BITRIX_HOLDER = "bitrix";
  14. const LOCAL_HOLDER = "local";
  15. private static $safeModeModules = array("main", "fileman");
  16. private static $arLoadedModules = array("main" => true);
  17. private static $arSemiloadedModules = array();
  18. private static $arLoadedModulesHolders = array("main" => self::BITRIX_HOLDER);
  19. private static $arSharewareModules = array();
  20. /**
  21. * Returned by includeSharewareModule() if module is not found
  22. */
  23. const MODULE_NOT_FOUND = 0;
  24. /**
  25. * Returned by includeSharewareModule() if module is installed
  26. */
  27. const MODULE_INSTALLED = 1;
  28. /**
  29. * Returned by includeSharewareModule() if module works in demo mode
  30. */
  31. const MODULE_DEMO = 2;
  32. /**
  33. * Returned by includeSharewareModule() if the trial period is expired
  34. */
  35. const MODULE_DEMO_EXPIRED = 3;
  36. private static $arAutoLoadClasses = array();
  37. private static $isAutoLoadOn = true;
  38. const ALPHA_LOWER = "qwertyuioplkjhgfdsazxcvbnm";
  39. const ALPHA_UPPER = "QWERTYUIOPLKJHGFDSAZXCVBNM";
  40. /**
  41. * Includes module by its name
  42. *
  43. * @param string $moduleName Name of the included module
  44. * @return bool Returns true if module was included successfully, otherwise returns false
  45. * @throws LoaderException
  46. */
  47. public static function includeModule($moduleName)
  48. {
  49. if (!is_string($moduleName) || $moduleName == "")
  50. throw new LoaderException("Empty module name");
  51. if (preg_match("#[^a-zA-Z0-9._]#", $moduleName))
  52. throw new LoaderException(sprintf("Module name '%s' is not correct", $moduleName));
  53. $moduleName = strtr($moduleName, static::ALPHA_UPPER, static::ALPHA_LOWER);
  54. if (self::SAFE_MODE)
  55. {
  56. if (!in_array($moduleName, self::$safeModeModules))
  57. return false;
  58. }
  59. if (isset(self::$arLoadedModules[$moduleName]))
  60. return self::$arLoadedModules[$moduleName];
  61. if (isset(self::$arSemiloadedModules[$moduleName]))
  62. trigger_error("Module '".$moduleName."' is in loading progress", E_USER_WARNING);
  63. $arInstalledModules = ModuleManager::getInstalledModules();
  64. if (!isset($arInstalledModules[$moduleName]))
  65. return self::$arLoadedModules[$moduleName] = false;
  66. $documentRoot = static::getDocumentRoot();
  67. $moduleHolder = self::LOCAL_HOLDER;
  68. $pathToInclude = $documentRoot."/".$moduleHolder."/modules/".$moduleName."/include.php";
  69. if (!file_exists($pathToInclude))
  70. {
  71. $moduleHolder = self::BITRIX_HOLDER;
  72. $pathToInclude = $documentRoot."/".$moduleHolder."/modules/".$moduleName."/include.php";
  73. if (!file_exists($pathToInclude))
  74. return self::$arLoadedModules[$moduleName] = false;
  75. }
  76. self::$arLoadedModulesHolders[$moduleName] = $moduleHolder;
  77. self::$arSemiloadedModules[$moduleName] = true;
  78. $res = self::includeModuleInternal($pathToInclude);
  79. unset(self::$arSemiloadedModules[$moduleName]);
  80. if ($res === false)
  81. return self::$arLoadedModules[$moduleName] = false;
  82. return self::$arLoadedModules[$moduleName] = true;
  83. }
  84. private static function includeModuleInternal($path)
  85. {
  86. /** @noinspection PhpUnusedLocalVariableInspection */
  87. global $DB, $MESS;
  88. return include_once($path);
  89. }
  90. /**
  91. * Includes shareware module by its name.
  92. * Module must initialize constant <module name>_DEMO = Y in include.php to define demo mode.
  93. * include.php must return false to define trial period expiration.
  94. * Constants is used because it is easy to obfuscate them.
  95. *
  96. * @param string $moduleName Name of the included module
  97. * @return int One of the following constant: Loader::MODULE_NOT_FOUND, Loader::MODULE_INSTALLED, Loader::MODULE_DEMO, Loader::MODULE_DEMO_EXPIRED
  98. */
  99. public static function includeSharewareModule($moduleName)
  100. {
  101. if (isset(self::$arSharewareModules[$moduleName]))
  102. return self::$arSharewareModules[$moduleName];
  103. $moduleNameTmp = str_replace(".", "_", $moduleName);
  104. if (self::includeModule($moduleName))
  105. {
  106. if (defined($moduleNameTmp."_DEMO") && constant($moduleNameTmp."_DEMO") == "Y")
  107. self::$arSharewareModules[$moduleName] = self::MODULE_DEMO;
  108. else
  109. self::$arSharewareModules[$moduleName] = self::MODULE_INSTALLED;
  110. return self::$arSharewareModules[$moduleName];
  111. }
  112. if (defined($moduleNameTmp."_DEMO") && constant($moduleNameTmp."_DEMO") == "Y")
  113. return self::$arSharewareModules[$moduleName] = self::MODULE_DEMO_EXPIRED;
  114. return self::$arSharewareModules[$moduleName] = self::MODULE_NOT_FOUND;
  115. }
  116. public static function clearModuleCache($moduleName)
  117. {
  118. if (!is_string($moduleName) || $moduleName == "")
  119. throw new LoaderException("Empty module name");
  120. if($moduleName !== "main")
  121. {
  122. unset(static::$arLoadedModules[$moduleName]);
  123. unset(static::$arLoadedModulesHolders[$moduleName]);
  124. }
  125. if (isset(static::$arSharewareModules[$moduleName]))
  126. unset(static::$arSharewareModules[$moduleName]);
  127. }
  128. /**
  129. * Returns document root
  130. *
  131. * @return string Document root
  132. */
  133. public static function getDocumentRoot()
  134. {
  135. static $documentRoot = null;
  136. if ($documentRoot === null)
  137. $documentRoot = rtrim($_SERVER["DOCUMENT_ROOT"], "/\\");
  138. return $documentRoot;
  139. }
  140. public static function switchAutoLoad($value = true)
  141. {
  142. static::$isAutoLoadOn = $value;
  143. }
  144. /**
  145. * Registers classes for auto loading.
  146. * All the frequently used classes should be registered for auto loading (performance).
  147. * It is not necessary to register rarely used classes. They can be found and loaded dynamically.
  148. *
  149. * @param string $moduleName Name of the module. Can be null if classes are not part of any module
  150. * @param array $arClasses Array of classes with class names as keys and paths as values.
  151. * @throws LoaderException
  152. */
  153. public static function registerAutoLoadClasses($moduleName, array $arClasses)
  154. {
  155. if (empty($arClasses))
  156. return;
  157. if (($moduleName !== null) && empty($moduleName))
  158. {
  159. throw new LoaderException(sprintf("Module name '%s' is not correct", $moduleName));
  160. }
  161. if (!static::$isAutoLoadOn)
  162. {
  163. if (!is_null($moduleName) && !isset(static::$arLoadedModulesHolders[$moduleName]))
  164. throw new LoaderException(sprintf("Holder of module '%s' is not found", $moduleName));
  165. $documentRoot = static::getDocumentRoot();
  166. if (!is_null($moduleName))
  167. {
  168. foreach ($arClasses as $value)
  169. {
  170. if (file_exists($documentRoot."/".self::$arLoadedModulesHolders[$moduleName]."/modules/".$moduleName."/".$value))
  171. require_once($documentRoot."/".self::$arLoadedModulesHolders[$moduleName]."/modules/".$moduleName."/".$value);
  172. }
  173. }
  174. else
  175. {
  176. foreach ($arClasses as $value)
  177. {
  178. if (($includePath = self::getLocal($value, $documentRoot)) !== false)
  179. require_once($includePath);
  180. }
  181. }
  182. }
  183. else
  184. {
  185. foreach ($arClasses as $key => $value)
  186. {
  187. $class = ltrim($key, "\\");
  188. self::$arAutoLoadClasses[strtr($class, static::ALPHA_UPPER, static::ALPHA_LOWER)] = array(
  189. "module" => $moduleName,
  190. "file" => $value
  191. );
  192. }
  193. }
  194. }
  195. public static function isAutoLoadClassRegistered($className)
  196. {
  197. $className = trim(ltrim($className, "\\"));
  198. if ($className == '')
  199. return false;
  200. $className = strtr($className, static::ALPHA_UPPER, static::ALPHA_LOWER);
  201. return isset(self::$arAutoLoadClasses[$className]);
  202. }
  203. /**
  204. * \Bitrix\Main\IO\File -> /main/lib/io/file.php
  205. * \Bitrix\IBlock\Type -> /iblock/lib/type.php
  206. * \Bitrix\IBlock\Section\Type -> /iblock/lib/section/type.php
  207. * \QSoft\Catalog\Tools\File -> /qsoft.catalog/lib/tools/file.php
  208. *
  209. * @param $className
  210. */
  211. public static function autoLoad($className)
  212. {
  213. $file = ltrim($className, "\\"); // fix web env
  214. $file = strtr($file, static::ALPHA_UPPER, static::ALPHA_LOWER);
  215. static $documentRoot = null;
  216. if ($documentRoot === null)
  217. $documentRoot = static::getDocumentRoot();
  218. if (isset(self::$arAutoLoadClasses[$file]))
  219. {
  220. $pathInfo = self::$arAutoLoadClasses[$file];
  221. if ($pathInfo["module"] != "")
  222. {
  223. $m = $pathInfo["module"];
  224. $h = isset(self::$arLoadedModulesHolders[$m]) ? self::$arLoadedModulesHolders[$m] : 'bitrix';
  225. include_once($documentRoot."/".$h."/modules/".$m."/" .$pathInfo["file"]);
  226. }
  227. else
  228. {
  229. require_once($documentRoot.$pathInfo["file"]);
  230. }
  231. return;
  232. }
  233. if (preg_match("#[^\\\\/a-zA-Z0-9_]#", $file))
  234. return;
  235. if (substr($file, -5) == "table")
  236. $file = substr($file, 0, -5);
  237. $file = str_replace('\\', '/', $file);
  238. $arFile = explode("/", $file);
  239. if ($arFile[0] === "bitrix")
  240. {
  241. array_shift($arFile);
  242. if (empty($arFile))
  243. return;
  244. $module = array_shift($arFile);
  245. if ($module == null || empty($arFile))
  246. return;
  247. }
  248. else
  249. {
  250. $module1 = array_shift($arFile);
  251. $module2 = array_shift($arFile);
  252. if ($module1 == null || $module2 == null || empty($arFile))
  253. return;
  254. $module = $module1.".".$module2;
  255. }
  256. if (!isset(self::$arLoadedModulesHolders[$module]))
  257. return;
  258. $filePath = $documentRoot."/".self::$arLoadedModulesHolders[$module]."/modules/".$module."/lib/".implode("/", $arFile).".php";
  259. if (file_exists($filePath))
  260. require_once($filePath);
  261. }
  262. /**
  263. * Checks if file exists in /local or /bitrix directories
  264. *
  265. * @param string $path File path relative to /local/ or /bitrix/
  266. * @param string $root Server document root, default static::getDocumentRoot()
  267. * @return string|bool Returns combined path or false if the file does not exist in both dirs
  268. */
  269. public static function getLocal($path, $root = null)
  270. {
  271. if ($root === null)
  272. $root = static::getDocumentRoot();
  273. if (file_exists($root."/local/".$path))
  274. return $root."/local/".$path;
  275. elseif (file_exists($root."/bitrix/".$path))
  276. return $root."/bitrix/".$path;
  277. else
  278. return false;
  279. }
  280. /**
  281. * Checks if file exists in personal directory.
  282. * If $_SERVER["BX_PERSONAL_ROOT"] is not set than personal directory is equal to /bitrix/
  283. *
  284. * @param string $path File path relative to personal directory
  285. * @return string|bool Returns combined path or false if the file does not exist
  286. */
  287. public static function getPersonal($path)
  288. {
  289. $root = static::getDocumentRoot();
  290. $personal = isset($_SERVER["BX_PERSONAL_ROOT"]) ? $_SERVER["BX_PERSONAL_ROOT"] : "";
  291. if (!empty($personal) && file_exists($root.$personal."/".$path))
  292. return $root.$personal."/".$path;
  293. return self::getLocal($path, $root);
  294. }
  295. }
  296. class LoaderException
  297. extends \Exception
  298. {
  299. public function __construct($message = "", $code = 0, \Exception $previous = null)
  300. {
  301. parent::__construct($message, $code, $previous);
  302. }
  303. }
  304. if (!function_exists("__autoload"))
  305. {
  306. if (function_exists('spl_autoload_register'))
  307. {
  308. \spl_autoload_register('\Bitrix\Main\Loader::autoLoad');
  309. }
  310. else
  311. {
  312. function __autoload($className)
  313. {
  314. Loader::autoLoad($className);
  315. }
  316. }
  317. Loader::switchAutoLoad(true);
  318. }
  319. else
  320. {
  321. Loader::switchAutoLoad(false);
  322. }