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