1<?php 2/** 3 * Initialize some defaults needed for DokuWiki 4 */ 5 6 7/** 8 * timing Dokuwiki execution 9 * 10 * @param integer $start 11 * 12 * @return mixed 13 */ 14function delta_time($start=0) { 15 return microtime(true)-((float)$start); 16} 17define('DOKU_START_TIME', delta_time()); 18 19global $config_cascade; 20$config_cascade = array(); 21 22// if available load a preload config file 23$preload = fullpath(dirname(__FILE__)).'/preload.php'; 24if (file_exists($preload)) include($preload); 25 26// define the include path 27if(!defined('DOKU_INC')) define('DOKU_INC',fullpath(dirname(__FILE__).'/../').'/'); 28 29// define Plugin dir 30if(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/'); 31 32// define config path (packagers may want to change this to /etc/dokuwiki/) 33if(!defined('DOKU_CONF')) define('DOKU_CONF',DOKU_INC.'conf/'); 34 35// check for error reporting override or set error reporting to sane values 36if (!defined('DOKU_E_LEVEL') && file_exists(DOKU_CONF.'report_e_all')) { 37 define('DOKU_E_LEVEL', E_ALL); 38} 39if (!defined('DOKU_E_LEVEL')) { 40 error_reporting(E_ALL & ~E_NOTICE & ~E_DEPRECATED & ~E_STRICT); 41} else { 42 error_reporting(DOKU_E_LEVEL); 43} 44 45// avoid caching issues #1594 46header('Vary: Cookie'); 47 48// init memory caches 49global $cache_revinfo; 50 $cache_revinfo = array(); 51global $cache_wikifn; 52 $cache_wikifn = array(); 53global $cache_cleanid; 54 $cache_cleanid = array(); 55global $cache_authname; 56 $cache_authname = array(); 57global $cache_metadata; 58 $cache_metadata = array(); 59 60// always include 'inc/config_cascade.php' 61// previously in preload.php set fields of $config_cascade will be merged with the defaults 62include(DOKU_INC.'inc/config_cascade.php'); 63 64//prepare config array() 65global $conf; 66$conf = array(); 67 68// load the global config file(s) 69foreach (array('default','local','protected') as $config_group) { 70 if (empty($config_cascade['main'][$config_group])) continue; 71 foreach ($config_cascade['main'][$config_group] as $config_file) { 72 if (file_exists($config_file)) { 73 include($config_file); 74 } 75 } 76} 77 78//prepare license array() 79global $license; 80$license = array(); 81 82// load the license file(s) 83foreach (array('default','local') as $config_group) { 84 if (empty($config_cascade['license'][$config_group])) continue; 85 foreach ($config_cascade['license'][$config_group] as $config_file) { 86 if(file_exists($config_file)){ 87 include($config_file); 88 } 89 } 90} 91 92// set timezone (as in pre 5.3.0 days) 93date_default_timezone_set(@date_default_timezone_get()); 94 95// define baseURL 96if(!defined('DOKU_REL')) define('DOKU_REL',getBaseURL(false)); 97if(!defined('DOKU_URL')) define('DOKU_URL',getBaseURL(true)); 98if(!defined('DOKU_BASE')){ 99 if($conf['canonical']){ 100 define('DOKU_BASE',DOKU_URL); 101 }else{ 102 define('DOKU_BASE',DOKU_REL); 103 } 104} 105 106// define whitespace 107if(!defined('NL')) define ('NL',"\n"); 108if(!defined('DOKU_LF')) define ('DOKU_LF',"\n"); 109if(!defined('DOKU_TAB')) define ('DOKU_TAB',"\t"); 110 111// define cookie and session id, append server port when securecookie is configured FS#1664 112if (!defined('DOKU_COOKIE')) define('DOKU_COOKIE', 'DW'.md5(DOKU_REL.(($conf['securecookie'])?$_SERVER['SERVER_PORT']:''))); 113 114 115// define main script 116if(!defined('DOKU_SCRIPT')) define('DOKU_SCRIPT','doku.php'); 117 118// DEPRECATED, use tpl_basedir() instead 119if(!defined('DOKU_TPL')) define('DOKU_TPL', 120 DOKU_BASE.'lib/tpl/'.$conf['template'].'/'); 121 122// DEPRECATED, use tpl_incdir() instead 123if(!defined('DOKU_TPLINC')) define('DOKU_TPLINC', 124 DOKU_INC.'lib/tpl/'.$conf['template'].'/'); 125 126// make session rewrites XHTML compliant 127@ini_set('arg_separator.output', '&'); 128 129// make sure global zlib does not interfere FS#1132 130@ini_set('zlib.output_compression', 'off'); 131 132// increase PCRE backtrack limit 133@ini_set('pcre.backtrack_limit', '20971520'); 134 135// enable gzip compression if supported 136$conf['gzip_output'] &= (strpos($_SERVER['HTTP_ACCEPT_ENCODING'],'gzip') !== false); 137global $ACT; 138if ($conf['gzip_output'] && 139 !defined('DOKU_DISABLE_GZIP_OUTPUT') && 140 function_exists('ob_gzhandler') && 141 // Disable compression when a (compressed) sitemap might be delivered 142 // See https://bugs.dokuwiki.org/index.php?do=details&task_id=2576 143 $ACT != 'sitemap') { 144 ob_start('ob_gzhandler'); 145} 146 147// init session 148if(!headers_sent() && !defined('NOSESSION')) { 149 if(!defined('DOKU_SESSION_NAME')) define ('DOKU_SESSION_NAME', "DokuWiki"); 150 if(!defined('DOKU_SESSION_LIFETIME')) define ('DOKU_SESSION_LIFETIME', 0); 151 if(!defined('DOKU_SESSION_PATH')) { 152 $cookieDir = empty($conf['cookiedir']) ? DOKU_REL : $conf['cookiedir']; 153 define ('DOKU_SESSION_PATH', $cookieDir); 154 } 155 if(!defined('DOKU_SESSION_DOMAIN')) define ('DOKU_SESSION_DOMAIN', ''); 156 157 // start the session 158 init_session(); 159 160 // load left over messages 161 if(isset($_SESSION[DOKU_COOKIE]['msg'])) { 162 $MSG = $_SESSION[DOKU_COOKIE]['msg']; 163 unset($_SESSION[DOKU_COOKIE]['msg']); 164 } 165} 166 167// don't let cookies ever interfere with request vars 168$_REQUEST = array_merge($_GET,$_POST); 169 170// we don't want a purge URL to be digged 171if(isset($_REQUEST['purge']) && !empty($_SERVER['HTTP_REFERER'])) unset($_REQUEST['purge']); 172 173// precalculate file creation modes 174init_creationmodes(); 175 176// make real paths and check them 177init_paths(); 178init_files(); 179 180// setup plugin controller class (can be overwritten in preload.php) 181$plugin_types = array('auth', 'admin','syntax','action','renderer', 'helper','remote'); 182global $plugin_controller_class, $plugin_controller; 183if (empty($plugin_controller_class)) $plugin_controller_class = 'Doku_Plugin_Controller'; 184 185// load libraries 186require_once(DOKU_INC.'vendor/autoload.php'); 187require_once(DOKU_INC.'inc/load.php'); 188 189// disable gzip if not available 190define('DOKU_HAS_BZIP', function_exists('bzopen')); 191define('DOKU_HAS_GZIP', function_exists('gzopen')); 192if($conf['compression'] == 'bz2' && !DOKU_HAS_BZIP) { 193 $conf['compression'] = 'gz'; 194} 195if($conf['compression'] == 'gz' && !DOKU_HAS_GZIP) { 196 $conf['compression'] = 0; 197} 198 199// input handle class 200global $INPUT; 201$INPUT = new Input(); 202 203// initialize plugin controller 204$plugin_controller = new $plugin_controller_class(); 205 206// initialize the event handler 207global $EVENT_HANDLER; 208$EVENT_HANDLER = new Doku_Event_Handler(); 209 210$local = $conf['lang']; 211trigger_event('INIT_LANG_LOAD', $local, 'init_lang', true); 212 213 214// setup authentication system 215if (!defined('NOSESSION')) { 216 auth_setup(); 217} 218 219// setup mail system 220mail_setup(); 221 222/** 223 * Initializes the session 224 * 225 * Makes sure the passed session cookie is valid, invalid ones are ignored an a new session ID is issued 226 * 227 * @link http://stackoverflow.com/a/33024310/172068 228 * @link http://php.net/manual/en/session.configuration.php#ini.session.sid-length 229 */ 230function init_session() { 231 global $conf; 232 session_name(DOKU_SESSION_NAME); 233 session_set_cookie_params(DOKU_SESSION_LIFETIME, DOKU_SESSION_PATH, DOKU_SESSION_DOMAIN, ($conf['securecookie'] && is_ssl()), true); 234 235 // make sure the session cookie contains a valid session ID 236 if(isset($_COOKIE[DOKU_SESSION_NAME]) && !preg_match('/^[-,a-zA-Z0-9]{22,256}$/', $_COOKIE[DOKU_SESSION_NAME])) { 237 unset($_COOKIE[DOKU_SESSION_NAME]); 238 } 239 240 session_start(); 241} 242 243 244/** 245 * Checks paths from config file 246 */ 247function init_paths(){ 248 global $conf; 249 250 $paths = array('datadir' => 'pages', 251 'olddir' => 'attic', 252 'mediadir' => 'media', 253 'mediaolddir' => 'media_attic', 254 'metadir' => 'meta', 255 'mediametadir' => 'media_meta', 256 'cachedir' => 'cache', 257 'indexdir' => 'index', 258 'lockdir' => 'locks', 259 'tmpdir' => 'tmp'); 260 261 foreach($paths as $c => $p) { 262 $path = empty($conf[$c]) ? $conf['savedir'].'/'.$p : $conf[$c]; 263 $conf[$c] = init_path($path); 264 if(empty($conf[$c])) 265 nice_die("The $c ('$p') at $path is not found, isn't accessible or writable. 266 You should check your config and permission settings. 267 Or maybe you want to <a href=\"install.php\">run the 268 installer</a>?"); 269 } 270 271 // path to old changelog only needed for upgrading 272 $conf['changelog_old'] = init_path((isset($conf['changelog']))?($conf['changelog']):($conf['savedir'].'/changes.log')); 273 if ($conf['changelog_old']=='') { unset($conf['changelog_old']); } 274 // hardcoded changelog because it is now a cache that lives in meta 275 $conf['changelog'] = $conf['metadir'].'/_dokuwiki.changes'; 276 $conf['media_changelog'] = $conf['metadir'].'/_media.changes'; 277} 278 279/** 280 * Load the language strings 281 * 282 * @param string $langCode language code, as passed by event handler 283 */ 284function init_lang($langCode) { 285 //prepare language array 286 global $lang, $config_cascade; 287 $lang = array(); 288 289 //load the language files 290 require(DOKU_INC.'inc/lang/en/lang.php'); 291 foreach ($config_cascade['lang']['core'] as $config_file) { 292 if (file_exists($config_file . 'en/lang.php')) { 293 include($config_file . 'en/lang.php'); 294 } 295 } 296 297 if ($langCode && $langCode != 'en') { 298 if (file_exists(DOKU_INC."inc/lang/$langCode/lang.php")) { 299 require(DOKU_INC."inc/lang/$langCode/lang.php"); 300 } 301 foreach ($config_cascade['lang']['core'] as $config_file) { 302 if (file_exists($config_file . "$langCode/lang.php")) { 303 include($config_file . "$langCode/lang.php"); 304 } 305 } 306 } 307} 308 309/** 310 * Checks the existence of certain files and creates them if missing. 311 */ 312function init_files(){ 313 global $conf; 314 315 $files = array($conf['indexdir'].'/page.idx'); 316 317 foreach($files as $file){ 318 if(!file_exists($file)){ 319 $fh = @fopen($file,'a'); 320 if($fh){ 321 fclose($fh); 322 if(!empty($conf['fperm'])) chmod($file, $conf['fperm']); 323 }else{ 324 nice_die("$file is not writable. Check your permissions settings!"); 325 } 326 } 327 } 328} 329 330/** 331 * Returns absolute path 332 * 333 * This tries the given path first, then checks in DOKU_INC. 334 * Check for accessibility on directories as well. 335 * 336 * @author Andreas Gohr <andi@splitbrain.org> 337 * 338 * @param string $path 339 * 340 * @return bool|string 341 */ 342function init_path($path){ 343 // check existence 344 $p = fullpath($path); 345 if(!file_exists($p)){ 346 $p = fullpath(DOKU_INC.$path); 347 if(!file_exists($p)){ 348 return ''; 349 } 350 } 351 352 // check writability 353 if(!@is_writable($p)){ 354 return ''; 355 } 356 357 // check accessability (execute bit) for directories 358 if(@is_dir($p) && !file_exists("$p/.")){ 359 return ''; 360 } 361 362 return $p; 363} 364 365/** 366 * Sets the internal config values fperm and dperm which, when set, 367 * will be used to change the permission of a newly created dir or 368 * file with chmod. Considers the influence of the system's umask 369 * setting the values only if needed. 370 */ 371function init_creationmodes(){ 372 global $conf; 373 374 // Legacy support for old umask/dmask scheme 375 unset($conf['dmask']); 376 unset($conf['fmask']); 377 unset($conf['umask']); 378 unset($conf['fperm']); 379 unset($conf['dperm']); 380 381 // get system umask, fallback to 0 if none available 382 $umask = @umask(); 383 if(!$umask) $umask = 0000; 384 385 // check what is set automatically by the system on file creation 386 // and set the fperm param if it's not what we want 387 $auto_fmode = 0666 & ~$umask; 388 if($auto_fmode != $conf['fmode']) $conf['fperm'] = $conf['fmode']; 389 390 // check what is set automatically by the system on file creation 391 // and set the dperm param if it's not what we want 392 $auto_dmode = $conf['dmode'] & ~$umask; 393 if($auto_dmode != $conf['dmode']) $conf['dperm'] = $conf['dmode']; 394} 395 396/** 397 * Returns the full absolute URL to the directory where 398 * DokuWiki is installed in (includes a trailing slash) 399 * 400 * !! Can not access $_SERVER values through $INPUT 401 * !! here as this function is called before $INPUT is 402 * !! initialized. 403 * 404 * @author Andreas Gohr <andi@splitbrain.org> 405 * 406 * @param null|string $abs 407 * 408 * @return string 409 */ 410function getBaseURL($abs=null){ 411 global $conf; 412 //if canonical url enabled always return absolute 413 if(is_null($abs)) $abs = $conf['canonical']; 414 415 if(!empty($conf['basedir'])){ 416 $dir = $conf['basedir']; 417 }elseif(substr($_SERVER['SCRIPT_NAME'],-4) == '.php'){ 418 $dir = dirname($_SERVER['SCRIPT_NAME']); 419 }elseif(substr($_SERVER['PHP_SELF'],-4) == '.php'){ 420 $dir = dirname($_SERVER['PHP_SELF']); 421 }elseif($_SERVER['DOCUMENT_ROOT'] && $_SERVER['SCRIPT_FILENAME']){ 422 $dir = preg_replace ('/^'.preg_quote($_SERVER['DOCUMENT_ROOT'],'/').'/','', 423 $_SERVER['SCRIPT_FILENAME']); 424 $dir = dirname('/'.$dir); 425 }else{ 426 $dir = '.'; //probably wrong 427 } 428 429 $dir = str_replace('\\','/',$dir); // bugfix for weird WIN behaviour 430 $dir = preg_replace('#//+#','/',"/$dir/"); // ensure leading and trailing slashes 431 432 //handle script in lib/exe dir 433 $dir = preg_replace('!lib/exe/$!','',$dir); 434 435 //handle script in lib/plugins dir 436 $dir = preg_replace('!lib/plugins/.*$!','',$dir); 437 438 //finish here for relative URLs 439 if(!$abs) return $dir; 440 441 //use config option if available, trim any slash from end of baseurl to avoid multiple consecutive slashes in the path 442 if(!empty($conf['baseurl'])) return rtrim($conf['baseurl'],'/').$dir; 443 444 //split hostheader into host and port 445 if(isset($_SERVER['HTTP_HOST'])){ 446 $parsed_host = parse_url('http://'.$_SERVER['HTTP_HOST']); 447 $host = isset($parsed_host['host']) ? $parsed_host['host'] : null; 448 $port = isset($parsed_host['port']) ? $parsed_host['port'] : null; 449 }elseif(isset($_SERVER['SERVER_NAME'])){ 450 $parsed_host = parse_url('http://'.$_SERVER['SERVER_NAME']); 451 $host = isset($parsed_host['host']) ? $parsed_host['host'] : null; 452 $port = isset($parsed_host['port']) ? $parsed_host['port'] : null; 453 }else{ 454 $host = php_uname('n'); 455 $port = ''; 456 } 457 458 if(is_null($port)){ 459 $port = ''; 460 } 461 462 if(!is_ssl()){ 463 $proto = 'http://'; 464 if ($port == '80') { 465 $port = ''; 466 } 467 }else{ 468 $proto = 'https://'; 469 if ($port == '443') { 470 $port = ''; 471 } 472 } 473 474 if($port !== '') $port = ':'.$port; 475 476 return $proto.$host.$port.$dir; 477} 478 479/** 480 * Check if accessed via HTTPS 481 * 482 * Apache leaves ,$_SERVER['HTTPS'] empty when not available, IIS sets it to 'off'. 483 * 'false' and 'disabled' are just guessing 484 * 485 * @returns bool true when SSL is active 486 */ 487function is_ssl() { 488 // check if we are behind a reverse proxy 489 if(isset($_SERVER['HTTP_X_FORWARDED_PROTO'])) { 490 if($_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https') { 491 return true; 492 } else { 493 return false; 494 } 495 } 496 if(!isset($_SERVER['HTTPS']) || 497 preg_match('/^(|off|false|disabled)$/i', $_SERVER['HTTPS'])) { 498 return false; 499 } else { 500 return true; 501 } 502} 503 504/** 505 * checks it is windows OS 506 * @return bool 507 */ 508function isWindows() { 509 return (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') ? true : false; 510} 511 512/** 513 * print a nice message even if no styles are loaded yet. 514 * 515 * @param integer|string $msg 516 */ 517function nice_die($msg){ 518 echo<<<EOT 519<!DOCTYPE html> 520<html> 521<head><title>DokuWiki Setup Error</title></head> 522<body style="font-family: Arial, sans-serif"> 523 <div style="width:60%; margin: auto; background-color: #fcc; 524 border: 1px solid #faa; padding: 0.5em 1em;"> 525 <h1 style="font-size: 120%">DokuWiki Setup Error</h1> 526 <p>$msg</p> 527 </div> 528</body> 529</html> 530EOT; 531 if(defined('DOKU_UNITTEST')) { 532 throw new RuntimeException('nice_die: '.$msg); 533 } 534 exit(1); 535} 536 537/** 538 * A realpath() replacement 539 * 540 * This function behaves similar to PHP's realpath() but does not resolve 541 * symlinks or accesses upper directories 542 * 543 * @author Andreas Gohr <andi@splitbrain.org> 544 * @author <richpageau at yahoo dot co dot uk> 545 * @link http://php.net/manual/en/function.realpath.php#75992 546 * 547 * @param string $path 548 * @param bool $exists 549 * 550 * @return bool|string 551 */ 552function fullpath($path,$exists=false){ 553 static $run = 0; 554 $root = ''; 555 $iswin = (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN' || @$GLOBALS['DOKU_UNITTEST_ASSUME_WINDOWS']); 556 557 // find the (indestructable) root of the path - keeps windows stuff intact 558 if($path{0} == '/'){ 559 $root = '/'; 560 }elseif($iswin){ 561 // match drive letter and UNC paths 562 if(preg_match('!^([a-zA-z]:)(.*)!',$path,$match)){ 563 $root = $match[1].'/'; 564 $path = $match[2]; 565 }else if(preg_match('!^(\\\\\\\\[^\\\\/]+\\\\[^\\\\/]+[\\\\/])(.*)!',$path,$match)){ 566 $root = $match[1]; 567 $path = $match[2]; 568 } 569 } 570 $path = str_replace('\\','/',$path); 571 572 // if the given path wasn't absolute already, prepend the script path and retry 573 if(!$root){ 574 $base = dirname($_SERVER['SCRIPT_FILENAME']); 575 $path = $base.'/'.$path; 576 if($run == 0){ // avoid endless recursion when base isn't absolute for some reason 577 $run++; 578 return fullpath($path,$exists); 579 } 580 } 581 $run = 0; 582 583 // canonicalize 584 $path=explode('/', $path); 585 $newpath=array(); 586 foreach($path as $p) { 587 if ($p === '' || $p === '.') continue; 588 if ($p==='..') { 589 array_pop($newpath); 590 continue; 591 } 592 array_push($newpath, $p); 593 } 594 $finalpath = $root.implode('/', $newpath); 595 596 // check for existence when needed (except when unit testing) 597 if($exists && !defined('DOKU_UNITTEST') && !file_exists($finalpath)) { 598 return false; 599 } 600 return $finalpath; 601} 602 603