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