xref: /dokuwiki/inc/load.php (revision 73dc0a8919857718a3b64a4c0741b57580a34b2a)
116905344SAndreas Gohr<?php
2d4f83172SAndreas Gohr
316905344SAndreas Gohr/**
416905344SAndreas Gohr * Load all internal libraries and setup class autoloader
516905344SAndreas Gohr *
616905344SAndreas Gohr * @author Andreas Gohr <andi@splitbrain.org>
716905344SAndreas Gohr */
816905344SAndreas Gohr
94602718bSAndreas Gohrnamespace dokuwiki;
104602718bSAndreas Gohr
111935a891SAndreas Gohruse dokuwiki\Extension\PluginController;
121935a891SAndreas Gohr
134602718bSAndreas Gohrreturn new class {
144602718bSAndreas Gohr    /** @var string[] Common libraries that are always loaded */
154602718bSAndreas Gohr    protected array $commonLibs = [
164602718bSAndreas Gohr        'defines.php',
174602718bSAndreas Gohr        'actions.php',
184602718bSAndreas Gohr        'changelog.php',
194602718bSAndreas Gohr        'common.php',
204602718bSAndreas Gohr        'confutils.php',
214602718bSAndreas Gohr        'pluginutils.php',
224602718bSAndreas Gohr        'form.php',
234602718bSAndreas Gohr        'html.php',
244602718bSAndreas Gohr        'httputils.php',
254602718bSAndreas Gohr        'infoutils.php',
264602718bSAndreas Gohr        'io.php',
274602718bSAndreas Gohr        'media.php',
284602718bSAndreas Gohr        'pageutils.php',
294602718bSAndreas Gohr        'parserutils.php',
304602718bSAndreas Gohr        'search.php',
314602718bSAndreas Gohr        'template.php',
324602718bSAndreas Gohr        'toolbar.php',
334602718bSAndreas Gohr        'utf8.php',
344602718bSAndreas Gohr        'auth.php',
354602718bSAndreas Gohr        'compatibility.php',
364602718bSAndreas Gohr        'deprecated.php',
374602718bSAndreas Gohr        'legacy.php',
384602718bSAndreas Gohr    ];
3916905344SAndreas Gohr
404602718bSAndreas Gohr    /** @var string[] Classname to file mappings */
414602718bSAndreas Gohr    protected array $fixedClassNames = [
424602718bSAndreas Gohr        'Diff' => 'DifferenceEngine.php',
434602718bSAndreas Gohr        'UnifiedDiffFormatter' => 'DifferenceEngine.php',
444602718bSAndreas Gohr        'TableDiffFormatter' => 'DifferenceEngine.php',
454602718bSAndreas Gohr        'cache' => 'cache.php',
464602718bSAndreas Gohr        'cache_parser' => 'cache.php',
474602718bSAndreas Gohr        'cache_instructions' => 'cache.php',
484602718bSAndreas Gohr        'cache_renderer' => 'cache.php',
494602718bSAndreas Gohr        'JpegMeta' => 'JpegMeta.php',
504602718bSAndreas Gohr        'FeedParser' => 'FeedParser.php',
514602718bSAndreas Gohr        'SafeFN' => 'SafeFN.class.php',
524602718bSAndreas Gohr        'Mailer' => 'Mailer.class.php',
534602718bSAndreas Gohr        'Doku_Renderer' => 'parser/renderer.php',
544602718bSAndreas Gohr        'Doku_Renderer_xhtml' => 'parser/xhtml.php',
554602718bSAndreas Gohr        'Doku_Renderer_code' => 'parser/code.php',
564602718bSAndreas Gohr        'Doku_Renderer_xhtmlsummary' => 'parser/xhtmlsummary.php',
574602718bSAndreas Gohr        'Doku_Renderer_metadata' => 'parser/metadata.php'
584602718bSAndreas Gohr    ];
594602718bSAndreas Gohr
604602718bSAndreas Gohr    /**
614602718bSAndreas Gohr     * Load common libs and register autoloader
624602718bSAndreas Gohr     */
634602718bSAndreas Gohr    public function __construct()
644602718bSAndreas Gohr    {
654602718bSAndreas Gohr        require_once(DOKU_INC . 'vendor/autoload.php');
66*093fe67eSAndreas Gohr        spl_autoload_register($this->autoload(...));
674602718bSAndreas Gohr        $this->loadCommonLibs();
684602718bSAndreas Gohr    }
694602718bSAndreas Gohr
704602718bSAndreas Gohr    /**
714602718bSAndreas Gohr     * require all the common libraries
724602718bSAndreas Gohr     *
734602718bSAndreas Gohr     * @return true
744602718bSAndreas Gohr     */
754602718bSAndreas Gohr    public function loadCommonLibs()
764602718bSAndreas Gohr    {
774602718bSAndreas Gohr        foreach ($this->commonLibs as $lib) {
784602718bSAndreas Gohr            require_once(DOKU_INC . 'inc/' . $lib);
794602718bSAndreas Gohr        }
804602718bSAndreas Gohr        return true;
814602718bSAndreas Gohr    }
8216905344SAndreas Gohr
8316905344SAndreas Gohr    /**
8416905344SAndreas Gohr     * spl_autoload_register callback
8516905344SAndreas Gohr     *
864602718bSAndreas Gohr     * @param string $className
87f50a239bSTakamura     * @return bool
8816905344SAndreas Gohr     */
894602718bSAndreas Gohr    public function autoload($className)
90d868eb89SAndreas Gohr    {
91b89dfc20SAndreas Gohr        // namespace to directory conversion
924602718bSAndreas Gohr        $classPath = str_replace('\\', '/', $className);
93e7a32b17SAndreas Gohr
944602718bSAndreas Gohr        return $this->autoloadFixedClass($className)
954602718bSAndreas Gohr            || $this->autoloadTestMockClass($classPath)
964602718bSAndreas Gohr            || $this->autoloadTestClass($classPath)
974602718bSAndreas Gohr            || $this->autoloadPluginClass($classPath)
984602718bSAndreas Gohr            || $this->autoloadTemplateClass($classPath)
994602718bSAndreas Gohr            || $this->autoloadCoreClass($classPath)
1004602718bSAndreas Gohr            || $this->autoloadNamedPluginClass($className);
1014602718bSAndreas Gohr    }
1024602718bSAndreas Gohr
1034602718bSAndreas Gohr    /**
1044602718bSAndreas Gohr     * Check if the class is one of the fixed names
1054602718bSAndreas Gohr     *
1064602718bSAndreas Gohr     * @param string $className
1074602718bSAndreas Gohr     * @return bool true if the class was loaded, false otherwise
1084602718bSAndreas Gohr     */
1094602718bSAndreas Gohr    protected function autoloadFixedClass($className)
1104602718bSAndreas Gohr    {
1114602718bSAndreas Gohr        if (isset($this->fixedClassNames[$className])) {
1124602718bSAndreas Gohr            require($this->fixedClassNames[$className]);
1134602718bSAndreas Gohr            return true;
1144602718bSAndreas Gohr        }
1154602718bSAndreas Gohr        return false;
1164602718bSAndreas Gohr    }
1174602718bSAndreas Gohr
1184602718bSAndreas Gohr    /**
1194602718bSAndreas Gohr     * Check if the class is a test mock class
1204602718bSAndreas Gohr     *
1214602718bSAndreas Gohr     * @param string $classPath The class name using forward slashes as namespace separators
1224602718bSAndreas Gohr     * @return bool true if the class was loaded, false otherwise
1234602718bSAndreas Gohr     */
1244602718bSAndreas Gohr    protected function autoloadTestMockClass($classPath)
1254602718bSAndreas Gohr    {
1264602718bSAndreas Gohr        if ($this->prefixStrip($classPath, 'dokuwiki/test/mock/')) {
1274602718bSAndreas Gohr            $file = DOKU_INC . '_test/mock/' . $classPath . '.php';
128a087da71SAndreas Gohr            if (file_exists($file)) {
129a087da71SAndreas Gohr                require $file;
130a087da71SAndreas Gohr                return true;
131a087da71SAndreas Gohr            }
132a087da71SAndreas Gohr        }
1334602718bSAndreas Gohr        return false;
1344602718bSAndreas Gohr    }
135a087da71SAndreas Gohr
1364602718bSAndreas Gohr    /**
1374602718bSAndreas Gohr     * Check if the class is a test mock class
1384602718bSAndreas Gohr     *
1394602718bSAndreas Gohr     * @param string $classPath The class name using forward slashes as namespace separators
1404602718bSAndreas Gohr     * @return bool true if the class was loaded, false otherwise
1414602718bSAndreas Gohr     */
1424602718bSAndreas Gohr    protected function autoloadTestClass($classPath)
1434602718bSAndreas Gohr    {
1444602718bSAndreas Gohr        if ($this->prefixStrip($classPath, 'dokuwiki/test/')) {
1454602718bSAndreas Gohr            $file = DOKU_INC . '_test/tests/' . $classPath . '.php';
146600fb65eSAndreas Gohr            if (file_exists($file)) {
147600fb65eSAndreas Gohr                require $file;
148600fb65eSAndreas Gohr                return true;
149600fb65eSAndreas Gohr            }
150600fb65eSAndreas Gohr        }
1514602718bSAndreas Gohr        return false;
1524602718bSAndreas Gohr    }
153600fb65eSAndreas Gohr
1544602718bSAndreas Gohr    /**
1554602718bSAndreas Gohr     * Check if the class is a namespaced plugin class
1564602718bSAndreas Gohr     *
1574602718bSAndreas Gohr     * @param string $classPath The class name using forward slashes as namespace separators
1584602718bSAndreas Gohr     * @return bool true if the class was loaded, false otherwise
1594602718bSAndreas Gohr     */
1604602718bSAndreas Gohr    protected function autoloadPluginClass($classPath)
1614602718bSAndreas Gohr    {
1624602718bSAndreas Gohr        global $plugin_controller;
1634602718bSAndreas Gohr
1644602718bSAndreas Gohr        if ($this->prefixStrip($classPath, 'dokuwiki/plugin/')) {
1654602718bSAndreas Gohr            $classPath = str_replace('/test/', '/_test/', $classPath); // no underscore in test namespace
1664602718bSAndreas Gohr            $file = DOKU_PLUGIN . $classPath . '.php';
167600fb65eSAndreas Gohr            if (file_exists($file)) {
1684602718bSAndreas Gohr                $plugin = substr($classPath, 0, strpos($classPath, '/'));
1694602718bSAndreas Gohr                // don't load disabled plugin classes (only if plugin controller is available)
170ff136773SAndreas Gohr                if (!defined('DOKU_UNITTEST') && $plugin_controller && plugin_isdisabled($plugin)) return false;
1714602718bSAndreas Gohr
172ffa84f81SAndreas Gohr                try {
173600fb65eSAndreas Gohr                    require $file;
174ffa84f81SAndreas Gohr                } catch (\Throwable $e) {
1754602718bSAndreas Gohr                    ErrorHandler::showExceptionMsg($e, "Error loading plugin $plugin");
176ffa84f81SAndreas Gohr                }
177600fb65eSAndreas Gohr                return true;
178600fb65eSAndreas Gohr            }
179600fb65eSAndreas Gohr        }
1804602718bSAndreas Gohr        return false;
1814602718bSAndreas Gohr    }
182600fb65eSAndreas Gohr
1834602718bSAndreas Gohr    /**
1844602718bSAndreas Gohr     * Check if the class is a namespaced template class
1854602718bSAndreas Gohr     *
1864602718bSAndreas Gohr     * @param string $classPath The class name using forward slashes as namespace separators
1874602718bSAndreas Gohr     * @return bool true if the class was loaded, false otherwise
1884602718bSAndreas Gohr     */
1894602718bSAndreas Gohr    protected function autoloadTemplateClass($classPath)
1904602718bSAndreas Gohr    {
191f83f0fd0SAndreas Gohr        // template namespace
1924602718bSAndreas Gohr        if ($this->prefixStrip($classPath, 'dokuwiki/template/')) {
1934602718bSAndreas Gohr            $classPath = str_replace('/test/', '/_test/', $classPath); // no underscore in test namespace
1944602718bSAndreas Gohr            $file = DOKU_INC . 'lib/tpl/' . $classPath . '.php';
195f83f0fd0SAndreas Gohr            if (file_exists($file)) {
1964602718bSAndreas Gohr                $template = substr($classPath, 0, strpos($classPath, '/'));
1974602718bSAndreas Gohr
198ffa84f81SAndreas Gohr                try {
199f83f0fd0SAndreas Gohr                    require $file;
200ffa84f81SAndreas Gohr                } catch (\Throwable $e) {
2014602718bSAndreas Gohr                    ErrorHandler::showExceptionMsg($e, "Error loading template $template");
202ffa84f81SAndreas Gohr                }
203f83f0fd0SAndreas Gohr                return true;
204f83f0fd0SAndreas Gohr            }
205f83f0fd0SAndreas Gohr        }
2064602718bSAndreas Gohr        return false;
2074602718bSAndreas Gohr    }
208f83f0fd0SAndreas Gohr
2094602718bSAndreas Gohr    /**
2104602718bSAndreas Gohr     * Check if the class is a namespaced DokuWiki core class
2114602718bSAndreas Gohr     *
2124602718bSAndreas Gohr     * @param string $classPath The class name using forward slashes as namespace separators
2134602718bSAndreas Gohr     * @return bool true if the class was loaded, false otherwise
2144602718bSAndreas Gohr     */
2154602718bSAndreas Gohr    protected function autoloadCoreClass($classPath)
2164602718bSAndreas Gohr    {
2174602718bSAndreas Gohr        if ($this->prefixStrip($classPath, 'dokuwiki/')) {
2184602718bSAndreas Gohr            $file = DOKU_INC . 'inc/' . $classPath . '.php';
219b16ddc6eSAndreas Gohr            if (file_exists($file)) {
220b16ddc6eSAndreas Gohr                require $file;
221b89dfc20SAndreas Gohr                return true;
222b89dfc20SAndreas Gohr            }
223b16ddc6eSAndreas Gohr        }
2244602718bSAndreas Gohr        return false;
2254602718bSAndreas Gohr    }
226b89dfc20SAndreas Gohr
2274602718bSAndreas Gohr    /**
2284602718bSAndreas Gohr     * Check if the class is a un-namespaced plugin class following our naming scheme
2294602718bSAndreas Gohr     *
2304602718bSAndreas Gohr     * @param string $className
2314602718bSAndreas Gohr     * @return bool true if the class was loaded, false otherwise
2324602718bSAndreas Gohr     */
2334602718bSAndreas Gohr    protected function autoloadNamedPluginClass($className)
2344602718bSAndreas Gohr    {
2354602718bSAndreas Gohr        global $plugin_controller;
2364602718bSAndreas Gohr
2377d34963bSAndreas Gohr        if (
2387d34963bSAndreas Gohr            preg_match(
2391935a891SAndreas Gohr                '/^(' . implode('|', PluginController::PLUGIN_TYPES) . ')_plugin_(' .
24064159a61SAndreas Gohr                DOKU_PLUGIN_NAME_REGEX .
24164159a61SAndreas Gohr                ')(?:_([^_]+))?$/',
2424602718bSAndreas Gohr                $className,
24364159a61SAndreas Gohr                $m
2447d34963bSAndreas Gohr            )
2457d34963bSAndreas Gohr        ) {
246d54ac877SAdrian Lang            $c = ((count($m) === 4) ? "/{$m[3]}" : '');
2475a9866e9SAndreas Gohr            $plg = DOKU_PLUGIN . "{$m[2]}/{$m[1]}$c.php";
24879e79377SAndreas Gohr            if (file_exists($plg)) {
2494602718bSAndreas Gohr                // don't load disabled plugin classes (only if plugin controller is available)
250ff136773SAndreas Gohr                if (!defined('DOKU_UNITTEST') && $plugin_controller && plugin_isdisabled($m[2])) return false;
251ffa84f81SAndreas Gohr                try {
252ce949263SAndreas Gohr                    require $plg;
253ffa84f81SAndreas Gohr                } catch (\Throwable $e) {
25424870174SAndreas Gohr                    ErrorHandler::showExceptionMsg($e, "Error loading plugin {$m[2]}");
255ffa84f81SAndreas Gohr                }
2565a9866e9SAndreas Gohr            }
2578a58013eSDavid Stone            return true;
258d54ac877SAdrian Lang        }
259ce949263SAndreas Gohr        return false;
26016905344SAndreas Gohr    }
26116905344SAndreas Gohr
2624602718bSAndreas Gohr    /**
2634602718bSAndreas Gohr     * Check if the given string starts with the given prefix and strip it
2644602718bSAndreas Gohr     *
2654602718bSAndreas Gohr     * @param string $string
2664602718bSAndreas Gohr     * @param string $prefix
2674602718bSAndreas Gohr     * @return bool true if the prefix was found and stripped, false otherwise
2684602718bSAndreas Gohr     */
2694602718bSAndreas Gohr    protected function prefixStrip(&$string, $prefix)
2704602718bSAndreas Gohr    {
2714602718bSAndreas Gohr        if (str_starts_with($string, $prefix)) {
2724602718bSAndreas Gohr            $string = substr($string, strlen($prefix));
2734602718bSAndreas Gohr            return true;
2744602718bSAndreas Gohr        }
2754602718bSAndreas Gohr        return false;
2764602718bSAndreas Gohr    }
2774602718bSAndreas Gohr};
278