xref: /dokuwiki/inc/load.php (revision ff136773483830fd139a631f357b7ded1ae77b11)
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 */
8d4f83172SAndreas 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        'fulltext.php',
244602718bSAndreas Gohr        'html.php',
254602718bSAndreas Gohr        'httputils.php',
264602718bSAndreas Gohr        'indexer.php',
274602718bSAndreas Gohr        'infoutils.php',
284602718bSAndreas Gohr        'io.php',
294602718bSAndreas Gohr        'mail.php',
304602718bSAndreas Gohr        'media.php',
314602718bSAndreas Gohr        'pageutils.php',
324602718bSAndreas Gohr        'parserutils.php',
334602718bSAndreas Gohr        'search.php',
344602718bSAndreas Gohr        'template.php',
354602718bSAndreas Gohr        'toolbar.php',
364602718bSAndreas Gohr        'utf8.php',
374602718bSAndreas Gohr        'auth.php',
384602718bSAndreas Gohr        'compatibility.php',
394602718bSAndreas Gohr        'deprecated.php',
404602718bSAndreas Gohr        'legacy.php',
414602718bSAndreas Gohr    ];
4216905344SAndreas Gohr
434602718bSAndreas Gohr    /** @var string[] Classname to file mappings */
444602718bSAndreas Gohr    protected array $fixedClassNames = [
454602718bSAndreas Gohr        'Diff' => 'DifferenceEngine.php',
464602718bSAndreas Gohr        'UnifiedDiffFormatter' => 'DifferenceEngine.php',
474602718bSAndreas Gohr        'TableDiffFormatter' => 'DifferenceEngine.php',
484602718bSAndreas Gohr        'cache' => 'cache.php',
494602718bSAndreas Gohr        'cache_parser' => 'cache.php',
504602718bSAndreas Gohr        'cache_instructions' => 'cache.php',
514602718bSAndreas Gohr        'cache_renderer' => 'cache.php',
524602718bSAndreas Gohr        'Input' => 'Input.class.php',
534602718bSAndreas Gohr        'JpegMeta' => 'JpegMeta.php',
544602718bSAndreas Gohr        'SimplePie' => 'SimplePie.php',
554602718bSAndreas Gohr        'FeedParser' => 'FeedParser.php',
564602718bSAndreas Gohr        'SafeFN' => 'SafeFN.class.php',
574602718bSAndreas Gohr        'Mailer' => 'Mailer.class.php',
584602718bSAndreas Gohr        'Doku_Handler' => 'parser/handler.php',
594602718bSAndreas Gohr        'Doku_Renderer' => 'parser/renderer.php',
604602718bSAndreas Gohr        'Doku_Renderer_xhtml' => 'parser/xhtml.php',
614602718bSAndreas Gohr        'Doku_Renderer_code' => 'parser/code.php',
624602718bSAndreas Gohr        'Doku_Renderer_xhtmlsummary' => 'parser/xhtmlsummary.php',
634602718bSAndreas Gohr        'Doku_Renderer_metadata' => 'parser/metadata.php'
644602718bSAndreas Gohr    ];
654602718bSAndreas Gohr
664602718bSAndreas Gohr    /**
674602718bSAndreas Gohr     * Load common libs and register autoloader
684602718bSAndreas Gohr     */
694602718bSAndreas Gohr    public function __construct()
704602718bSAndreas Gohr    {
714602718bSAndreas Gohr        require_once(DOKU_INC . 'vendor/autoload.php');
724602718bSAndreas Gohr        spl_autoload_register([$this, 'autoload']);
734602718bSAndreas Gohr        $this->loadCommonLibs();
744602718bSAndreas Gohr    }
754602718bSAndreas Gohr
764602718bSAndreas Gohr    /**
774602718bSAndreas Gohr     * require all the common libraries
784602718bSAndreas Gohr     *
794602718bSAndreas Gohr     * @return true
804602718bSAndreas Gohr     */
814602718bSAndreas Gohr    public function loadCommonLibs()
824602718bSAndreas Gohr    {
834602718bSAndreas Gohr        foreach ($this->commonLibs as $lib) {
844602718bSAndreas Gohr            require_once(DOKU_INC . 'inc/' . $lib);
854602718bSAndreas Gohr        }
864602718bSAndreas Gohr        return true;
874602718bSAndreas Gohr    }
8816905344SAndreas Gohr
8916905344SAndreas Gohr    /**
9016905344SAndreas Gohr     * spl_autoload_register callback
9116905344SAndreas Gohr     *
924602718bSAndreas Gohr     * @param string $className
93f50a239bSTakamura     * @return bool
9416905344SAndreas Gohr     */
954602718bSAndreas Gohr    public function autoload($className)
96d868eb89SAndreas Gohr    {
97b89dfc20SAndreas Gohr        // namespace to directory conversion
984602718bSAndreas Gohr        $classPath = str_replace('\\', '/', $className);
99e7a32b17SAndreas Gohr
1004602718bSAndreas Gohr        return $this->autoloadFixedClass($className)
1014602718bSAndreas Gohr            || $this->autoloadTestMockClass($classPath)
1024602718bSAndreas Gohr            || $this->autoloadTestClass($classPath)
1034602718bSAndreas Gohr            || $this->autoloadPluginClass($classPath)
1044602718bSAndreas Gohr            || $this->autoloadTemplateClass($classPath)
1054602718bSAndreas Gohr            || $this->autoloadCoreClass($classPath)
1064602718bSAndreas Gohr            || $this->autoloadNamedPluginClass($className);
1074602718bSAndreas Gohr    }
1084602718bSAndreas Gohr
1094602718bSAndreas Gohr    /**
1104602718bSAndreas Gohr     * Check if the class is one of the fixed names
1114602718bSAndreas Gohr     *
1124602718bSAndreas Gohr     * @param string $className
1134602718bSAndreas Gohr     * @return bool true if the class was loaded, false otherwise
1144602718bSAndreas Gohr     */
1154602718bSAndreas Gohr    protected function autoloadFixedClass($className)
1164602718bSAndreas Gohr    {
1174602718bSAndreas Gohr        if (isset($this->fixedClassNames[$className])) {
1184602718bSAndreas Gohr            require($this->fixedClassNames[$className]);
1194602718bSAndreas Gohr            return true;
1204602718bSAndreas Gohr        }
1214602718bSAndreas Gohr        return false;
1224602718bSAndreas Gohr    }
1234602718bSAndreas Gohr
1244602718bSAndreas Gohr    /**
1254602718bSAndreas Gohr     * Check if the class is a test mock class
1264602718bSAndreas Gohr     *
1274602718bSAndreas Gohr     * @param string $classPath The class name using forward slashes as namespace separators
1284602718bSAndreas Gohr     * @return bool true if the class was loaded, false otherwise
1294602718bSAndreas Gohr     */
1304602718bSAndreas Gohr    protected function autoloadTestMockClass($classPath)
1314602718bSAndreas Gohr    {
1324602718bSAndreas Gohr        if ($this->prefixStrip($classPath, 'dokuwiki/test/mock/')) {
1334602718bSAndreas Gohr            $file = DOKU_INC . '_test/mock/' . $classPath . '.php';
134ec85aeb2SAndreas Gohr            if (file_exists($file)) {
135ec85aeb2SAndreas Gohr                require $file;
136ec85aeb2SAndreas Gohr                return true;
137ec85aeb2SAndreas Gohr            }
138ec85aeb2SAndreas Gohr        }
1394602718bSAndreas Gohr        return false;
1404602718bSAndreas Gohr    }
141ec85aeb2SAndreas Gohr
1424602718bSAndreas Gohr    /**
1434602718bSAndreas Gohr     * Check if the class is a test mock class
1444602718bSAndreas Gohr     *
1454602718bSAndreas Gohr     * @param string $classPath The class name using forward slashes as namespace separators
1464602718bSAndreas Gohr     * @return bool true if the class was loaded, false otherwise
1474602718bSAndreas Gohr     */
1484602718bSAndreas Gohr    protected function autoloadTestClass($classPath)
1494602718bSAndreas Gohr    {
1504602718bSAndreas Gohr        if ($this->prefixStrip($classPath, 'dokuwiki/test/')) {
1514602718bSAndreas Gohr            $file = DOKU_INC . '_test/tests/' . $classPath . '.php';
152a087da71SAndreas Gohr            if (file_exists($file)) {
153a087da71SAndreas Gohr                require $file;
154a087da71SAndreas Gohr                return true;
155a087da71SAndreas Gohr            }
156a087da71SAndreas Gohr        }
1574602718bSAndreas Gohr        return false;
1584602718bSAndreas Gohr    }
159a087da71SAndreas Gohr
1604602718bSAndreas Gohr    /**
1614602718bSAndreas Gohr     * Check if the class is a namespaced plugin class
1624602718bSAndreas Gohr     *
1634602718bSAndreas Gohr     * @param string $classPath The class name using forward slashes as namespace separators
1644602718bSAndreas Gohr     * @return bool true if the class was loaded, false otherwise
1654602718bSAndreas Gohr     */
1664602718bSAndreas Gohr    protected function autoloadPluginClass($classPath)
1674602718bSAndreas Gohr    {
1684602718bSAndreas Gohr        global $plugin_controller;
1694602718bSAndreas Gohr
1704602718bSAndreas Gohr        if ($this->prefixStrip($classPath, 'dokuwiki/plugin/')) {
1714602718bSAndreas Gohr            $classPath = str_replace('/test/', '/_test/', $classPath); // no underscore in test namespace
1724602718bSAndreas Gohr            $file = DOKU_PLUGIN . $classPath . '.php';
173600fb65eSAndreas Gohr            if (file_exists($file)) {
1744602718bSAndreas Gohr                $plugin = substr($classPath, 0, strpos($classPath, '/'));
1754602718bSAndreas Gohr                // don't load disabled plugin classes (only if plugin controller is available)
176*ff136773SAndreas Gohr                if (!defined('DOKU_UNITTEST') && $plugin_controller && plugin_isdisabled($plugin)) return false;
1774602718bSAndreas Gohr
178ffa84f81SAndreas Gohr                try {
179600fb65eSAndreas Gohr                    require $file;
180ffa84f81SAndreas Gohr                } catch (\Throwable $e) {
1814602718bSAndreas Gohr                    ErrorHandler::showExceptionMsg($e, "Error loading plugin $plugin");
182ffa84f81SAndreas Gohr                }
183600fb65eSAndreas Gohr                return true;
184600fb65eSAndreas Gohr            }
185600fb65eSAndreas Gohr        }
1864602718bSAndreas Gohr        return false;
1874602718bSAndreas Gohr    }
188600fb65eSAndreas Gohr
1894602718bSAndreas Gohr    /**
1904602718bSAndreas Gohr     * Check if the class is a namespaced template class
1914602718bSAndreas Gohr     *
1924602718bSAndreas Gohr     * @param string $classPath The class name using forward slashes as namespace separators
1934602718bSAndreas Gohr     * @return bool true if the class was loaded, false otherwise
1944602718bSAndreas Gohr     */
1954602718bSAndreas Gohr    protected function autoloadTemplateClass($classPath)
1964602718bSAndreas Gohr    {
197f83f0fd0SAndreas Gohr        // template namespace
1984602718bSAndreas Gohr        if ($this->prefixStrip($classPath, 'dokuwiki/template/')) {
1994602718bSAndreas Gohr            $classPath = str_replace('/test/', '/_test/', $classPath); // no underscore in test namespace
2004602718bSAndreas Gohr            $file = DOKU_INC . 'lib/tpl/' . $classPath . '.php';
201f83f0fd0SAndreas Gohr            if (file_exists($file)) {
2024602718bSAndreas Gohr                $template = substr($classPath, 0, strpos($classPath, '/'));
2034602718bSAndreas Gohr
204ffa84f81SAndreas Gohr                try {
205f83f0fd0SAndreas Gohr                    require $file;
206ffa84f81SAndreas Gohr                } catch (\Throwable $e) {
2074602718bSAndreas Gohr                    ErrorHandler::showExceptionMsg($e, "Error loading template $template");
208ffa84f81SAndreas Gohr                }
209f83f0fd0SAndreas Gohr                return true;
210f83f0fd0SAndreas Gohr            }
211f83f0fd0SAndreas Gohr        }
2124602718bSAndreas Gohr        return false;
2134602718bSAndreas Gohr    }
214f83f0fd0SAndreas Gohr
2154602718bSAndreas Gohr    /**
2164602718bSAndreas Gohr     * Check if the class is a namespaced DokuWiki core class
2174602718bSAndreas Gohr     *
2184602718bSAndreas Gohr     * @param string $classPath The class name using forward slashes as namespace separators
2194602718bSAndreas Gohr     * @return bool true if the class was loaded, false otherwise
2204602718bSAndreas Gohr     */
2214602718bSAndreas Gohr    protected function autoloadCoreClass($classPath)
2224602718bSAndreas Gohr    {
2234602718bSAndreas Gohr        if ($this->prefixStrip($classPath, 'dokuwiki/')) {
2244602718bSAndreas Gohr            $file = DOKU_INC . 'inc/' . $classPath . '.php';
225b16ddc6eSAndreas Gohr            if (file_exists($file)) {
226b16ddc6eSAndreas Gohr                require $file;
227b89dfc20SAndreas Gohr                return true;
228b89dfc20SAndreas Gohr            }
229b16ddc6eSAndreas Gohr        }
2304602718bSAndreas Gohr        return false;
2314602718bSAndreas Gohr    }
232b89dfc20SAndreas Gohr
2334602718bSAndreas Gohr    /**
2344602718bSAndreas Gohr     * Check if the class is a un-namespaced plugin class following our naming scheme
2354602718bSAndreas Gohr     *
2364602718bSAndreas Gohr     * @param string $className
2374602718bSAndreas Gohr     * @return bool true if the class was loaded, false otherwise
2384602718bSAndreas Gohr     */
2394602718bSAndreas Gohr    protected function autoloadNamedPluginClass($className)
2404602718bSAndreas Gohr    {
2414602718bSAndreas Gohr        global $plugin_controller;
2424602718bSAndreas Gohr
2437d34963bSAndreas Gohr        if (
2447d34963bSAndreas Gohr            preg_match(
2451935a891SAndreas Gohr                '/^(' . implode('|', PluginController::PLUGIN_TYPES) . ')_plugin_(' .
24664159a61SAndreas Gohr                DOKU_PLUGIN_NAME_REGEX .
24764159a61SAndreas Gohr                ')(?:_([^_]+))?$/',
2484602718bSAndreas Gohr                $className,
24964159a61SAndreas Gohr                $m
2507d34963bSAndreas Gohr            )
2517d34963bSAndreas Gohr        ) {
252d54ac877SAdrian Lang            $c = ((count($m) === 4) ? "/{$m[3]}" : '');
2535a9866e9SAndreas Gohr            $plg = DOKU_PLUGIN . "{$m[2]}/{$m[1]}$c.php";
25479e79377SAndreas Gohr            if (file_exists($plg)) {
2554602718bSAndreas Gohr                // don't load disabled plugin classes (only if plugin controller is available)
256*ff136773SAndreas Gohr                if (!defined('DOKU_UNITTEST') && $plugin_controller && plugin_isdisabled($m[2])) return false;
257ffa84f81SAndreas Gohr                try {
258ce949263SAndreas Gohr                    require $plg;
259ffa84f81SAndreas Gohr                } catch (\Throwable $e) {
26024870174SAndreas Gohr                    ErrorHandler::showExceptionMsg($e, "Error loading plugin {$m[2]}");
261ffa84f81SAndreas Gohr                }
2625a9866e9SAndreas Gohr            }
2638a58013eSDavid Stone            return true;
264d54ac877SAdrian Lang        }
265ce949263SAndreas Gohr        return false;
26616905344SAndreas Gohr    }
2674602718bSAndreas Gohr
2684602718bSAndreas Gohr    /**
2694602718bSAndreas Gohr     * Check if the given string starts with the given prefix and strip it
2704602718bSAndreas Gohr     *
2714602718bSAndreas Gohr     * @param string $string
2724602718bSAndreas Gohr     * @param string $prefix
2734602718bSAndreas Gohr     * @return bool true if the prefix was found and stripped, false otherwise
2744602718bSAndreas Gohr     */
2754602718bSAndreas Gohr    protected function prefixStrip(&$string, $prefix)
2764602718bSAndreas Gohr    {
2774602718bSAndreas Gohr        if (str_starts_with($string, $prefix)) {
2784602718bSAndreas Gohr            $string = substr($string, strlen($prefix));
2794602718bSAndreas Gohr            return true;
2804602718bSAndreas Gohr        }
2814602718bSAndreas Gohr        return false;
2824602718bSAndreas Gohr    }
2834602718bSAndreas Gohr};
284