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