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