xref: /plugin/farmer/DokuWikiFarmCore.php (revision b96c66cc018b7a6d9630acddc46fe47fbaff0136)
1da0ae2c0SAndreas Gohr<?php
2da0ae2c0SAndreas Gohr
3a646d519SAndreas Gohr/**
4a646d519SAndreas Gohr * Core Manager for the Farm functionality
5a646d519SAndreas Gohr *
6a646d519SAndreas Gohr * This class is initialized before any other DokuWiki code runs. Therefore it is
7a646d519SAndreas Gohr * completely selfcontained and does not use any of DokuWiki's utility functions.
8a646d519SAndreas Gohr *
9*b96c66ccSAndreas Gohr * It's registered as a global $FARMCORE variable but you should not interact with
10*b96c66ccSAndreas Gohr * it directly. Instead use the Farmer plugin's helper component.
11a646d519SAndreas Gohr */
12da0ae2c0SAndreas Gohrclass DokuWikiFarmCore {
13da0ae2c0SAndreas Gohr    /**
14da0ae2c0SAndreas Gohr     * @var array The default config - changed by loadConfig
15da0ae2c0SAndreas Gohr     */
16da0ae2c0SAndreas Gohr    protected $config = array(
17a646d519SAndreas Gohr        'base' => array(
18a646d519SAndreas Gohr            'farmdir' => '',
19a646d519SAndreas Gohr            'farmhost' => ''
20a646d519SAndreas Gohr        ),
21da0ae2c0SAndreas Gohr        'notfound' => array(
22da0ae2c0SAndreas Gohr            'show' => 'farmer',
23da0ae2c0SAndreas Gohr            'url' => ''
24da0ae2c0SAndreas Gohr        ),
25da0ae2c0SAndreas Gohr        'inherit' => array(
26da0ae2c0SAndreas Gohr            'main' => 1,
27da0ae2c0SAndreas Gohr            'acronyms' => 1,
28da0ae2c0SAndreas Gohr            'entities' => 1,
29da0ae2c0SAndreas Gohr            'interwiki' => 1,
30da0ae2c0SAndreas Gohr            'license' => 1,
31da0ae2c0SAndreas Gohr            'mime' => 1,
32da0ae2c0SAndreas Gohr            'scheme' => 1,
33da0ae2c0SAndreas Gohr            'smileys' => 1,
34da0ae2c0SAndreas Gohr            'wordblock' => 1,
35da0ae2c0SAndreas Gohr            'userstyle' => 0,
36da0ae2c0SAndreas Gohr            'userscript' => 0
37da0ae2c0SAndreas Gohr        )
38da0ae2c0SAndreas Gohr    );
39da0ae2c0SAndreas Gohr
40a646d519SAndreas Gohr    /** @var string|false The current animal, false for farmer */
41a646d519SAndreas Gohr    protected $animal = false;
42a646d519SAndreas Gohr    /** @var bool true if an animal was requested but was not found */
43a646d519SAndreas Gohr    protected $notfound = false;
44a646d519SAndreas Gohr    /** @var bool true if the current animal was requested by host */
45a646d519SAndreas Gohr    protected $hostbased = false;
46a646d519SAndreas Gohr
47da0ae2c0SAndreas Gohr    /**
48da0ae2c0SAndreas Gohr     * DokuWikiFarmCore constructor.
49da0ae2c0SAndreas Gohr     *
50a646d519SAndreas Gohr     * This initializes the whole farm by loading the configuration and setting
51a646d519SAndreas Gohr     * DOKU_CONF depending on the requested animal
52da0ae2c0SAndreas Gohr     */
53da0ae2c0SAndreas Gohr    public function __construct() {
54da0ae2c0SAndreas Gohr        $this->loadConfig();
55a646d519SAndreas Gohr        if($this->config['base']['farmdir'] === '') return; // farm setup not complete
56a646d519SAndreas Gohr
57a646d519SAndreas Gohr        // animal?
58a646d519SAndreas Gohr        $this->detectAnimal();
59a646d519SAndreas Gohr
60a646d519SAndreas Gohr        // setup defines
61a646d519SAndreas Gohr        define('DOKU_FARMDIR', $this->config['base']['farmdir']);
62a646d519SAndreas Gohr        define('DOKU_FARM_ANIMAL', $this->animal);
63a646d519SAndreas Gohr        if($this->animal) {
64a646d519SAndreas Gohr            define('DOKU_CONF', DOKU_FARMDIR . '/' . $this->animal . '/conf/');
65a646d519SAndreas Gohr        } else {
66a646d519SAndreas Gohr            define('DOKU_CONF', DOKU_INC . '/conf/');
67a646d519SAndreas Gohr        }
68a646d519SAndreas Gohr
69a646d519SAndreas Gohr        $this->setupCascade();
70a646d519SAndreas Gohr        $this->adjustCascade();
71da0ae2c0SAndreas Gohr    }
72da0ae2c0SAndreas Gohr
73da0ae2c0SAndreas Gohr    /**
74da0ae2c0SAndreas Gohr     * @return array the current farm configuration
75da0ae2c0SAndreas Gohr     */
76da0ae2c0SAndreas Gohr    public function getConfig() {
77da0ae2c0SAndreas Gohr        return $this->config;
78da0ae2c0SAndreas Gohr    }
79da0ae2c0SAndreas Gohr
80da0ae2c0SAndreas Gohr    /**
81a646d519SAndreas Gohr     * @return false|string
82a646d519SAndreas Gohr     */
83a646d519SAndreas Gohr    public function getAnimal() {
84a646d519SAndreas Gohr        return $this->animal;
85a646d519SAndreas Gohr    }
86a646d519SAndreas Gohr
87a646d519SAndreas Gohr    /**
88a646d519SAndreas Gohr     * @return boolean
89a646d519SAndreas Gohr     */
90a646d519SAndreas Gohr    public function isHostbased() {
91a646d519SAndreas Gohr        return $this->hostbased;
92a646d519SAndreas Gohr    }
93a646d519SAndreas Gohr
94a646d519SAndreas Gohr    /**
95a646d519SAndreas Gohr     * @return boolean
96a646d519SAndreas Gohr     */
97a646d519SAndreas Gohr    public function wasNotfound() {
98a646d519SAndreas Gohr        return $this->notfound;
99a646d519SAndreas Gohr    }
100a646d519SAndreas Gohr
101a646d519SAndreas Gohr    /**
102a646d519SAndreas Gohr     * Detect the current animal
103a646d519SAndreas Gohr     *
104a646d519SAndreas Gohr     * Sets internal members $animal, $notfound and $hostbased
105a646d519SAndreas Gohr     *
106a646d519SAndreas Gohr     * This borrows form DokuWiki's inc/farm.php but does not support a default conf dir
107a646d519SAndreas Gohr     */
108a646d519SAndreas Gohr    protected function detectAnimal() {
109a646d519SAndreas Gohr        $farmdir = $this->config['base']['farmdir'];
110a646d519SAndreas Gohr        $farmhost = $this->config['base']['farmhost'];
111a646d519SAndreas Gohr
112a646d519SAndreas Gohr        // check if animal was set via parameter (rewrite or CLI)
113a646d519SAndreas Gohr        $animal = '';
114a646d519SAndreas Gohr        if(isset($_REQUEST['animal'])) $animal = $_REQUEST['animal'];
115a646d519SAndreas Gohr        if('cli' == php_sapi_name() && isset($_SERVER['animal'])) $animal = $_SERVER['animal'];
116a646d519SAndreas Gohr        if($animal) {
117a646d519SAndreas Gohr            // check that $animal is a string and just a directory name and not a path
118a646d519SAndreas Gohr            if(!is_string($animal) || strpbrk($animal, '\\/') !== false) {
119a646d519SAndreas Gohr                $this->notfound = true;
120a646d519SAndreas Gohr                return;
121a646d519SAndreas Gohr            };
122a646d519SAndreas Gohr            $animal = strtolower($animal);
123a646d519SAndreas Gohr
124a646d519SAndreas Gohr            // check if animal exists
125a646d519SAndreas Gohr            if(is_dir("$farmdir/$animal/conf")) {
126a646d519SAndreas Gohr                $this->animal = $animal;
127a646d519SAndreas Gohr                return;
128a646d519SAndreas Gohr            } else {
129a646d519SAndreas Gohr                $this->notfound = true;
130a646d519SAndreas Gohr                return;
131a646d519SAndreas Gohr            }
132a646d519SAndreas Gohr        }
133a646d519SAndreas Gohr
134a646d519SAndreas Gohr        // is this the farmer?
135a646d519SAndreas Gohr        if(strtolower($_SERVER['HTTP_HOST']) == $farmhost) {
136a646d519SAndreas Gohr            return;
137a646d519SAndreas Gohr        }
138a646d519SAndreas Gohr
139a646d519SAndreas Gohr        // still here? check for host based
140a646d519SAndreas Gohr        $this->hostbased = true;
141a646d519SAndreas Gohr        $uri = explode('/', $_SERVER['SCRIPT_NAME'] ? $_SERVER['SCRIPT_NAME'] : $_SERVER['SCRIPT_FILENAME']);
142a646d519SAndreas Gohr        $server = explode('.', implode('.', array_reverse(explode(':', rtrim($_SERVER['HTTP_HOST'], '.')))));
143a646d519SAndreas Gohr        for($i = count($uri) - 1; $i > 0; $i--) {
144a646d519SAndreas Gohr            for($j = count($server); $j > 0; $j--) {
145a646d519SAndreas Gohr                $animal = implode('.', array_slice($server, -$j)) . implode('.', array_slice($uri, 0, $i));
146a646d519SAndreas Gohr                if(is_dir("$farmdir/$animal/conf/")) {
147a646d519SAndreas Gohr                    $this->animal = $animal;
148a646d519SAndreas Gohr                    return;
149a646d519SAndreas Gohr                }
150a646d519SAndreas Gohr            }
151a646d519SAndreas Gohr        }
152a646d519SAndreas Gohr
153a646d519SAndreas Gohr        // no hit
154a646d519SAndreas Gohr        $this->notfound = true;
155a646d519SAndreas Gohr        return;
156a646d519SAndreas Gohr    }
157a646d519SAndreas Gohr
158a646d519SAndreas Gohr    /**
159a646d519SAndreas Gohr     * This sets up the default farming config cascade
160a646d519SAndreas Gohr     */
161a646d519SAndreas Gohr    protected function setupCascade() {
162a646d519SAndreas Gohr        global $config_cascade;
163a646d519SAndreas Gohr        $config_cascade = array(
164a646d519SAndreas Gohr            'main' => array(
165a646d519SAndreas Gohr                'default' => array(DOKU_INC . 'conf/dokuwiki.php',),
166a646d519SAndreas Gohr                'local' => array(DOKU_CONF . 'local.php',),
167a646d519SAndreas Gohr                'protected' => array(DOKU_CONF . 'local.protected.php',),
168a646d519SAndreas Gohr            ),
169a646d519SAndreas Gohr            'acronyms' => array(
170a646d519SAndreas Gohr                'default' => array(DOKU_INC . 'conf/acronyms.conf',),
171a646d519SAndreas Gohr                'local' => array(DOKU_CONF . 'acronyms.local.conf',),
172a646d519SAndreas Gohr            ),
173a646d519SAndreas Gohr            'entities' => array(
174a646d519SAndreas Gohr                'default' => array(DOKU_INC . 'conf/entities.conf',),
175a646d519SAndreas Gohr                'local' => array(DOKU_CONF . 'entities.local.conf',),
176a646d519SAndreas Gohr            ),
177a646d519SAndreas Gohr            'interwiki' => array(
178a646d519SAndreas Gohr                'default' => array(DOKU_INC . 'conf/interwiki.conf',),
179a646d519SAndreas Gohr                'local' => array(DOKU_CONF . 'interwiki.local.conf',),
180a646d519SAndreas Gohr            ),
181a646d519SAndreas Gohr            'license' => array(
182a646d519SAndreas Gohr                'default' => array(DOKU_INC . 'conf/license.php',),
183a646d519SAndreas Gohr                'local' => array(DOKU_CONF . 'license.local.php',),
184a646d519SAndreas Gohr            ),
185a646d519SAndreas Gohr            'mediameta' => array(
186a646d519SAndreas Gohr                'default' => array(DOKU_INC . 'conf/mediameta.php',),
187a646d519SAndreas Gohr                'local' => array(DOKU_CONF . 'mediameta.local.php',),
188a646d519SAndreas Gohr            ),
189a646d519SAndreas Gohr            'mime' => array(
190a646d519SAndreas Gohr                'default' => array(DOKU_INC . 'conf/mime.conf',),
191a646d519SAndreas Gohr                'local' => array(DOKU_CONF . 'mime.local.conf',),
192a646d519SAndreas Gohr            ),
193a646d519SAndreas Gohr            'scheme' => array(
194a646d519SAndreas Gohr                'default' => array(DOKU_INC . 'conf/scheme.conf',),
195a646d519SAndreas Gohr                'local' => array(DOKU_CONF . 'scheme.local.conf',),
196a646d519SAndreas Gohr            ),
197a646d519SAndreas Gohr            'smileys' => array(
198a646d519SAndreas Gohr                'default' => array(DOKU_INC . 'conf/smileys.conf',),
199a646d519SAndreas Gohr                'local' => array(DOKU_CONF . 'smileys.local.conf',),
200a646d519SAndreas Gohr            ),
201a646d519SAndreas Gohr            'wordblock' => array(
202a646d519SAndreas Gohr                'default' => array(DOKU_INC . 'conf/wordblock.conf',),
203a646d519SAndreas Gohr                'local' => array(DOKU_CONF . 'wordblock.local.conf',),
204a646d519SAndreas Gohr            ),
205a646d519SAndreas Gohr            'acl' => array(
206a646d519SAndreas Gohr                'default' => DOKU_CONF . 'acl.auth.php',
207a646d519SAndreas Gohr            ),
208a646d519SAndreas Gohr            'plainauth.users' => array(
209a646d519SAndreas Gohr                'default' => DOKU_CONF . 'users.auth.php',
210a646d519SAndreas Gohr            ),
211a646d519SAndreas Gohr            'plugins' => array( // needed since Angua
212a646d519SAndreas Gohr                                'default' => array(DOKU_INC . 'conf/plugins.php',),
213a646d519SAndreas Gohr                                'local' => array(DOKU_CONF . 'plugins.local.php',),
214a646d519SAndreas Gohr                                'protected' => array(
215a646d519SAndreas Gohr                                    DOKU_INC . 'conf/plugins.required.php',
216a646d519SAndreas Gohr                                    DOKU_CONF . 'plugins.protected.php',
217a646d519SAndreas Gohr                                ),
218a646d519SAndreas Gohr            ),
219a646d519SAndreas Gohr            'userstyle' => array(
220a646d519SAndreas Gohr                'screen' => array(DOKU_CONF . 'userstyle.css', DOKU_CONF . 'userstyle.less',),
221a646d519SAndreas Gohr                'print' => array(DOKU_CONF . 'userprint.css', DOKU_CONF . 'userprint.less',),
222a646d519SAndreas Gohr                'feed' => array(DOKU_CONF . 'userfeed.css', DOKU_CONF . 'userfeed.less',),
223a646d519SAndreas Gohr                'all' => array(DOKU_CONF . 'userall.css', DOKU_CONF . 'userall.less',),
224a646d519SAndreas Gohr            ),
225a646d519SAndreas Gohr            'userscript' => array(
226a646d519SAndreas Gohr                'default' => array(DOKU_CONF . 'userscript.js',),
227a646d519SAndreas Gohr            ),
228a646d519SAndreas Gohr        );
229a646d519SAndreas Gohr    }
230a646d519SAndreas Gohr
231a646d519SAndreas Gohr    /**
232a646d519SAndreas Gohr     * This adds additional files to the config cascade based on the inheritence settings
233a646d519SAndreas Gohr     *
234a646d519SAndreas Gohr     * These are only added for animals, not the farmer
235a646d519SAndreas Gohr     */
236a646d519SAndreas Gohr    protected function adjustCascade() {
237a646d519SAndreas Gohr        // FIXME check if this is an animal
238a646d519SAndreas Gohr        global $config_cascade;
239a646d519SAndreas Gohr
240a646d519SAndreas Gohr        foreach($this->config['inherit'] as $key => $val) {
241a646d519SAndreas Gohr            if(!$val) continue;
242a646d519SAndreas Gohr
243a646d519SAndreas Gohr            // prepare what is to append or prepend
244a646d519SAndreas Gohr            $append = array();
245a646d519SAndreas Gohr            $prepend = array();
246a646d519SAndreas Gohr            if($key == 'main') {
247a646d519SAndreas Gohr                $append = array('default' => array(DOKU_INC . 'conf/local.php'));
248a646d519SAndreas Gohr            } elseif($key == 'license') {
249a646d519SAndreas Gohr                $append = array('default' => array(DOKU_INC . 'conf/' . $key . '.local.php'));
250a646d519SAndreas Gohr            } elseif($key == 'userscript') {
251a646d519SAndreas Gohr                $prepend = array('default' => array(DOKU_INC . 'conf/userscript.js'));
252a646d519SAndreas Gohr            } elseif($key == 'userstyle') {
253a646d519SAndreas Gohr                $prepend = array(
254a646d519SAndreas Gohr                    'screen' => array(DOKU_INC . 'conf/userstyle.css', DOKU_INC . 'conf/userstyle.less',),
255a646d519SAndreas Gohr                    'print' => array(DOKU_INC . 'conf/userprint.css', DOKU_INC . 'conf/userprint.less',),
256a646d519SAndreas Gohr                    'feed' => array(DOKU_INC . 'conf/userfeed.css', DOKU_INC . 'conf/userfeed.less',),
257a646d519SAndreas Gohr                    'all' => array(DOKU_INC . 'conf/userall.css', DOKU_INC . 'conf/userall.less',),
258a646d519SAndreas Gohr                );
259a646d519SAndreas Gohr            } else {
260a646d519SAndreas Gohr                $append = array('default' => array(DOKU_INC . 'conf/' . $key . '.local.conf'));
261a646d519SAndreas Gohr            }
262a646d519SAndreas Gohr
263a646d519SAndreas Gohr            // add to cascade
264a646d519SAndreas Gohr            foreach($prepend as $section => $data) {
265a646d519SAndreas Gohr                $config_cascade[$key][$section] = array_merge($data, $config_cascade[$key][$section]);
266a646d519SAndreas Gohr            }
267a646d519SAndreas Gohr            foreach($append as $section => $data) {
268a646d519SAndreas Gohr                $config_cascade[$key][$section] = array_merge($config_cascade[$key][$section], $data);
269a646d519SAndreas Gohr            }
270a646d519SAndreas Gohr        }
271a646d519SAndreas Gohr    }
272a646d519SAndreas Gohr
273a646d519SAndreas Gohr    /**
274da0ae2c0SAndreas Gohr     * Loads the farm config
275da0ae2c0SAndreas Gohr     */
276da0ae2c0SAndreas Gohr    protected function loadConfig() {
277da0ae2c0SAndreas Gohr        $ini = DOKU_INC . 'conf/farm.ini';
278da0ae2c0SAndreas Gohr        if(!file_exists($ini)) return;
279da0ae2c0SAndreas Gohr        $config = parse_ini_file($ini, true);
280da0ae2c0SAndreas Gohr        foreach(array_keys($this->config) as $section) {
281da0ae2c0SAndreas Gohr            if(isset($config[$section])) {
282da0ae2c0SAndreas Gohr                $this->config[$section] = array_merge(
283da0ae2c0SAndreas Gohr                    $this->config[$section],
284da0ae2c0SAndreas Gohr                    $config[$section]
285da0ae2c0SAndreas Gohr                );
286da0ae2c0SAndreas Gohr            }
287da0ae2c0SAndreas Gohr        }
288da0ae2c0SAndreas Gohr
289a646d519SAndreas Gohr        $this->config['base']['farmdir'] = trim($this->config['base']['farmdir']);
290a646d519SAndreas Gohr        $this->config['base']['farmhost'] = strtolower(trim($this->config['base']['farmhost']));
291a646d519SAndreas Gohr    }
292da0ae2c0SAndreas Gohr
293da0ae2c0SAndreas Gohr}
294da0ae2c0SAndreas Gohr
295da0ae2c0SAndreas Gohr// initialize it globally
296da0ae2c0SAndreas Gohrglobal $FARMCORE;
297da0ae2c0SAndreas Gohr$FARMCORE = new DokuWikiFarmCore();
298