xref: /dokuwiki/inc/load.php (revision 4602718be573dd5f46a72c4ef3ac2ce3d8c129d1)
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
9*4602718bSAndreas Gohrnamespace dokuwiki;
10*4602718bSAndreas Gohr
111935a891SAndreas Gohruse dokuwiki\Extension\PluginController;
121935a891SAndreas Gohr
13*4602718bSAndreas Gohrreturn new class {
14*4602718bSAndreas Gohr    /** @var string[] Common libraries that are always loaded */
15*4602718bSAndreas Gohr    protected array $commonLibs = [
16*4602718bSAndreas Gohr        'defines.php',
17*4602718bSAndreas Gohr        'actions.php',
18*4602718bSAndreas Gohr        'changelog.php',
19*4602718bSAndreas Gohr        'common.php',
20*4602718bSAndreas Gohr        'confutils.php',
21*4602718bSAndreas Gohr        'pluginutils.php',
22*4602718bSAndreas Gohr        'form.php',
23*4602718bSAndreas Gohr        'fulltext.php',
24*4602718bSAndreas Gohr        'html.php',
25*4602718bSAndreas Gohr        'httputils.php',
26*4602718bSAndreas Gohr        'indexer.php',
27*4602718bSAndreas Gohr        'infoutils.php',
28*4602718bSAndreas Gohr        'io.php',
29*4602718bSAndreas Gohr        'mail.php',
30*4602718bSAndreas Gohr        'media.php',
31*4602718bSAndreas Gohr        'pageutils.php',
32*4602718bSAndreas Gohr        'parserutils.php',
33*4602718bSAndreas Gohr        'search.php',
34*4602718bSAndreas Gohr        'template.php',
35*4602718bSAndreas Gohr        'toolbar.php',
36*4602718bSAndreas Gohr        'utf8.php',
37*4602718bSAndreas Gohr        'auth.php',
38*4602718bSAndreas Gohr        'compatibility.php',
39*4602718bSAndreas Gohr        'deprecated.php',
40*4602718bSAndreas Gohr        'legacy.php',
41*4602718bSAndreas Gohr    ];
4216905344SAndreas Gohr
43*4602718bSAndreas Gohr    /** @var string[] Classname to file mappings */
44*4602718bSAndreas Gohr    protected array $fixedClassNames = [
45*4602718bSAndreas Gohr        'Diff' => 'DifferenceEngine.php',
46*4602718bSAndreas Gohr        'UnifiedDiffFormatter' => 'DifferenceEngine.php',
47*4602718bSAndreas Gohr        'TableDiffFormatter' => 'DifferenceEngine.php',
48*4602718bSAndreas Gohr        'cache' => 'cache.php',
49*4602718bSAndreas Gohr        'cache_parser' => 'cache.php',
50*4602718bSAndreas Gohr        'cache_instructions' => 'cache.php',
51*4602718bSAndreas Gohr        'cache_renderer' => 'cache.php',
52*4602718bSAndreas Gohr        'Input' => 'Input.class.php',
53*4602718bSAndreas Gohr        'JpegMeta' => 'JpegMeta.php',
54*4602718bSAndreas Gohr        'SimplePie' => 'SimplePie.php',
55*4602718bSAndreas Gohr        'FeedParser' => 'FeedParser.php',
56*4602718bSAndreas Gohr        'SafeFN' => 'SafeFN.class.php',
57*4602718bSAndreas Gohr        'Mailer' => 'Mailer.class.php',
58*4602718bSAndreas Gohr        'Doku_Handler' => 'parser/handler.php',
59*4602718bSAndreas Gohr        'Doku_Renderer' => 'parser/renderer.php',
60*4602718bSAndreas Gohr        'Doku_Renderer_xhtml' => 'parser/xhtml.php',
61*4602718bSAndreas Gohr        'Doku_Renderer_code' => 'parser/code.php',
62*4602718bSAndreas Gohr        'Doku_Renderer_xhtmlsummary' => 'parser/xhtmlsummary.php',
63*4602718bSAndreas Gohr        'Doku_Renderer_metadata' => 'parser/metadata.php'
64*4602718bSAndreas Gohr    ];
65*4602718bSAndreas Gohr
66*4602718bSAndreas Gohr    /**
67*4602718bSAndreas Gohr     * Load common libs and register autoloader
68*4602718bSAndreas Gohr     */
69*4602718bSAndreas Gohr    public function __construct()
70*4602718bSAndreas Gohr    {
71*4602718bSAndreas Gohr        require_once(DOKU_INC . 'vendor/autoload.php');
72*4602718bSAndreas Gohr        spl_autoload_register([$this, 'autoload']);
73*4602718bSAndreas Gohr        $this->loadCommonLibs();
74*4602718bSAndreas Gohr    }
75*4602718bSAndreas Gohr
76*4602718bSAndreas Gohr    /**
77*4602718bSAndreas Gohr     * require all the common libraries
78*4602718bSAndreas Gohr     *
79*4602718bSAndreas Gohr     * @return true
80*4602718bSAndreas Gohr     */
81*4602718bSAndreas Gohr    public function loadCommonLibs()
82*4602718bSAndreas Gohr    {
83*4602718bSAndreas Gohr        foreach ($this->commonLibs as $lib) {
84*4602718bSAndreas Gohr            require_once(DOKU_INC . 'inc/' . $lib);
85*4602718bSAndreas Gohr        }
86*4602718bSAndreas Gohr        return true;
87*4602718bSAndreas Gohr    }
8816905344SAndreas Gohr
8916905344SAndreas Gohr    /**
9016905344SAndreas Gohr     * spl_autoload_register callback
9116905344SAndreas Gohr     *
92*4602718bSAndreas Gohr     * @param string $className
93f50a239bSTakamura     * @return bool
9416905344SAndreas Gohr     */
95*4602718bSAndreas Gohr    public function autoload($className)
96d868eb89SAndreas Gohr    {
97b89dfc20SAndreas Gohr        // namespace to directory conversion
98*4602718bSAndreas Gohr        $classPath = str_replace('\\', '/', $className);
99e7a32b17SAndreas Gohr
100*4602718bSAndreas Gohr        return $this->autoloadFixedClass($className)
101*4602718bSAndreas Gohr            || $this->autoloadTestMockClass($classPath)
102*4602718bSAndreas Gohr            || $this->autoloadTestClass($classPath)
103*4602718bSAndreas Gohr            || $this->autoloadPluginClass($classPath)
104*4602718bSAndreas Gohr            || $this->autoloadTemplateClass($classPath)
105*4602718bSAndreas Gohr            || $this->autoloadCoreClass($classPath)
106*4602718bSAndreas Gohr            || $this->autoloadNamedPluginClass($className);
107*4602718bSAndreas Gohr    }
108*4602718bSAndreas Gohr
109*4602718bSAndreas Gohr    /**
110*4602718bSAndreas Gohr     * Check if the class is one of the fixed names
111*4602718bSAndreas Gohr     *
112*4602718bSAndreas Gohr     * @param string $className
113*4602718bSAndreas Gohr     * @return bool true if the class was loaded, false otherwise
114*4602718bSAndreas Gohr     */
115*4602718bSAndreas Gohr    protected function autoloadFixedClass($className)
116*4602718bSAndreas Gohr    {
117*4602718bSAndreas Gohr        if (isset($this->fixedClassNames[$className])) {
118*4602718bSAndreas Gohr            require($this->fixedClassNames[$className]);
119*4602718bSAndreas Gohr            return true;
120*4602718bSAndreas Gohr        }
121*4602718bSAndreas Gohr        return false;
122*4602718bSAndreas Gohr    }
123*4602718bSAndreas Gohr
124*4602718bSAndreas Gohr    /**
125*4602718bSAndreas Gohr     * Check if the class is a test mock class
126*4602718bSAndreas Gohr     *
127*4602718bSAndreas Gohr     * @param string $classPath The class name using forward slashes as namespace separators
128*4602718bSAndreas Gohr     * @return bool true if the class was loaded, false otherwise
129*4602718bSAndreas Gohr     */
130*4602718bSAndreas Gohr    protected function autoloadTestMockClass($classPath)
131*4602718bSAndreas Gohr    {
132*4602718bSAndreas Gohr        if ($this->prefixStrip($classPath, 'dokuwiki/test/mock/')) {
133*4602718bSAndreas 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        }
139*4602718bSAndreas Gohr        return false;
140*4602718bSAndreas Gohr    }
141ec85aeb2SAndreas Gohr
142*4602718bSAndreas Gohr    /**
143*4602718bSAndreas Gohr     * Check if the class is a test mock class
144*4602718bSAndreas Gohr     *
145*4602718bSAndreas Gohr     * @param string $classPath The class name using forward slashes as namespace separators
146*4602718bSAndreas Gohr     * @return bool true if the class was loaded, false otherwise
147*4602718bSAndreas Gohr     */
148*4602718bSAndreas Gohr    protected function autoloadTestClass($classPath)
149*4602718bSAndreas Gohr    {
150*4602718bSAndreas Gohr        if ($this->prefixStrip($classPath, 'dokuwiki/test/')) {
151*4602718bSAndreas 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        }
157*4602718bSAndreas Gohr        return false;
158*4602718bSAndreas Gohr    }
159a087da71SAndreas Gohr
160*4602718bSAndreas Gohr    /**
161*4602718bSAndreas Gohr     * Check if the class is a namespaced plugin class
162*4602718bSAndreas Gohr     *
163*4602718bSAndreas Gohr     * @param string $classPath The class name using forward slashes as namespace separators
164*4602718bSAndreas Gohr     * @return bool true if the class was loaded, false otherwise
165*4602718bSAndreas Gohr     */
166*4602718bSAndreas Gohr    protected function autoloadPluginClass($classPath)
167*4602718bSAndreas Gohr    {
168*4602718bSAndreas Gohr        global $plugin_controller;
169*4602718bSAndreas Gohr
170*4602718bSAndreas Gohr        if ($this->prefixStrip($classPath, 'dokuwiki/plugin/')) {
171*4602718bSAndreas Gohr            $classPath = str_replace('/test/', '/_test/', $classPath); // no underscore in test namespace
172*4602718bSAndreas Gohr            $file = DOKU_PLUGIN . $classPath . '.php';
173600fb65eSAndreas Gohr            if (file_exists($file)) {
174*4602718bSAndreas Gohr                $plugin = substr($classPath, 0, strpos($classPath, '/'));
175*4602718bSAndreas Gohr                // don't load disabled plugin classes (only if plugin controller is available)
176*4602718bSAndreas Gohr                if ($plugin_controller && plugin_isdisabled($plugin)) return false;
177*4602718bSAndreas Gohr
178ffa84f81SAndreas Gohr                try {
179600fb65eSAndreas Gohr                    require $file;
180ffa84f81SAndreas Gohr                } catch (\Throwable $e) {
181*4602718bSAndreas Gohr                    ErrorHandler::showExceptionMsg($e, "Error loading plugin $plugin");
182ffa84f81SAndreas Gohr                }
183600fb65eSAndreas Gohr                return true;
184600fb65eSAndreas Gohr            }
185600fb65eSAndreas Gohr        }
186*4602718bSAndreas Gohr        return false;
187*4602718bSAndreas Gohr    }
188600fb65eSAndreas Gohr
189*4602718bSAndreas Gohr    /**
190*4602718bSAndreas Gohr     * Check if the class is a namespaced template class
191*4602718bSAndreas Gohr     *
192*4602718bSAndreas Gohr     * @param string $classPath The class name using forward slashes as namespace separators
193*4602718bSAndreas Gohr     * @return bool true if the class was loaded, false otherwise
194*4602718bSAndreas Gohr     */
195*4602718bSAndreas Gohr    protected function autoloadTemplateClass($classPath)
196*4602718bSAndreas Gohr    {
197f83f0fd0SAndreas Gohr        // template namespace
198*4602718bSAndreas Gohr        if ($this->prefixStrip($classPath, 'dokuwiki/template/')) {
199*4602718bSAndreas Gohr            $classPath = str_replace('/test/', '/_test/', $classPath); // no underscore in test namespace
200*4602718bSAndreas Gohr            $file = DOKU_INC . 'lib/tpl/' . $classPath . '.php';
201f83f0fd0SAndreas Gohr            if (file_exists($file)) {
202*4602718bSAndreas Gohr                $template = substr($classPath, 0, strpos($classPath, '/'));
203*4602718bSAndreas Gohr
204ffa84f81SAndreas Gohr                try {
205f83f0fd0SAndreas Gohr                    require $file;
206ffa84f81SAndreas Gohr                } catch (\Throwable $e) {
207*4602718bSAndreas Gohr                    ErrorHandler::showExceptionMsg($e, "Error loading template $template");
208ffa84f81SAndreas Gohr                }
209f83f0fd0SAndreas Gohr                return true;
210f83f0fd0SAndreas Gohr            }
211f83f0fd0SAndreas Gohr        }
212*4602718bSAndreas Gohr        return false;
213*4602718bSAndreas Gohr    }
214f83f0fd0SAndreas Gohr
215*4602718bSAndreas Gohr    /**
216*4602718bSAndreas Gohr     * Check if the class is a namespaced DokuWiki core class
217*4602718bSAndreas Gohr     *
218*4602718bSAndreas Gohr     * @param string $classPath The class name using forward slashes as namespace separators
219*4602718bSAndreas Gohr     * @return bool true if the class was loaded, false otherwise
220*4602718bSAndreas Gohr     */
221*4602718bSAndreas Gohr    protected function autoloadCoreClass($classPath)
222*4602718bSAndreas Gohr    {
223*4602718bSAndreas Gohr        if ($this->prefixStrip($classPath, 'dokuwiki/')) {
224*4602718bSAndreas 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        }
230*4602718bSAndreas Gohr        return false;
231*4602718bSAndreas Gohr    }
232b89dfc20SAndreas Gohr
233*4602718bSAndreas Gohr    /**
234*4602718bSAndreas Gohr     * Check if the class is a un-namespaced plugin class following our naming scheme
235*4602718bSAndreas Gohr     *
236*4602718bSAndreas Gohr     * @param string $className
237*4602718bSAndreas Gohr     * @return bool true if the class was loaded, false otherwise
238*4602718bSAndreas Gohr     */
239*4602718bSAndreas Gohr    protected function autoloadNamedPluginClass($className)
240*4602718bSAndreas Gohr    {
241*4602718bSAndreas Gohr        global $plugin_controller;
242*4602718bSAndreas Gohr
2437d34963bSAndreas Gohr        if (
2447d34963bSAndreas Gohr            preg_match(
2451935a891SAndreas Gohr                '/^(' . implode('|', PluginController::PLUGIN_TYPES) . ')_plugin_(' .
24664159a61SAndreas Gohr                DOKU_PLUGIN_NAME_REGEX .
24764159a61SAndreas Gohr                ')(?:_([^_]+))?$/',
248*4602718bSAndreas 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)) {
255*4602718bSAndreas Gohr                // don't load disabled plugin classes (only if plugin controller is available)
256*4602718bSAndreas Gohr                if ($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    }
267*4602718bSAndreas Gohr
268*4602718bSAndreas Gohr    /**
269*4602718bSAndreas Gohr     * Check if the given string starts with the given prefix and strip it
270*4602718bSAndreas Gohr     *
271*4602718bSAndreas Gohr     * @param string $string
272*4602718bSAndreas Gohr     * @param string $prefix
273*4602718bSAndreas Gohr     * @return bool true if the prefix was found and stripped, false otherwise
274*4602718bSAndreas Gohr     */
275*4602718bSAndreas Gohr    protected function prefixStrip(&$string, $prefix)
276*4602718bSAndreas Gohr    {
277*4602718bSAndreas Gohr        if (str_starts_with($string, $prefix)) {
278*4602718bSAndreas Gohr            $string = substr($string, strlen($prefix));
279*4602718bSAndreas Gohr            return true;
280*4602718bSAndreas Gohr        }
281*4602718bSAndreas Gohr        return false;
282*4602718bSAndreas Gohr    }
283*4602718bSAndreas Gohr};
284