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