You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

284 lines
8.8 KiB

  1. <?php
  2. /**
  3. * Load all internal libraries and setup class autoloader
  4. *
  5. * @author Andreas Gohr <andi@splitbrain.org>
  6. */
  7. namespace dokuwiki;
  8. use dokuwiki\Extension\PluginController;
  9. return new class {
  10. /** @var string[] Common libraries that are always loaded */
  11. protected array $commonLibs = [
  12. 'defines.php',
  13. 'actions.php',
  14. 'changelog.php',
  15. 'common.php',
  16. 'confutils.php',
  17. 'pluginutils.php',
  18. 'form.php',
  19. 'fulltext.php',
  20. 'html.php',
  21. 'httputils.php',
  22. 'indexer.php',
  23. 'infoutils.php',
  24. 'io.php',
  25. 'mail.php',
  26. 'media.php',
  27. 'pageutils.php',
  28. 'parserutils.php',
  29. 'search.php',
  30. 'template.php',
  31. 'toolbar.php',
  32. 'utf8.php',
  33. 'auth.php',
  34. 'compatibility.php',
  35. 'deprecated.php',
  36. 'legacy.php',
  37. ];
  38. /** @var string[] Classname to file mappings */
  39. protected array $fixedClassNames = [
  40. 'Diff' => 'DifferenceEngine.php',
  41. 'UnifiedDiffFormatter' => 'DifferenceEngine.php',
  42. 'TableDiffFormatter' => 'DifferenceEngine.php',
  43. 'cache' => 'cache.php',
  44. 'cache_parser' => 'cache.php',
  45. 'cache_instructions' => 'cache.php',
  46. 'cache_renderer' => 'cache.php',
  47. 'Input' => 'Input.class.php',
  48. 'JpegMeta' => 'JpegMeta.php',
  49. 'SimplePie' => 'SimplePie.php',
  50. 'FeedParser' => 'FeedParser.php',
  51. 'SafeFN' => 'SafeFN.class.php',
  52. 'Mailer' => 'Mailer.class.php',
  53. 'Doku_Handler' => 'parser/handler.php',
  54. 'Doku_Renderer' => 'parser/renderer.php',
  55. 'Doku_Renderer_xhtml' => 'parser/xhtml.php',
  56. 'Doku_Renderer_code' => 'parser/code.php',
  57. 'Doku_Renderer_xhtmlsummary' => 'parser/xhtmlsummary.php',
  58. 'Doku_Renderer_metadata' => 'parser/metadata.php'
  59. ];
  60. /**
  61. * Load common libs and register autoloader
  62. */
  63. public function __construct()
  64. {
  65. require_once(DOKU_INC . 'vendor/autoload.php');
  66. spl_autoload_register([$this, 'autoload']);
  67. $this->loadCommonLibs();
  68. }
  69. /**
  70. * require all the common libraries
  71. *
  72. * @return true
  73. */
  74. public function loadCommonLibs()
  75. {
  76. foreach ($this->commonLibs as $lib) {
  77. require_once(DOKU_INC . 'inc/' . $lib);
  78. }
  79. return true;
  80. }
  81. /**
  82. * spl_autoload_register callback
  83. *
  84. * @param string $className
  85. * @return bool
  86. */
  87. public function autoload($className)
  88. {
  89. // namespace to directory conversion
  90. $classPath = str_replace('\\', '/', $className);
  91. return $this->autoloadFixedClass($className)
  92. || $this->autoloadTestMockClass($classPath)
  93. || $this->autoloadTestClass($classPath)
  94. || $this->autoloadPluginClass($classPath)
  95. || $this->autoloadTemplateClass($classPath)
  96. || $this->autoloadCoreClass($classPath)
  97. || $this->autoloadNamedPluginClass($className);
  98. }
  99. /**
  100. * Check if the class is one of the fixed names
  101. *
  102. * @param string $className
  103. * @return bool true if the class was loaded, false otherwise
  104. */
  105. protected function autoloadFixedClass($className)
  106. {
  107. if (isset($this->fixedClassNames[$className])) {
  108. require($this->fixedClassNames[$className]);
  109. return true;
  110. }
  111. return false;
  112. }
  113. /**
  114. * Check if the class is a test mock class
  115. *
  116. * @param string $classPath The class name using forward slashes as namespace separators
  117. * @return bool true if the class was loaded, false otherwise
  118. */
  119. protected function autoloadTestMockClass($classPath)
  120. {
  121. if ($this->prefixStrip($classPath, 'dokuwiki/test/mock/')) {
  122. $file = DOKU_INC . '_test/mock/' . $classPath . '.php';
  123. if (file_exists($file)) {
  124. require $file;
  125. return true;
  126. }
  127. }
  128. return false;
  129. }
  130. /**
  131. * Check if the class is a test mock class
  132. *
  133. * @param string $classPath The class name using forward slashes as namespace separators
  134. * @return bool true if the class was loaded, false otherwise
  135. */
  136. protected function autoloadTestClass($classPath)
  137. {
  138. if ($this->prefixStrip($classPath, 'dokuwiki/test/')) {
  139. $file = DOKU_INC . '_test/tests/' . $classPath . '.php';
  140. if (file_exists($file)) {
  141. require $file;
  142. return true;
  143. }
  144. }
  145. return false;
  146. }
  147. /**
  148. * Check if the class is a namespaced plugin class
  149. *
  150. * @param string $classPath The class name using forward slashes as namespace separators
  151. * @return bool true if the class was loaded, false otherwise
  152. */
  153. protected function autoloadPluginClass($classPath)
  154. {
  155. global $plugin_controller;
  156. if ($this->prefixStrip($classPath, 'dokuwiki/plugin/')) {
  157. $classPath = str_replace('/test/', '/_test/', $classPath); // no underscore in test namespace
  158. $file = DOKU_PLUGIN . $classPath . '.php';
  159. if (file_exists($file)) {
  160. $plugin = substr($classPath, 0, strpos($classPath, '/'));
  161. // don't load disabled plugin classes (only if plugin controller is available)
  162. if (!defined('DOKU_UNITTEST') && $plugin_controller && plugin_isdisabled($plugin)) return false;
  163. try {
  164. require $file;
  165. } catch (\Throwable $e) {
  166. ErrorHandler::showExceptionMsg($e, "Error loading plugin $plugin");
  167. }
  168. return true;
  169. }
  170. }
  171. return false;
  172. }
  173. /**
  174. * Check if the class is a namespaced template class
  175. *
  176. * @param string $classPath The class name using forward slashes as namespace separators
  177. * @return bool true if the class was loaded, false otherwise
  178. */
  179. protected function autoloadTemplateClass($classPath)
  180. {
  181. // template namespace
  182. if ($this->prefixStrip($classPath, 'dokuwiki/template/')) {
  183. $classPath = str_replace('/test/', '/_test/', $classPath); // no underscore in test namespace
  184. $file = DOKU_INC . 'lib/tpl/' . $classPath . '.php';
  185. if (file_exists($file)) {
  186. $template = substr($classPath, 0, strpos($classPath, '/'));
  187. try {
  188. require $file;
  189. } catch (\Throwable $e) {
  190. ErrorHandler::showExceptionMsg($e, "Error loading template $template");
  191. }
  192. return true;
  193. }
  194. }
  195. return false;
  196. }
  197. /**
  198. * Check if the class is a namespaced DokuWiki core class
  199. *
  200. * @param string $classPath The class name using forward slashes as namespace separators
  201. * @return bool true if the class was loaded, false otherwise
  202. */
  203. protected function autoloadCoreClass($classPath)
  204. {
  205. if ($this->prefixStrip($classPath, 'dokuwiki/')) {
  206. $file = DOKU_INC . 'inc/' . $classPath . '.php';
  207. if (file_exists($file)) {
  208. require $file;
  209. return true;
  210. }
  211. }
  212. return false;
  213. }
  214. /**
  215. * Check if the class is a un-namespaced plugin class following our naming scheme
  216. *
  217. * @param string $className
  218. * @return bool true if the class was loaded, false otherwise
  219. */
  220. protected function autoloadNamedPluginClass($className)
  221. {
  222. global $plugin_controller;
  223. if (
  224. preg_match(
  225. '/^(' . implode('|', PluginController::PLUGIN_TYPES) . ')_plugin_(' .
  226. DOKU_PLUGIN_NAME_REGEX .
  227. ')(?:_([^_]+))?$/',
  228. $className,
  229. $m
  230. )
  231. ) {
  232. $c = ((count($m) === 4) ? "/{$m[3]}" : '');
  233. $plg = DOKU_PLUGIN . "{$m[2]}/{$m[1]}$c.php";
  234. if (file_exists($plg)) {
  235. // don't load disabled plugin classes (only if plugin controller is available)
  236. if (!defined('DOKU_UNITTEST') && $plugin_controller && plugin_isdisabled($m[2])) return false;
  237. try {
  238. require $plg;
  239. } catch (\Throwable $e) {
  240. ErrorHandler::showExceptionMsg($e, "Error loading plugin {$m[2]}");
  241. }
  242. }
  243. return true;
  244. }
  245. return false;
  246. }
  247. /**
  248. * Check if the given string starts with the given prefix and strip it
  249. *
  250. * @param string $string
  251. * @param string $prefix
  252. * @return bool true if the prefix was found and stripped, false otherwise
  253. */
  254. protected function prefixStrip(&$string, $prefix)
  255. {
  256. if (str_starts_with($string, $prefix)) {
  257. $string = substr($string, strlen($prefix));
  258. return true;
  259. }
  260. return false;
  261. }
  262. };