1da0ae2c0SAndreas Gohr<?php 2da0ae2c0SAndreas Gohr 31da41c8bSAndreas Gohr// phpcs:disable PSR1.Files.SideEffects 4*c468f8caSAndreas Gohr 5a646d519SAndreas Gohr/** 6a646d519SAndreas Gohr * Core Manager for the Farm functionality 7a646d519SAndreas Gohr * 8a646d519SAndreas Gohr * This class is initialized before any other DokuWiki code runs. Therefore it is 9a646d519SAndreas Gohr * completely selfcontained and does not use any of DokuWiki's utility functions. 10a646d519SAndreas Gohr * 11b96c66ccSAndreas Gohr * It's registered as a global $FARMCORE variable but you should not interact with 12b96c66ccSAndreas Gohr * it directly. Instead use the Farmer plugin's helper component. 130a5d2da2SAndreas Gohr * 140a5d2da2SAndreas Gohr * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html 150a5d2da2SAndreas Gohr * @author Andreas Gohr <gohr@cosmocode.de> 16a646d519SAndreas Gohr */ 171da41c8bSAndreas Gohrclass DokuWikiFarmCore 181da41c8bSAndreas Gohr{ 19da0ae2c0SAndreas Gohr /** 20da0ae2c0SAndreas Gohr * @var array The default config - changed by loadConfig 21da0ae2c0SAndreas Gohr */ 221da41c8bSAndreas Gohr protected $config = [ 231da41c8bSAndreas Gohr 'base' => [ 24a646d519SAndreas Gohr 'farmdir' => '', 25c4c8e953SAndreas Gohr 'farmhost' => '', 261da41c8bSAndreas Gohr 'basedomain' => '' 271da41c8bSAndreas Gohr ], 281da41c8bSAndreas Gohr 'notfound' => [ 29da0ae2c0SAndreas Gohr 'show' => 'farmer', 30da0ae2c0SAndreas Gohr 'url' => '' 311da41c8bSAndreas Gohr ], 321da41c8bSAndreas Gohr 'inherit' => [ 33da0ae2c0SAndreas Gohr 'main' => 1, 34da0ae2c0SAndreas Gohr 'acronyms' => 1, 35da0ae2c0SAndreas Gohr 'entities' => 1, 36da0ae2c0SAndreas Gohr 'interwiki' => 1, 37da0ae2c0SAndreas Gohr 'license' => 1, 38da0ae2c0SAndreas Gohr 'mime' => 1, 39da0ae2c0SAndreas Gohr 'scheme' => 1, 40da0ae2c0SAndreas Gohr 'smileys' => 1, 41da0ae2c0SAndreas Gohr 'wordblock' => 1, 421272da0cSAndreas Gohr 'users' => 0, 43af1c6dd8SAndreas Gohr 'plugins' => 0, 44da0ae2c0SAndreas Gohr 'userstyle' => 0, 4505ea7625SAnna Dabrowska 'userscript' => 0, 463cee9885SAnna Dabrowska 'styleini' => 0 471da41c8bSAndreas Gohr ] 481da41c8bSAndreas Gohr ]; 49da0ae2c0SAndreas Gohr 50a646d519SAndreas Gohr /** @var string|false The current animal, false for farmer */ 51a646d519SAndreas Gohr protected $animal = false; 52a646d519SAndreas Gohr /** @var bool true if an animal was requested but was not found */ 53a646d519SAndreas Gohr protected $notfound = false; 54a646d519SAndreas Gohr /** @var bool true if the current animal was requested by host */ 55a646d519SAndreas Gohr protected $hostbased = false; 56a646d519SAndreas Gohr 57da0ae2c0SAndreas Gohr /** 58da0ae2c0SAndreas Gohr * DokuWikiFarmCore constructor. 59da0ae2c0SAndreas Gohr * 60a646d519SAndreas Gohr * This initializes the whole farm by loading the configuration and setting 61a646d519SAndreas Gohr * DOKU_CONF depending on the requested animal 62da0ae2c0SAndreas Gohr */ 631da41c8bSAndreas Gohr public function __construct() 641da41c8bSAndreas Gohr { 65da0ae2c0SAndreas Gohr $this->loadConfig(); 66a646d519SAndreas Gohr if ($this->config['base']['farmdir'] === '') return; // farm setup not complete 678262a4cbSAndreas Gohr $this->config['base']['farmdir'] = rtrim($this->config['base']['farmdir'], '/') . '/'; // trailing slash always 6849f2871cSAndreas Gohr define('DOKU_FARMDIR', $this->config['base']['farmdir']); 69a646d519SAndreas Gohr 70a646d519SAndreas Gohr // animal? 71a646d519SAndreas Gohr $this->detectAnimal(); 72a646d519SAndreas Gohr 73a646d519SAndreas Gohr // setup defines 74a646d519SAndreas Gohr define('DOKU_FARM_ANIMAL', $this->animal); 75a646d519SAndreas Gohr if ($this->animal) { 768262a4cbSAndreas Gohr define('DOKU_CONF', DOKU_FARMDIR . $this->animal . '/conf/'); 77a646d519SAndreas Gohr } else { 78a646d519SAndreas Gohr define('DOKU_CONF', DOKU_INC . '/conf/'); 79a646d519SAndreas Gohr } 80a646d519SAndreas Gohr 81a646d519SAndreas Gohr $this->setupCascade(); 82a646d519SAndreas Gohr $this->adjustCascade(); 83da0ae2c0SAndreas Gohr } 84da0ae2c0SAndreas Gohr 85da0ae2c0SAndreas Gohr /** 86da0ae2c0SAndreas Gohr * @return array the current farm configuration 87da0ae2c0SAndreas Gohr */ 881da41c8bSAndreas Gohr public function getConfig() 891da41c8bSAndreas Gohr { 90da0ae2c0SAndreas Gohr return $this->config; 91da0ae2c0SAndreas Gohr } 92da0ae2c0SAndreas Gohr 93da0ae2c0SAndreas Gohr /** 94a646d519SAndreas Gohr * @return false|string 95a646d519SAndreas Gohr */ 961da41c8bSAndreas Gohr public function getAnimal() 971da41c8bSAndreas Gohr { 98a646d519SAndreas Gohr return $this->animal; 99a646d519SAndreas Gohr } 100a646d519SAndreas Gohr 101a646d519SAndreas Gohr /** 102a646d519SAndreas Gohr * @return boolean 103a646d519SAndreas Gohr */ 1041da41c8bSAndreas Gohr public function isHostbased() 1051da41c8bSAndreas Gohr { 106a646d519SAndreas Gohr return $this->hostbased; 107a646d519SAndreas Gohr } 108a646d519SAndreas Gohr 109a646d519SAndreas Gohr /** 110a646d519SAndreas Gohr * @return boolean 111a646d519SAndreas Gohr */ 1121da41c8bSAndreas Gohr public function wasNotfound() 1131da41c8bSAndreas Gohr { 114a646d519SAndreas Gohr return $this->notfound; 115a646d519SAndreas Gohr } 116a646d519SAndreas Gohr 117a646d519SAndreas Gohr /** 118b330074aSAndreas Gohr * @return string 119b330074aSAndreas Gohr */ 1201da41c8bSAndreas Gohr public function getAnimalDataDir() 1211da41c8bSAndreas Gohr { 1228262a4cbSAndreas Gohr return DOKU_FARMDIR . $this->getAnimal() . '/data/'; 123b330074aSAndreas Gohr } 124b330074aSAndreas Gohr 125b330074aSAndreas Gohr /** 126b330074aSAndreas Gohr * @return string 127b330074aSAndreas Gohr */ 1281da41c8bSAndreas Gohr public function getAnimalBaseDir() 1291da41c8bSAndreas Gohr { 13004dc6bd5SSzymon Olewniczak if ($this->isHostbased()) return '/'; 131b330074aSAndreas Gohr return getBaseURL() . '!' . $this->getAnimal(); 132b330074aSAndreas Gohr } 133b330074aSAndreas Gohr 134b330074aSAndreas Gohr /** 135*c468f8caSAndreas Gohr * Set the animal 136a646d519SAndreas Gohr * 137*c468f8caSAndreas Gohr * Checks if the animal exists and is a valid directory name. 138a646d519SAndreas Gohr * 139*c468f8caSAndreas Gohr * @param mixed $animal the animal name 140*c468f8caSAndreas Gohr * @return bool returns true if the animal was set successfully, false otherwise 141a646d519SAndreas Gohr */ 142*c468f8caSAndreas Gohr protected function setAnimal($animal) 1431da41c8bSAndreas Gohr { 144a646d519SAndreas Gohr $farmdir = $this->config['base']['farmdir']; 145a646d519SAndreas Gohr 146*c468f8caSAndreas Gohr // invalid animal stuff is always a not found 147a646d519SAndreas Gohr if (!is_string($animal) || strpbrk($animal, '\\/') !== false) { 148a646d519SAndreas Gohr $this->notfound = true; 149*c468f8caSAndreas Gohr return false; 150*c468f8caSAndreas Gohr } 151a646d519SAndreas Gohr $animal = strtolower($animal); 152a646d519SAndreas Gohr 153a646d519SAndreas Gohr // check if animal exists 154a646d519SAndreas Gohr if (is_dir("$farmdir/$animal/conf")) { 155a646d519SAndreas Gohr $this->animal = $animal; 156*c468f8caSAndreas Gohr $this->notfound = false; 157*c468f8caSAndreas Gohr return true; 158a646d519SAndreas Gohr } else { 159a646d519SAndreas Gohr $this->notfound = true; 160*c468f8caSAndreas Gohr return false; 161a646d519SAndreas Gohr } 162a646d519SAndreas Gohr } 163a646d519SAndreas Gohr 164*c468f8caSAndreas Gohr /** 165*c468f8caSAndreas Gohr * Detect the animal from the given query string 166*c468f8caSAndreas Gohr * 167*c468f8caSAndreas Gohr * This removes the animal parameter from the given string and sets the animal 168*c468f8caSAndreas Gohr * 169*c468f8caSAndreas Gohr * @param string $queryString The query string to extract the animal from, will be modified 170*c468f8caSAndreas Gohr * @return bool true if the animal was set successfully, false otherwise 171*c468f8caSAndreas Gohr */ 172*c468f8caSAndreas Gohr protected function detectAnimalFromQueryString(string &$queryString): bool 173*c468f8caSAndreas Gohr { 174*c468f8caSAndreas Gohr $params = []; 175*c468f8caSAndreas Gohr parse_str($queryString, $params); 176*c468f8caSAndreas Gohr if (!isset($params['animal'])) return false; 177*c468f8caSAndreas Gohr $animal = $params['animal']; 178*c468f8caSAndreas Gohr unset($params['animal']); 179*c468f8caSAndreas Gohr $queryString = http_build_query($params); 180*c468f8caSAndreas Gohr 181*c468f8caSAndreas Gohr $this->hostbased = false; 182*c468f8caSAndreas Gohr return $this->setAnimal($animal); 183*c468f8caSAndreas Gohr } 184*c468f8caSAndreas Gohr 185*c468f8caSAndreas Gohr /** 186*c468f8caSAndreas Gohr * Detect the animal from the bang path 187*c468f8caSAndreas Gohr * 188*c468f8caSAndreas Gohr * This is used to detect the animal from a bang path like `/!animal/my:page` or '/dokuwiki/!animal/my:page'. 189*c468f8caSAndreas Gohr * 190*c468f8caSAndreas Gohr * @param string $path The bang path to extract the animal from 191*c468f8caSAndreas Gohr * @return bool true if the animal was set successfully, false otherwise 192*c468f8caSAndreas Gohr */ 193*c468f8caSAndreas Gohr protected function detectAnimalFromBangPath(string $path): bool 194*c468f8caSAndreas Gohr { 195*c468f8caSAndreas Gohr $bangregex = '#^(/(?:[^/]*/)*)!([^/]+)/#'; 196*c468f8caSAndreas Gohr if (preg_match($bangregex, $path, $matches)) { 197*c468f8caSAndreas Gohr // found a bang path 198*c468f8caSAndreas Gohr $animal = $matches[2]; 199*c468f8caSAndreas Gohr 200*c468f8caSAndreas Gohr $this->hostbased = false; 201*c468f8caSAndreas Gohr return $this->setAnimal($animal); 202*c468f8caSAndreas Gohr } 203*c468f8caSAndreas Gohr return false; 204*c468f8caSAndreas Gohr } 205*c468f8caSAndreas Gohr 206*c468f8caSAndreas Gohr /** 207*c468f8caSAndreas Gohr * Detect the animal from the host name 208*c468f8caSAndreas Gohr * 209*c468f8caSAndreas Gohr * @param string $host The hostname 210*c468f8caSAndreas Gohr * @return bool true if the animal was set successfully, false otherwise 211*c468f8caSAndreas Gohr */ 212*c468f8caSAndreas Gohr protected function detectAnimalFromHostName(string $host): bool 213*c468f8caSAndreas Gohr { 214*c468f8caSAndreas Gohr $possible = $this->getAnimalNamesForHost($host); 215*c468f8caSAndreas Gohr foreach ($possible as $animal) { 216*c468f8caSAndreas Gohr if ($this->setAnimal($animal)) { 217*c468f8caSAndreas Gohr $this->hostbased = true; 218*c468f8caSAndreas Gohr return true; 219*c468f8caSAndreas Gohr } 220*c468f8caSAndreas Gohr } 221*c468f8caSAndreas Gohr return false; 222*c468f8caSAndreas Gohr } 223*c468f8caSAndreas Gohr 224*c468f8caSAndreas Gohr /** 225*c468f8caSAndreas Gohr * Detect the current animal 226*c468f8caSAndreas Gohr * 227*c468f8caSAndreas Gohr * Sets internal members $animal, $notfound and $hostbased 228*c468f8caSAndreas Gohr * 229*c468f8caSAndreas Gohr * This borrows form DokuWiki's inc/farm.php but does not support a default conf dir 230*c468f8caSAndreas Gohr * 231*c468f8caSAndreas Gohr * @params string|null $sapi the SAPI to use. Only changed during testing 232*c468f8caSAndreas Gohr */ 233*c468f8caSAndreas Gohr protected function detectAnimal($sapi = null) 234*c468f8caSAndreas Gohr { 235*c468f8caSAndreas Gohr $sapi = $sapi ?: PHP_SAPI; 236*c468f8caSAndreas Gohr 237*c468f8caSAndreas Gohr $farmdir = $this->config['base']['farmdir']; 238*c468f8caSAndreas Gohr $farmhost = $this->config['base']['farmhost']; 239*c468f8caSAndreas Gohr 240*c468f8caSAndreas Gohr if ('cli' == $sapi) { 241*c468f8caSAndreas Gohr if (!isset($_SERVER['animal'])) return; // no animal parameter given - we're the farmer 242*c468f8caSAndreas Gohr 243*c468f8caSAndreas Gohr if (preg_match('#^https?://#i', $_SERVER['animal'])) { 244*c468f8caSAndreas Gohr // CLI animal parameter is a URL 245*c468f8caSAndreas Gohr $urlparts = parse_url($_SERVER['animal']); 246*c468f8caSAndreas Gohr $urlparts['query'] ??= ''; 247*c468f8caSAndreas Gohr 248*c468f8caSAndreas Gohr // detect the animal from the URL 249*c468f8caSAndreas Gohr $this->detectAnimalFromQueryString($urlparts['query']) || 250*c468f8caSAndreas Gohr $this->detectAnimalFromBangPath($urlparts['path']) || 251*c468f8caSAndreas Gohr $this->detectAnimalFromHostName($urlparts['host']); 252*c468f8caSAndreas Gohr 253*c468f8caSAndreas Gohr // fake baseurl etc. 254*c468f8caSAndreas Gohr $this->injectServerEnvironment($urlparts); 255*c468f8caSAndreas Gohr } else { 256*c468f8caSAndreas Gohr // CLI animal parameter is just a name 257*c468f8caSAndreas Gohr $this->setAnimal(strtolower($_SERVER['animal'])); 258*c468f8caSAndreas Gohr } 259*c468f8caSAndreas Gohr 260*c468f8caSAndreas Gohr } else { 261*c468f8caSAndreas Gohr // an animal url parameter has been set 262*c468f8caSAndreas Gohr if (isset($_GET['animal'])) { 263*c468f8caSAndreas Gohr $this->detectAnimalFromQueryString($_SERVER['QUERY_STRING']); 264*c468f8caSAndreas Gohr unset($_GET['animal']); 265*c468f8caSAndreas Gohr return; 266*c468f8caSAndreas Gohr } 267*c468f8caSAndreas Gohr 26836282384SAndreas Gohr // no host - no host based setup. if we're still here then it's the farmer 269*c468f8caSAndreas Gohr if (empty($_SERVER['HTTP_HOST'])) return; 27036282384SAndreas Gohr 271a646d519SAndreas Gohr // is this the farmer? 272a646d519SAndreas Gohr if (strtolower($_SERVER['HTTP_HOST']) == $farmhost) { 273a646d519SAndreas Gohr return; 274a646d519SAndreas Gohr } 275a646d519SAndreas Gohr 276*c468f8caSAndreas Gohr // we're in host based mode now 277a646d519SAndreas Gohr $this->hostbased = true; 278*c468f8caSAndreas Gohr 279*c468f8caSAndreas Gohr // we should get an animal now 280*c468f8caSAndreas Gohr if (!$this->detectAnimalFromHostName($_SERVER['HTTP_HOST'])) { 281*c468f8caSAndreas Gohr $this->notfound = true; 282*c468f8caSAndreas Gohr } 283a646d519SAndreas Gohr } 284a646d519SAndreas Gohr } 285a646d519SAndreas Gohr 286*c468f8caSAndreas Gohr /** 287*c468f8caSAndreas Gohr * Create Server environment variables for the current animal 288*c468f8caSAndreas Gohr * 289*c468f8caSAndreas Gohr * This is called when the animal is initialized on the command line using a full URL. 290*c468f8caSAndreas Gohr * Since the initialization is running before any configuration is loaded, we instead 291*c468f8caSAndreas Gohr * set the $_SERVER variables that will later be used to autodetect the base URL. This 292*c468f8caSAndreas Gohr * way a manually set base URL will still take precedence. 293*c468f8caSAndreas Gohr * 294*c468f8caSAndreas Gohr * @param array $urlparts A parse_url() result array 295*c468f8caSAndreas Gohr * @return void 296*c468f8caSAndreas Gohr * @see is_ssl() 297*c468f8caSAndreas Gohr * @see getBaseURL() 298*c468f8caSAndreas Gohr */ 299*c468f8caSAndreas Gohr protected function injectServerEnvironment(array $urlparts) 300*c468f8caSAndreas Gohr { 301*c468f8caSAndreas Gohr // prepare data for DOKU_REL 302*c468f8caSAndreas Gohr $path = $urlparts['path'] ?? '/'; 303*c468f8caSAndreas Gohr if (($bangpos = strpos($path, '!')) !== false) { 304*c468f8caSAndreas Gohr // strip from the bang path 305*c468f8caSAndreas Gohr $path = substr($path, 0, $bangpos); 306*c468f8caSAndreas Gohr } 307*c468f8caSAndreas Gohr if (!str_ends_with($path, '.php')) { 308*c468f8caSAndreas Gohr // make sure we have a script name 309*c468f8caSAndreas Gohr $path = rtrim($path, '/') . '/doku.php'; 310*c468f8caSAndreas Gohr } 311*c468f8caSAndreas Gohr $_SERVER['SCRIPT_NAME'] = $path; 312*c468f8caSAndreas Gohr 313*c468f8caSAndreas Gohr // prepare data for is_ssl() 314*c468f8caSAndreas Gohr if (($urlparts['scheme'] ?? '') === 'https') { 315*c468f8caSAndreas Gohr $_SERVER['HTTPS'] = 'on'; 316*c468f8caSAndreas Gohr } else { 317*c468f8caSAndreas Gohr $_SERVER['HTTPS'] = 'off'; 318*c468f8caSAndreas Gohr } 319*c468f8caSAndreas Gohr 320*c468f8caSAndreas Gohr // prepare data for DOKU_URL 321*c468f8caSAndreas Gohr $_SERVER['HTTP_HOST'] = $urlparts['host'] ?? ''; 322*c468f8caSAndreas Gohr if (isset($urlparts['port'])) { 323*c468f8caSAndreas Gohr $_SERVER['HTTP_HOST'] .= ':' . $urlparts['port']; 324*c468f8caSAndreas Gohr } 325a646d519SAndreas Gohr } 326a646d519SAndreas Gohr 327a646d519SAndreas Gohr /** 32885becf1bSAndreas Gohr * Return a list of possible animal names for the given host 32985becf1bSAndreas Gohr * 33085becf1bSAndreas Gohr * @param string $host the HTTP_HOST header 33185becf1bSAndreas Gohr * @return array 33285becf1bSAndreas Gohr */ 3331da41c8bSAndreas Gohr protected function getAnimalNamesForHost($host) 3341da41c8bSAndreas Gohr { 3351da41c8bSAndreas Gohr $animals = []; 33685becf1bSAndreas Gohr $parts = explode('.', implode('.', explode(':', rtrim($host, '.')))); 33785becf1bSAndreas Gohr for ($j = count($parts); $j > 0; $j--) { 33885becf1bSAndreas Gohr // strip from the end 33985becf1bSAndreas Gohr $animals[] = implode('.', array_slice($parts, 0, $j)); 34085becf1bSAndreas Gohr // strip from the end without host part 34185becf1bSAndreas Gohr $animals[] = implode('.', array_slice($parts, 1, $j)); 34285becf1bSAndreas Gohr } 34385becf1bSAndreas Gohr $animals = array_unique($animals); 34485becf1bSAndreas Gohr $animals = array_filter($animals); 3450a5d2da2SAndreas Gohr usort( 346bfecda9bSAndreas Gohr $animals, 347bfecda9bSAndreas Gohr // compare by length, then alphabet 348bfecda9bSAndreas Gohr function ($a, $b) { 349bfecda9bSAndreas Gohr $ret = strlen($b) - strlen($a); 350bfecda9bSAndreas Gohr if ($ret != 0) return $ret; 351a2a8c90bSAndreas Gohr return $a <=> $b; 3520a5d2da2SAndreas Gohr } 3530a5d2da2SAndreas Gohr ); 35485becf1bSAndreas Gohr return $animals; 35585becf1bSAndreas Gohr } 35685becf1bSAndreas Gohr 35785becf1bSAndreas Gohr /** 358a646d519SAndreas Gohr * This sets up the default farming config cascade 359a646d519SAndreas Gohr */ 3601da41c8bSAndreas Gohr protected function setupCascade() 3611da41c8bSAndreas Gohr { 362a646d519SAndreas Gohr global $config_cascade; 3631da41c8bSAndreas Gohr $config_cascade = [ 3641da41c8bSAndreas Gohr 'main' => [ 3651da41c8bSAndreas Gohr 'default' => [DOKU_INC . 'conf/dokuwiki.php'], 3661da41c8bSAndreas Gohr 'local' => [DOKU_CONF . 'local.php'], 3671da41c8bSAndreas Gohr 'protected' => [DOKU_CONF . 'local.protected.php'] 3681da41c8bSAndreas Gohr ], 3691da41c8bSAndreas Gohr 'acronyms' => [ 3701da41c8bSAndreas Gohr 'default' => [DOKU_INC . 'conf/acronyms.conf'], 3711da41c8bSAndreas Gohr 'local' => [DOKU_CONF . 'acronyms.local.conf'] 3721da41c8bSAndreas Gohr ], 3731da41c8bSAndreas Gohr 'entities' => [ 3741da41c8bSAndreas Gohr 'default' => [DOKU_INC . 'conf/entities.conf'], 3751da41c8bSAndreas Gohr 'local' => [DOKU_CONF . 'entities.local.conf'] 3761da41c8bSAndreas Gohr ], 3771da41c8bSAndreas Gohr 'interwiki' => [ 3781da41c8bSAndreas Gohr 'default' => [DOKU_INC . 'conf/interwiki.conf'], 3791da41c8bSAndreas Gohr 'local' => [DOKU_CONF . 'interwiki.local.conf'] 3801da41c8bSAndreas Gohr ], 3811da41c8bSAndreas Gohr 'license' => [ 3821da41c8bSAndreas Gohr 'default' => [DOKU_INC . 'conf/license.php'], 3831da41c8bSAndreas Gohr 'local' => [DOKU_CONF . 'license.local.php'] 3841da41c8bSAndreas Gohr ], 3851da41c8bSAndreas Gohr 'manifest' => [ 3861da41c8bSAndreas Gohr 'default' => [DOKU_INC . 'conf/manifest.json'], 3871da41c8bSAndreas Gohr 'local' => [DOKU_CONF . 'manifest.local.json'] 3881da41c8bSAndreas Gohr ], 3891da41c8bSAndreas Gohr 'mediameta' => [ 3901da41c8bSAndreas Gohr 'default' => [DOKU_INC . 'conf/mediameta.php'], 3911da41c8bSAndreas Gohr 'local' => [DOKU_CONF . 'mediameta.local.php'] 3921da41c8bSAndreas Gohr ], 3931da41c8bSAndreas Gohr 'mime' => [ 3941da41c8bSAndreas Gohr 'default' => [DOKU_INC . 'conf/mime.conf'], 3951da41c8bSAndreas Gohr 'local' => [DOKU_CONF . 'mime.local.conf'] 3961da41c8bSAndreas Gohr ], 3971da41c8bSAndreas Gohr 'scheme' => [ 3981da41c8bSAndreas Gohr 'default' => [DOKU_INC . 'conf/scheme.conf'], 3991da41c8bSAndreas Gohr 'local' => [DOKU_CONF . 'scheme.local.conf'] 4001da41c8bSAndreas Gohr ], 4011da41c8bSAndreas Gohr 'smileys' => [ 4021da41c8bSAndreas Gohr 'default' => [DOKU_INC . 'conf/smileys.conf'], 4031da41c8bSAndreas Gohr 'local' => [DOKU_CONF . 'smileys.local.conf'] 4041da41c8bSAndreas Gohr ], 4051da41c8bSAndreas Gohr 'wordblock' => [ 4061da41c8bSAndreas Gohr 'default' => [DOKU_INC . 'conf/wordblock.conf'], 4071da41c8bSAndreas Gohr 'local' => [DOKU_CONF . 'wordblock.local.conf'] 4081da41c8bSAndreas Gohr ], 4091da41c8bSAndreas Gohr 'acl' => [ 4101da41c8bSAndreas Gohr 'default' => DOKU_CONF . 'acl.auth.php' 4111da41c8bSAndreas Gohr ], 4121da41c8bSAndreas Gohr 'plainauth.users' => [ 4131da41c8bSAndreas Gohr 'default' => DOKU_CONF . 'users.auth.php' 4141da41c8bSAndreas Gohr ], 4151da41c8bSAndreas Gohr 'plugins' => [ 4161da41c8bSAndreas Gohr 'default' => [DOKU_INC . 'conf/plugins.php'], 4171da41c8bSAndreas Gohr 'local' => [DOKU_CONF . 'plugins.local.php'], 4181da41c8bSAndreas Gohr 'protected' => [ 419a646d519SAndreas Gohr DOKU_INC . 'conf/plugins.required.php', 4201da41c8bSAndreas Gohr DOKU_CONF . 'plugins.protected.php' 4211da41c8bSAndreas Gohr ] 4221da41c8bSAndreas Gohr ], 4231da41c8bSAndreas Gohr 'userstyle' => [ 4241da41c8bSAndreas Gohr 'screen' => [ 4251da41c8bSAndreas Gohr DOKU_CONF . 'userstyle.css', 4261da41c8bSAndreas Gohr DOKU_CONF . 'userstyle.less' 4271da41c8bSAndreas Gohr ], 4281da41c8bSAndreas Gohr 'print' => [ 4291da41c8bSAndreas Gohr DOKU_CONF . 'userprint.css', 4301da41c8bSAndreas Gohr DOKU_CONF . 'userprint.less' 4311da41c8bSAndreas Gohr ], 4321da41c8bSAndreas Gohr 'feed' => [ 4331da41c8bSAndreas Gohr DOKU_CONF . 'userfeed.css', 4341da41c8bSAndreas Gohr DOKU_CONF . 'userfeed.less' 4351da41c8bSAndreas Gohr ], 4361da41c8bSAndreas Gohr 'all' => [ 4371da41c8bSAndreas Gohr DOKU_CONF . 'userall.css', 4381da41c8bSAndreas Gohr DOKU_CONF . 'userall.less' 4391da41c8bSAndreas Gohr ] 4401da41c8bSAndreas Gohr ], 4411da41c8bSAndreas Gohr 'userscript' => [ 4421da41c8bSAndreas Gohr 'default' => [DOKU_CONF . 'userscript.js'] 4431da41c8bSAndreas Gohr ], 4441da41c8bSAndreas Gohr 'styleini' => [ 4451da41c8bSAndreas Gohr 'default' => [DOKU_INC . 'lib/tpl/%TEMPLATE%/' . 'style.ini'], 4461da41c8bSAndreas Gohr 'local' => [DOKU_CONF . 'tpl/%TEMPLATE%/' . 'style.ini'] 4471da41c8bSAndreas Gohr ] 4481da41c8bSAndreas Gohr ]; 449a646d519SAndreas Gohr } 450a646d519SAndreas Gohr 451a646d519SAndreas Gohr /** 452a646d519SAndreas Gohr * This adds additional files to the config cascade based on the inheritence settings 453a646d519SAndreas Gohr * 454a646d519SAndreas Gohr * These are only added for animals, not the farmer 455a646d519SAndreas Gohr */ 4561da41c8bSAndreas Gohr protected function adjustCascade() 4571da41c8bSAndreas Gohr { 458b330074aSAndreas Gohr // nothing to do when on the farmer: 459b330074aSAndreas Gohr if (!$this->animal) return; 460a646d519SAndreas Gohr 461b330074aSAndreas Gohr global $config_cascade; 462a646d519SAndreas Gohr foreach ($this->config['inherit'] as $key => $val) { 463a646d519SAndreas Gohr if (!$val) continue; 464a646d519SAndreas Gohr 465a646d519SAndreas Gohr // prepare what is to append or prepend 4661da41c8bSAndreas Gohr $append = []; 4671da41c8bSAndreas Gohr $prepend = []; 468a646d519SAndreas Gohr if ($key == 'main') { 4694b1aad07Satisne $prepend = [ 4704b1aad07Satisne 'protected' => [DOKU_INC . 'conf/local.protected.php'] 4714b1aad07Satisne ]; 4721da41c8bSAndreas Gohr $append = [ 4731da41c8bSAndreas Gohr 'default' => [DOKU_INC . 'conf/local.php'], 4741da41c8bSAndreas Gohr 'protected' => [DOKU_INC . 'lib/plugins/farmer/includes/config.php'] 4751da41c8bSAndreas Gohr ]; 476a646d519SAndreas Gohr } elseif ($key == 'license') { 4771da41c8bSAndreas Gohr $append = [ 4781da41c8bSAndreas Gohr 'default' => [DOKU_INC . 'conf/' . $key . '.local.php'] 4791da41c8bSAndreas Gohr ]; 480a646d519SAndreas Gohr } elseif ($key == 'userscript') { 4811da41c8bSAndreas Gohr $prepend = [ 4821da41c8bSAndreas Gohr 'default' => [DOKU_INC . 'conf/userscript.js'] 4831da41c8bSAndreas Gohr ]; 484a646d519SAndreas Gohr } elseif ($key == 'userstyle') { 4851da41c8bSAndreas Gohr $prepend = [ 4861da41c8bSAndreas Gohr 'screen' => [ 4871da41c8bSAndreas Gohr DOKU_INC . 'conf/userstyle.css', 4881da41c8bSAndreas Gohr DOKU_INC . 'conf/userstyle.less' 4891da41c8bSAndreas Gohr ], 4901da41c8bSAndreas Gohr 'print' => [ 4911da41c8bSAndreas Gohr DOKU_INC . 'conf/userprint.css', 4921da41c8bSAndreas Gohr DOKU_INC . 'conf/userprint.less' 4931da41c8bSAndreas Gohr ], 4941da41c8bSAndreas Gohr 'feed' => [ 4951da41c8bSAndreas Gohr DOKU_INC . 'conf/userfeed.css', 4961da41c8bSAndreas Gohr DOKU_INC . 'conf/userfeed.less' 4971da41c8bSAndreas Gohr ], 4981da41c8bSAndreas Gohr 'all' => [ 4991da41c8bSAndreas Gohr DOKU_INC . 'conf/userall.css', 5001da41c8bSAndreas Gohr DOKU_INC . 'conf/userall.less' 5011da41c8bSAndreas Gohr ] 5021da41c8bSAndreas Gohr ]; 50305ea7625SAnna Dabrowska } elseif ($key == 'styleini') { 5041da41c8bSAndreas Gohr $append = [ 5051da41c8bSAndreas Gohr 'local' => [DOKU_INC . 'conf/tpl/%TEMPLATE%/style.ini'] 5061da41c8bSAndreas Gohr ]; 5071272da0cSAndreas Gohr } elseif ($key == 'users') { 5081272da0cSAndreas Gohr $config_cascade['plainauth.users']['protected'] = DOKU_INC . 'conf/users.auth.php'; 509af1c6dd8SAndreas Gohr } elseif ($key == 'plugins') { 5104b1aad07Satisne $prepend = [ 5114b1aad07Satisne 'protected' => [DOKU_INC . 'conf/local.protected.php'] 5124b1aad07Satisne ]; 5131da41c8bSAndreas Gohr $append = [ 5141da41c8bSAndreas Gohr 'default' => [DOKU_INC . 'conf/plugins.local.php'] 5151da41c8bSAndreas Gohr ]; 516a646d519SAndreas Gohr } else { 5171da41c8bSAndreas Gohr $append = [ 5181da41c8bSAndreas Gohr 'default' => [DOKU_INC . 'conf/' . $key . '.local.conf'] 5191da41c8bSAndreas Gohr ]; 520a646d519SAndreas Gohr } 521a646d519SAndreas Gohr 522a646d519SAndreas Gohr // add to cascade 523a646d519SAndreas Gohr foreach ($prepend as $section => $data) { 524a646d519SAndreas Gohr $config_cascade[$key][$section] = array_merge($data, $config_cascade[$key][$section]); 525a646d519SAndreas Gohr } 526a646d519SAndreas Gohr foreach ($append as $section => $data) { 527a646d519SAndreas Gohr $config_cascade[$key][$section] = array_merge($config_cascade[$key][$section], $data); 528a646d519SAndreas Gohr } 529a646d519SAndreas Gohr } 530de156015SAndreas Gohr 531de156015SAndreas Gohr // add plugin overrides 532de156015SAndreas Gohr $config_cascade['plugins']['protected'][] = DOKU_INC . 'lib/plugins/farmer/includes/plugins.php'; 533a646d519SAndreas Gohr } 534a646d519SAndreas Gohr 535a646d519SAndreas Gohr /** 536da0ae2c0SAndreas Gohr * Loads the farm config 537da0ae2c0SAndreas Gohr */ 5381da41c8bSAndreas Gohr protected function loadConfig() 5391da41c8bSAndreas Gohr { 540da0ae2c0SAndreas Gohr $ini = DOKU_INC . 'conf/farm.ini'; 541700b5633SAndreas Gohr if (file_exists($ini)) { 542da0ae2c0SAndreas Gohr $config = parse_ini_file($ini, true); 543da0ae2c0SAndreas Gohr foreach (array_keys($this->config) as $section) { 544da0ae2c0SAndreas Gohr if (isset($config[$section])) { 545da0ae2c0SAndreas Gohr $this->config[$section] = array_merge( 546da0ae2c0SAndreas Gohr $this->config[$section], 547da0ae2c0SAndreas Gohr $config[$section] 548da0ae2c0SAndreas Gohr ); 549da0ae2c0SAndreas Gohr } 550da0ae2c0SAndreas Gohr } 551700b5633SAndreas Gohr } 552700b5633SAndreas Gohr 553700b5633SAndreas Gohr // farmdir setup can be done via environment 554700b5633SAndreas Gohr if ($this->config['base']['farmdir'] === '' && isset($_ENV['DOKU_FARMDIR'])) { 555700b5633SAndreas Gohr $this->config['base']['farmdir'] = $_ENV['DOKU_FARMDIR']; 556700b5633SAndreas Gohr } 557da0ae2c0SAndreas Gohr 558a646d519SAndreas Gohr $this->config['base']['farmdir'] = trim($this->config['base']['farmdir']); 559a646d519SAndreas Gohr $this->config['base']['farmhost'] = strtolower(trim($this->config['base']['farmhost'])); 560a646d519SAndreas Gohr } 561da0ae2c0SAndreas Gohr} 562da0ae2c0SAndreas Gohr 563da0ae2c0SAndreas Gohr// initialize it globally 56485becf1bSAndreas Gohrif (!defined('DOKU_UNITTEST')) { 565da0ae2c0SAndreas Gohr global $FARMCORE; 566da0ae2c0SAndreas Gohr $FARMCORE = new DokuWikiFarmCore(); 56785becf1bSAndreas Gohr} 568