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