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