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