You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

629 lines
18 KiB

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