xref: /plugin/farmer/DokuWikiFarmCore.php (revision 917a67f077447938b386ef7e0818a0696b38f93b)
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 *
9b96c66ccSAndreas Gohr * It's registered as a global $FARMCORE variable but you should not interact with
10b96c66ccSAndreas Gohr * it directly. Instead use the Farmer plugin's helper component.
110a5d2da2SAndreas Gohr *
120a5d2da2SAndreas Gohr * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html
130a5d2da2SAndreas Gohr * @author  Andreas Gohr <gohr@cosmocode.de>
14a646d519SAndreas Gohr */
15da0ae2c0SAndreas Gohrclass DokuWikiFarmCore {
16da0ae2c0SAndreas Gohr    /**
17da0ae2c0SAndreas Gohr     * @var array The default config - changed by loadConfig
18da0ae2c0SAndreas Gohr     */
19da0ae2c0SAndreas Gohr    protected $config = array(
20a646d519SAndreas Gohr        'base' => array(
21a646d519SAndreas Gohr            'farmdir' => '',
22c4c8e953SAndreas Gohr            'farmhost' => '',
23c4c8e953SAndreas Gohr            'basedomain' => '',
24a646d519SAndreas Gohr        ),
25da0ae2c0SAndreas Gohr        'notfound' => array(
26da0ae2c0SAndreas Gohr            'show' => 'farmer',
27da0ae2c0SAndreas Gohr            'url' => ''
28da0ae2c0SAndreas Gohr        ),
29da0ae2c0SAndreas Gohr        'inherit' => array(
30da0ae2c0SAndreas Gohr            'main' => 1,
31da0ae2c0SAndreas Gohr            'acronyms' => 1,
32da0ae2c0SAndreas Gohr            'entities' => 1,
33da0ae2c0SAndreas Gohr            'interwiki' => 1,
34da0ae2c0SAndreas Gohr            'license' => 1,
35da0ae2c0SAndreas Gohr            'mime' => 1,
36da0ae2c0SAndreas Gohr            'scheme' => 1,
37da0ae2c0SAndreas Gohr            'smileys' => 1,
38da0ae2c0SAndreas Gohr            'wordblock' => 1,
391272da0cSAndreas Gohr            'users' => 0,
40af1c6dd8SAndreas Gohr            'plugins' => 0,
41da0ae2c0SAndreas Gohr            'userstyle' => 0,
4205ea7625SAnna Dabrowska            'userscript' => 0,
433cee9885SAnna Dabrowska            'styleini' => 0
44da0ae2c0SAndreas Gohr        )
45da0ae2c0SAndreas Gohr    );
46da0ae2c0SAndreas Gohr
47a646d519SAndreas Gohr    /** @var string|false The current animal, false for farmer */
48a646d519SAndreas Gohr    protected $animal = false;
49a646d519SAndreas Gohr    /** @var bool true if an animal was requested but was not found */
50a646d519SAndreas Gohr    protected $notfound = false;
51a646d519SAndreas Gohr    /** @var bool true if the current animal was requested by host */
52a646d519SAndreas Gohr    protected $hostbased = false;
53a646d519SAndreas Gohr
54da0ae2c0SAndreas Gohr    /**
55da0ae2c0SAndreas Gohr     * DokuWikiFarmCore constructor.
56da0ae2c0SAndreas Gohr     *
57a646d519SAndreas Gohr     * This initializes the whole farm by loading the configuration and setting
58a646d519SAndreas Gohr     * DOKU_CONF depending on the requested animal
59da0ae2c0SAndreas Gohr     */
60da0ae2c0SAndreas Gohr    public function __construct() {
61da0ae2c0SAndreas Gohr        $this->loadConfig();
62a646d519SAndreas Gohr        if($this->config['base']['farmdir'] === '') return; // farm setup not complete
638262a4cbSAndreas Gohr        $this->config['base']['farmdir'] = rtrim($this->config['base']['farmdir'], '/').'/'; // trailing slash always
6449f2871cSAndreas Gohr        define('DOKU_FARMDIR', $this->config['base']['farmdir']);
65a646d519SAndreas Gohr
66a646d519SAndreas Gohr        // animal?
67a646d519SAndreas Gohr        $this->detectAnimal();
68a646d519SAndreas Gohr
69a646d519SAndreas Gohr        // setup defines
70a646d519SAndreas Gohr        define('DOKU_FARM_ANIMAL', $this->animal);
71a646d519SAndreas Gohr        if($this->animal) {
728262a4cbSAndreas Gohr            define('DOKU_CONF', DOKU_FARMDIR . $this->animal . '/conf/');
73a646d519SAndreas Gohr        } else {
74a646d519SAndreas Gohr            define('DOKU_CONF', DOKU_INC . '/conf/');
75a646d519SAndreas Gohr        }
76a646d519SAndreas Gohr
77a646d519SAndreas Gohr        $this->setupCascade();
78a646d519SAndreas Gohr        $this->adjustCascade();
79da0ae2c0SAndreas Gohr    }
80da0ae2c0SAndreas Gohr
81da0ae2c0SAndreas Gohr    /**
82da0ae2c0SAndreas Gohr     * @return array the current farm configuration
83da0ae2c0SAndreas Gohr     */
84da0ae2c0SAndreas Gohr    public function getConfig() {
85da0ae2c0SAndreas Gohr        return $this->config;
86da0ae2c0SAndreas Gohr    }
87da0ae2c0SAndreas Gohr
88da0ae2c0SAndreas Gohr    /**
89a646d519SAndreas Gohr     * @return false|string
90a646d519SAndreas Gohr     */
91a646d519SAndreas Gohr    public function getAnimal() {
92a646d519SAndreas Gohr        return $this->animal;
93a646d519SAndreas Gohr    }
94a646d519SAndreas Gohr
95a646d519SAndreas Gohr    /**
96a646d519SAndreas Gohr     * @return boolean
97a646d519SAndreas Gohr     */
98a646d519SAndreas Gohr    public function isHostbased() {
99a646d519SAndreas Gohr        return $this->hostbased;
100a646d519SAndreas Gohr    }
101a646d519SAndreas Gohr
102a646d519SAndreas Gohr    /**
103a646d519SAndreas Gohr     * @return boolean
104a646d519SAndreas Gohr     */
105a646d519SAndreas Gohr    public function wasNotfound() {
106a646d519SAndreas Gohr        return $this->notfound;
107a646d519SAndreas Gohr    }
108a646d519SAndreas Gohr
109a646d519SAndreas Gohr    /**
110b330074aSAndreas Gohr     * @return string
111b330074aSAndreas Gohr     */
112b330074aSAndreas Gohr    public function getAnimalDataDir() {
1138262a4cbSAndreas Gohr        return DOKU_FARMDIR . $this->getAnimal() . '/data/';
114b330074aSAndreas Gohr    }
115b330074aSAndreas Gohr
116b330074aSAndreas Gohr    /**
117b330074aSAndreas Gohr     * @return string
118b330074aSAndreas Gohr     */
119b330074aSAndreas Gohr    public function getAnimalBaseDir() {
12004dc6bd5SSzymon Olewniczak        if($this->isHostbased()) return '/';
121b330074aSAndreas Gohr        return getBaseURL() . '!' . $this->getAnimal();
122b330074aSAndreas Gohr    }
123b330074aSAndreas Gohr
124b330074aSAndreas Gohr    /**
125a646d519SAndreas Gohr     * Detect the current animal
126a646d519SAndreas Gohr     *
127a646d519SAndreas Gohr     * Sets internal members $animal, $notfound and $hostbased
128a646d519SAndreas Gohr     *
129a646d519SAndreas Gohr     * This borrows form DokuWiki's inc/farm.php but does not support a default conf dir
130a646d519SAndreas Gohr     */
131a646d519SAndreas Gohr    protected function detectAnimal() {
132a646d519SAndreas Gohr        $farmdir = $this->config['base']['farmdir'];
133a646d519SAndreas Gohr        $farmhost = $this->config['base']['farmhost'];
134a646d519SAndreas Gohr
135*917a67f0SAndreas Gohr        // check if animal was set via rewrite parameter
136a646d519SAndreas Gohr        $animal = '';
137*917a67f0SAndreas Gohr        if (isset($_GET['animal'])) {
138*917a67f0SAndreas Gohr            $animal = $_GET['animal'];
139*917a67f0SAndreas Gohr            // now unset the parameter to not leak into new queries
140*917a67f0SAndreas Gohr            unset($_GET['animal']);
141*917a67f0SAndreas Gohr            $params = [];
142*917a67f0SAndreas Gohr            parse_str($_SERVER['QUERY_STRING'], $params);
143*917a67f0SAndreas Gohr            if (isset($params['animal'])) unset($params['animal']);
144*917a67f0SAndreas Gohr            $_SERVER['QUERY_STRING'] = http_build_query($params);
145*917a67f0SAndreas Gohr        }
146*917a67f0SAndreas Gohr        // get animal from CLI parameter
147a646d519SAndreas Gohr        if('cli' == php_sapi_name() && isset($_SERVER['animal'])) $animal = $_SERVER['animal'];
148a646d519SAndreas Gohr        if($animal) {
149a646d519SAndreas Gohr            // check that $animal is a string and just a directory name and not a path
150a646d519SAndreas Gohr            if(!is_string($animal) || strpbrk($animal, '\\/') !== false) {
151a646d519SAndreas Gohr                $this->notfound = true;
152a646d519SAndreas Gohr                return;
153a646d519SAndreas Gohr            };
154a646d519SAndreas Gohr            $animal = strtolower($animal);
155a646d519SAndreas Gohr
156a646d519SAndreas Gohr            // check if animal exists
157a646d519SAndreas Gohr            if(is_dir("$farmdir/$animal/conf")) {
158a646d519SAndreas Gohr                $this->animal = $animal;
159a646d519SAndreas Gohr                return;
160a646d519SAndreas Gohr            } else {
161a646d519SAndreas Gohr                $this->notfound = true;
162a646d519SAndreas Gohr                return;
163a646d519SAndreas Gohr            }
164a646d519SAndreas Gohr        }
165a646d519SAndreas Gohr
16636282384SAndreas Gohr        // no host - no host based setup. if we're still here then it's the farmer
16736282384SAndreas Gohr        if(!isset($_SERVER['HTTP_HOST'])) return;
16836282384SAndreas Gohr
169a646d519SAndreas Gohr        // is this the farmer?
170a646d519SAndreas Gohr        if(strtolower($_SERVER['HTTP_HOST']) == $farmhost) {
171a646d519SAndreas Gohr            return;
172a646d519SAndreas Gohr        }
173a646d519SAndreas Gohr
17485becf1bSAndreas Gohr        // still here? check for host based
175a646d519SAndreas Gohr        $this->hostbased = true;
17685becf1bSAndreas Gohr        $possible = $this->getAnimalNamesForHost($_SERVER['HTTP_HOST']);
17785becf1bSAndreas Gohr        foreach($possible as $animal) {
178a646d519SAndreas Gohr            if(is_dir("$farmdir/$animal/conf/")) {
179a646d519SAndreas Gohr                $this->animal = $animal;
180a646d519SAndreas Gohr                return;
181a646d519SAndreas Gohr            }
182a646d519SAndreas Gohr        }
183a646d519SAndreas Gohr
184a646d519SAndreas Gohr        // no hit
185a646d519SAndreas Gohr        $this->notfound = true;
186a646d519SAndreas Gohr        return;
187a646d519SAndreas Gohr    }
188a646d519SAndreas Gohr
189a646d519SAndreas Gohr    /**
19085becf1bSAndreas Gohr     * Return a list of possible animal names for the given host
19185becf1bSAndreas Gohr     *
19285becf1bSAndreas Gohr     * @param string $host the HTTP_HOST header
19385becf1bSAndreas Gohr     * @return array
19485becf1bSAndreas Gohr     */
19585becf1bSAndreas Gohr    protected function getAnimalNamesForHost($host) {
19685becf1bSAndreas Gohr        $animals = array();
19785becf1bSAndreas Gohr        $parts = explode('.', implode('.', explode(':', rtrim($host, '.'))));
19885becf1bSAndreas Gohr        for($j = count($parts); $j > 0; $j--) {
19985becf1bSAndreas Gohr            // strip from the end
20085becf1bSAndreas Gohr            $animals[] = implode('.', array_slice($parts, 0, $j));
20185becf1bSAndreas Gohr            // strip from the end without host part
20285becf1bSAndreas Gohr            $animals[] = implode('.', array_slice($parts, 1, $j));
20385becf1bSAndreas Gohr        }
20485becf1bSAndreas Gohr        $animals = array_unique($animals);
20585becf1bSAndreas Gohr        $animals = array_filter($animals);
2060a5d2da2SAndreas Gohr        usort(
207bfecda9bSAndreas Gohr            $animals,
208bfecda9bSAndreas Gohr            // compare by length, then alphabet
209bfecda9bSAndreas Gohr            function ($a, $b) {
210bfecda9bSAndreas Gohr                $ret = strlen($b) - strlen($a);
211bfecda9bSAndreas Gohr                if($ret != 0) return $ret;
212bfecda9bSAndreas Gohr                return $a > $b;
2130a5d2da2SAndreas Gohr            }
2140a5d2da2SAndreas Gohr        );
21585becf1bSAndreas Gohr        return $animals;
21685becf1bSAndreas Gohr    }
21785becf1bSAndreas Gohr
21885becf1bSAndreas Gohr    /**
219a646d519SAndreas Gohr     * This sets up the default farming config cascade
220a646d519SAndreas Gohr     */
221a646d519SAndreas Gohr    protected function setupCascade() {
222a646d519SAndreas Gohr        global $config_cascade;
223a646d519SAndreas Gohr        $config_cascade = array(
224a646d519SAndreas Gohr            'main' => array(
225a646d519SAndreas Gohr                'default' => array(DOKU_INC . 'conf/dokuwiki.php',),
226a646d519SAndreas Gohr                'local' => array(DOKU_CONF . 'local.php',),
227a646d519SAndreas Gohr                'protected' => array(DOKU_CONF . 'local.protected.php',),
228a646d519SAndreas Gohr            ),
229a646d519SAndreas Gohr            'acronyms' => array(
230a646d519SAndreas Gohr                'default' => array(DOKU_INC . 'conf/acronyms.conf',),
231a646d519SAndreas Gohr                'local' => array(DOKU_CONF . 'acronyms.local.conf',),
232a646d519SAndreas Gohr            ),
233a646d519SAndreas Gohr            'entities' => array(
234a646d519SAndreas Gohr                'default' => array(DOKU_INC . 'conf/entities.conf',),
235a646d519SAndreas Gohr                'local' => array(DOKU_CONF . 'entities.local.conf',),
236a646d519SAndreas Gohr            ),
237a646d519SAndreas Gohr            'interwiki' => array(
238a646d519SAndreas Gohr                'default' => array(DOKU_INC . 'conf/interwiki.conf',),
239a646d519SAndreas Gohr                'local' => array(DOKU_CONF . 'interwiki.local.conf',),
240a646d519SAndreas Gohr            ),
241a646d519SAndreas Gohr            'license' => array(
242a646d519SAndreas Gohr                'default' => array(DOKU_INC . 'conf/license.php',),
243a646d519SAndreas Gohr                'local' => array(DOKU_CONF . 'license.local.php',),
244a646d519SAndreas Gohr            ),
24527d95445SMichael Große            'manifest' => array(
24627d95445SMichael Große                'default' => array(DOKU_INC . 'conf/manifest.json',),
24727d95445SMichael Große                'local' => array(DOKU_CONF . 'manifest.local.json',),
24827d95445SMichael Große            ),
249a646d519SAndreas Gohr            'mediameta' => array(
250a646d519SAndreas Gohr                'default' => array(DOKU_INC . 'conf/mediameta.php',),
251a646d519SAndreas Gohr                'local' => array(DOKU_CONF . 'mediameta.local.php',),
252a646d519SAndreas Gohr            ),
253a646d519SAndreas Gohr            'mime' => array(
254a646d519SAndreas Gohr                'default' => array(DOKU_INC . 'conf/mime.conf',),
255a646d519SAndreas Gohr                'local' => array(DOKU_CONF . 'mime.local.conf',),
256a646d519SAndreas Gohr            ),
257a646d519SAndreas Gohr            'scheme' => array(
258a646d519SAndreas Gohr                'default' => array(DOKU_INC . 'conf/scheme.conf',),
259a646d519SAndreas Gohr                'local' => array(DOKU_CONF . 'scheme.local.conf',),
260a646d519SAndreas Gohr            ),
261a646d519SAndreas Gohr            'smileys' => array(
262a646d519SAndreas Gohr                'default' => array(DOKU_INC . 'conf/smileys.conf',),
263a646d519SAndreas Gohr                'local' => array(DOKU_CONF . 'smileys.local.conf',),
264a646d519SAndreas Gohr            ),
265a646d519SAndreas Gohr            'wordblock' => array(
266a646d519SAndreas Gohr                'default' => array(DOKU_INC . 'conf/wordblock.conf',),
267a646d519SAndreas Gohr                'local' => array(DOKU_CONF . 'wordblock.local.conf',),
268a646d519SAndreas Gohr            ),
269a646d519SAndreas Gohr            'acl' => array(
270a646d519SAndreas Gohr                'default' => DOKU_CONF . 'acl.auth.php',
271a646d519SAndreas Gohr            ),
272a646d519SAndreas Gohr            'plainauth.users' => array(
273a646d519SAndreas Gohr                'default' => DOKU_CONF . 'users.auth.php',
274a646d519SAndreas Gohr            ),
275de156015SAndreas Gohr            'plugins' => array(
276a646d519SAndreas Gohr                'default' => array(DOKU_INC . 'conf/plugins.php',),
277a646d519SAndreas Gohr                'local' => array(DOKU_CONF . 'plugins.local.php',),
278a646d519SAndreas Gohr                'protected' => array(
279a646d519SAndreas Gohr                    DOKU_INC . 'conf/plugins.required.php',
280a646d519SAndreas Gohr                    DOKU_CONF . 'plugins.protected.php',
281a646d519SAndreas Gohr                ),
282a646d519SAndreas Gohr            ),
283a646d519SAndreas Gohr            'userstyle' => array(
284a646d519SAndreas Gohr                'screen' => array(DOKU_CONF . 'userstyle.css', DOKU_CONF . 'userstyle.less',),
285a646d519SAndreas Gohr                'print' => array(DOKU_CONF . 'userprint.css', DOKU_CONF . 'userprint.less',),
286a646d519SAndreas Gohr                'feed' => array(DOKU_CONF . 'userfeed.css', DOKU_CONF . 'userfeed.less',),
287a646d519SAndreas Gohr                'all' => array(DOKU_CONF . 'userall.css', DOKU_CONF . 'userall.less',),
288a646d519SAndreas Gohr            ),
289a646d519SAndreas Gohr            'userscript' => array(
290a646d519SAndreas Gohr                'default' => array(DOKU_CONF . 'userscript.js',),
291a646d519SAndreas Gohr            ),
29205ea7625SAnna Dabrowska            'styleini' => array(
293bdb1e6e9SAnna Dabrowska                'default'   => array(DOKU_INC . 'lib/tpl/%TEMPLATE%/' . 'style.ini'),
294bdb1e6e9SAnna Dabrowska                'local'     => array(DOKU_CONF . 'tpl/%TEMPLATE%/' . 'style.ini')
29505ea7625SAnna Dabrowska            ),
296a646d519SAndreas Gohr        );
297a646d519SAndreas Gohr    }
298a646d519SAndreas Gohr
299a646d519SAndreas Gohr    /**
300a646d519SAndreas Gohr     * This adds additional files to the config cascade based on the inheritence settings
301a646d519SAndreas Gohr     *
302a646d519SAndreas Gohr     * These are only added for animals, not the farmer
303a646d519SAndreas Gohr     */
304a646d519SAndreas Gohr    protected function adjustCascade() {
305b330074aSAndreas Gohr        // nothing to do when on the farmer:
306b330074aSAndreas Gohr        if(!$this->animal) return;
307a646d519SAndreas Gohr
308b330074aSAndreas Gohr        global $config_cascade;
309a646d519SAndreas Gohr        foreach($this->config['inherit'] as $key => $val) {
310a646d519SAndreas Gohr            if(!$val) continue;
311a646d519SAndreas Gohr
312a646d519SAndreas Gohr            // prepare what is to append or prepend
313a646d519SAndreas Gohr            $append = array();
314a646d519SAndreas Gohr            $prepend = array();
315a646d519SAndreas Gohr            if($key == 'main') {
316b330074aSAndreas Gohr                $append = array(
317b330074aSAndreas Gohr                    'default' => array(DOKU_INC . 'conf/local.php'),
318b330074aSAndreas Gohr                    'protected' => array(DOKU_INC . 'lib/plugins/farmer/includes/config.php')
319b330074aSAndreas Gohr                );
320a646d519SAndreas Gohr            } elseif($key == 'license') {
321a646d519SAndreas Gohr                $append = array('default' => array(DOKU_INC . 'conf/' . $key . '.local.php'));
322a646d519SAndreas Gohr            } elseif($key == 'userscript') {
323a646d519SAndreas Gohr                $prepend = array('default' => array(DOKU_INC . 'conf/userscript.js'));
324a646d519SAndreas Gohr            } elseif($key == 'userstyle') {
325a646d519SAndreas Gohr                $prepend = array(
326a646d519SAndreas Gohr                    'screen' => array(DOKU_INC . 'conf/userstyle.css', DOKU_INC . 'conf/userstyle.less',),
327a646d519SAndreas Gohr                    'print' => array(DOKU_INC . 'conf/userprint.css', DOKU_INC . 'conf/userprint.less',),
328a646d519SAndreas Gohr                    'feed' => array(DOKU_INC . 'conf/userfeed.css', DOKU_INC . 'conf/userfeed.less',),
329a646d519SAndreas Gohr                    'all' => array(DOKU_INC . 'conf/userall.css', DOKU_INC . 'conf/userall.less',),
330a646d519SAndreas Gohr                );
33105ea7625SAnna Dabrowska            } elseif ($key == 'styleini') {
33205ea7625SAnna Dabrowska                $append = array(
33305ea7625SAnna Dabrowska                    'local' => array(
3343cee9885SAnna Dabrowska                        DOKU_INC . 'conf/tpl/%TEMPLATE%/style.ini'
33505ea7625SAnna Dabrowska                    )
33605ea7625SAnna Dabrowska                );
3371272da0cSAndreas Gohr            } elseif($key == 'users') {
3381272da0cSAndreas Gohr                $config_cascade['plainauth.users']['protected'] = DOKU_INC . 'conf/users.auth.php';
339af1c6dd8SAndreas Gohr            } elseif($key == 'plugins') {
340af1c6dd8SAndreas Gohr                $append = array('default' => array(DOKU_INC . 'conf/plugins.local.php'));
341a646d519SAndreas Gohr            } else {
342a646d519SAndreas Gohr                $append = array('default' => array(DOKU_INC . 'conf/' . $key . '.local.conf'));
343a646d519SAndreas Gohr            }
344a646d519SAndreas Gohr
345a646d519SAndreas Gohr            // add to cascade
346a646d519SAndreas Gohr            foreach($prepend as $section => $data) {
347a646d519SAndreas Gohr                $config_cascade[$key][$section] = array_merge($data, $config_cascade[$key][$section]);
348a646d519SAndreas Gohr            }
349a646d519SAndreas Gohr            foreach($append as $section => $data) {
350a646d519SAndreas Gohr                $config_cascade[$key][$section] = array_merge($config_cascade[$key][$section], $data);
351a646d519SAndreas Gohr            }
352a646d519SAndreas Gohr        }
353de156015SAndreas Gohr
354de156015SAndreas Gohr        // add plugin overrides
355de156015SAndreas Gohr        $config_cascade['plugins']['protected'][] = DOKU_INC . 'lib/plugins/farmer/includes/plugins.php';
356a646d519SAndreas Gohr    }
357a646d519SAndreas Gohr
358a646d519SAndreas Gohr    /**
359da0ae2c0SAndreas Gohr     * Loads the farm config
360da0ae2c0SAndreas Gohr     */
361da0ae2c0SAndreas Gohr    protected function loadConfig() {
362da0ae2c0SAndreas Gohr        $ini = DOKU_INC . 'conf/farm.ini';
363da0ae2c0SAndreas Gohr        if(!file_exists($ini)) return;
364da0ae2c0SAndreas Gohr        $config = parse_ini_file($ini, true);
365da0ae2c0SAndreas Gohr        foreach(array_keys($this->config) as $section) {
366da0ae2c0SAndreas Gohr            if(isset($config[$section])) {
367da0ae2c0SAndreas Gohr                $this->config[$section] = array_merge(
368da0ae2c0SAndreas Gohr                    $this->config[$section],
369da0ae2c0SAndreas Gohr                    $config[$section]
370da0ae2c0SAndreas Gohr                );
371da0ae2c0SAndreas Gohr            }
372da0ae2c0SAndreas Gohr        }
373da0ae2c0SAndreas Gohr
374a646d519SAndreas Gohr        $this->config['base']['farmdir'] = trim($this->config['base']['farmdir']);
375a646d519SAndreas Gohr        $this->config['base']['farmhost'] = strtolower(trim($this->config['base']['farmhost']));
376a646d519SAndreas Gohr    }
377da0ae2c0SAndreas Gohr
378da0ae2c0SAndreas Gohr}
379da0ae2c0SAndreas Gohr
380da0ae2c0SAndreas Gohr// initialize it globally
38185becf1bSAndreas Gohrif(!defined('DOKU_UNITTEST')) {
382da0ae2c0SAndreas Gohr    global $FARMCORE;
383da0ae2c0SAndreas Gohr    $FARMCORE = new DokuWikiFarmCore();
38485becf1bSAndreas Gohr}
385