Completed
Push — old-stable ( 1e6113...045573 )
by
unknown
04:31
created

init.php ➔ init_session()   A

Complexity

Conditions 4
Paths 2

Size

Total Lines 12
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 7
nc 2
nop 0
dl 0
loc 12
rs 9.2
c 0
b 0
f 0
1
<?php
2
/**
3
 * Initialize some defaults needed for DokuWiki
4
 */
5
6
/**
7
 * timing Dokuwiki execution
8
 */
9
function delta_time($start=0) {
10
    return microtime(true)-((float)$start);
11
}
12
define('DOKU_START_TIME', delta_time());
13
14
global $config_cascade;
15
$config_cascade = array();
16
17
// if available load a preload config file
18
$preload = fullpath(dirname(__FILE__)).'/preload.php';
19
if (file_exists($preload)) include($preload);
20
21
// define the include path
22
if(!defined('DOKU_INC')) define('DOKU_INC',fullpath(dirname(__FILE__).'/../').'/');
23
24
// define Plugin dir
25
if(!defined('DOKU_PLUGIN'))  define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/');
26
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
30
// check for error reporting override or set error reporting to sane values
31
if (!defined('DOKU_E_LEVEL') && file_exists(DOKU_CONF.'report_e_all')) {
32
    define('DOKU_E_LEVEL', E_ALL);
33
}
34
if (!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
45
global $cache_revinfo;
46
       $cache_revinfo = array();
47
global $cache_wikifn;
48
       $cache_wikifn = array();
49
global $cache_cleanid;
50
       $cache_cleanid = array();
51
global $cache_authname;
52
       $cache_authname = array();
53
global $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
58
include(DOKU_INC.'inc/config_cascade.php');
59
60
//prepare config array()
61
global $conf;
62
$conf = array();
63
64
// load the global config file(s)
65
foreach (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()
75
global $license;
76
$license = array();
77
78
// load the license file(s)
79
foreach (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)
89
date_default_timezone_set(@date_default_timezone_get());
90
91
// define baseURL
92
if(!defined('DOKU_REL')) define('DOKU_REL',getBaseURL(false));
93
if(!defined('DOKU_URL')) define('DOKU_URL',getBaseURL(true));
94
if(!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
103
if(!defined('DOKU_LF')) define ('DOKU_LF',"\n");
104
if(!defined('DOKU_TAB')) define ('DOKU_TAB',"\t");
105
106
// define cookie and session id, append server port when securecookie is configured FS#1664
107
if (!defined('DOKU_COOKIE')) define('DOKU_COOKIE', 'DW'.md5(DOKU_REL.(($conf['securecookie'])?$_SERVER['SERVER_PORT']:'')));
108
109
110
// define main script
111
if(!defined('DOKU_SCRIPT')) define('DOKU_SCRIPT','doku.php');
112
113
// DEPRECATED, use tpl_basedir() instead
114
if(!defined('DOKU_TPL')) define('DOKU_TPL',
115
        DOKU_BASE.'lib/tpl/'.$conf['template'].'/');
116
117
// DEPRECATED, use tpl_incdir() instead
118
if(!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;');
1 ignored issue
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
123
124
// make sure global zlib does not interfere FS#1132
125
@ini_set('zlib.output_compression', 'off');
1 ignored issue
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
126
127
// increase PCRE backtrack limit
128
@ini_set('pcre.backtrack_limit', '20971520');
1 ignored issue
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
129
130
// enable gzip compression if supported
131
$conf['gzip_output'] &= (strpos($_SERVER['HTTP_ACCEPT_ENCODING'],'gzip') !== false);
132
global $ACT;
133
if ($conf['gzip_output'] &&
134
        !defined('DOKU_DISABLE_GZIP_OUTPUT') &&
135
        function_exists('ob_gzhandler') &&
136
        // Disable compression when a (compressed) sitemap might be delivered
137
        // See https://bugs.dokuwiki.org/index.php?do=details&task_id=2576
138
        $ACT != 'sitemap') {
139
    ob_start('ob_gzhandler');
140
}
141
142
// init session
143
if(!headers_sent() && !defined('NOSESSION')) {
144
    if(!defined('DOKU_SESSION_NAME'))     define ('DOKU_SESSION_NAME', "DokuWiki");
145
    if(!defined('DOKU_SESSION_LIFETIME')) define ('DOKU_SESSION_LIFETIME', 0);
146
    if(!defined('DOKU_SESSION_PATH')) {
147
        $cookieDir = empty($conf['cookiedir']) ? DOKU_REL : $conf['cookiedir'];
148
        define ('DOKU_SESSION_PATH', $cookieDir);
149
    }
150
    if(!defined('DOKU_SESSION_DOMAIN'))   define ('DOKU_SESSION_DOMAIN', '');
151
152
    // start the session
153
    init_session();
154
155
    // load left over messages
156
    if(isset($_SESSION[DOKU_COOKIE]['msg'])) {
157
        $MSG = $_SESSION[DOKU_COOKIE]['msg'];
158
        unset($_SESSION[DOKU_COOKIE]['msg']);
159
    }
160
}
161
162
// kill magic quotes
163
if (get_magic_quotes_gpc() && !defined('MAGIC_QUOTES_STRIPPED')) {
164
    if (!empty($_GET))    remove_magic_quotes($_GET);
165
    if (!empty($_POST))   remove_magic_quotes($_POST);
166
    if (!empty($_COOKIE)) remove_magic_quotes($_COOKIE);
167
    if (!empty($_REQUEST)) remove_magic_quotes($_REQUEST);
168
    @ini_set('magic_quotes_gpc', 0);
1 ignored issue
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
169
    define('MAGIC_QUOTES_STRIPPED',1);
170
}
171
if(function_exists('set_magic_quotes_runtime')) @set_magic_quotes_runtime(0);
1 ignored issue
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
172
@ini_set('magic_quotes_sybase',0);
1 ignored issue
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
173
174
// don't let cookies ever interfere with request vars
175
$_REQUEST = array_merge($_GET,$_POST);
176
177
// we don't want a purge URL to be digged
178
if(isset($_REQUEST['purge']) && !empty($_SERVER['HTTP_REFERER'])) unset($_REQUEST['purge']);
179
180
// precalculate file creation modes
181
init_creationmodes();
182
183
// make real paths and check them
184
init_paths();
185
init_files();
186
187
// setup plugin controller class (can be overwritten in preload.php)
188
$plugin_types = array('auth', 'admin','syntax','action','renderer', 'helper','remote');
189
global $plugin_controller_class, $plugin_controller;
190
if (empty($plugin_controller_class)) $plugin_controller_class = 'Doku_Plugin_Controller';
191
192
// load libraries
193
require_once(DOKU_INC.'vendor/autoload.php');
194
require_once(DOKU_INC.'inc/load.php');
195
196
// disable gzip if not available
197
define('DOKU_HAS_BZIP', function_exists('bzopen'));
198
define('DOKU_HAS_GZIP', function_exists('gzopen'));
199
if($conf['compression'] == 'bz2' && !DOKU_HAS_BZIP) {
200
    $conf['compression'] = 'gz';
201
}
202
if($conf['compression'] == 'gz' && !DOKU_HAS_GZIP) {
203
    $conf['compression'] = 0;
204
}
205
206
// input handle class
207
global $INPUT;
208
$INPUT = new Input();
209
210
// initialize plugin controller
211
$plugin_controller = new $plugin_controller_class();
212
213
// initialize the event handler
214
global $EVENT_HANDLER;
215
$EVENT_HANDLER = new Doku_Event_Handler();
216
217
$local = $conf['lang'];
218
trigger_event('INIT_LANG_LOAD', $local, 'init_lang', true);
219
220
221
// setup authentication system
222
if (!defined('NOSESSION')) {
223
    auth_setup();
224
}
225
226
// setup mail system
227
mail_setup();
228
229
/**
230
 * Initializes the session
231
 *
232
 * Makes sure the passed session cookie is valid, invalid ones are ignored an a new session ID is issued
233
 *
234
 * @link http://stackoverflow.com/a/33024310/172068
235
 * @link http://php.net/manual/en/session.configuration.php#ini.session.sid-length
236
 */
237
function init_session() {
238
    global $conf;
239
    session_name(DOKU_SESSION_NAME);
240
    session_set_cookie_params(DOKU_SESSION_LIFETIME, DOKU_SESSION_PATH, DOKU_SESSION_DOMAIN, ($conf['securecookie'] && is_ssl()), true);
241
242
    // make sure the session cookie contains a valid session ID
243
    if(isset($_COOKIE[DOKU_SESSION_NAME]) && !preg_match('/^[-,a-zA-Z0-9]{22,256}$/', $_COOKIE[DOKU_SESSION_NAME])) {
244
        unset($_COOKIE[DOKU_SESSION_NAME]);
245
    }
246
247
    session_start();
248
}
249
250
251
/**
252
 * Checks paths from config file
253
 */
254
function init_paths(){
255
    global $conf;
256
257
    $paths = array('datadir'   => 'pages',
258
            'olddir'    => 'attic',
259
            'mediadir'  => 'media',
260
            'mediaolddir' => 'media_attic',
261
            'metadir'   => 'meta',
262
            'mediametadir' => 'media_meta',
263
            'cachedir'  => 'cache',
264
            'indexdir'  => 'index',
265
            'lockdir'   => 'locks',
266
            'tmpdir'    => 'tmp');
267
268
    foreach($paths as $c => $p) {
269
        $path = empty($conf[$c]) ? $conf['savedir'].'/'.$p : $conf[$c];
270
        $conf[$c] = init_path($path);
271
        if(empty($conf[$c]))
272
            nice_die("The $c ('$p') at $path is not found, isn't accessible or writable.
273
                You should check your config and permission settings.
274
                Or maybe you want to <a href=\"install.php\">run the
275
                installer</a>?");
276
    }
277
278
    // path to old changelog only needed for upgrading
279
    $conf['changelog_old'] = init_path((isset($conf['changelog']))?($conf['changelog']):($conf['savedir'].'/changes.log'));
280
    if ($conf['changelog_old']=='') { unset($conf['changelog_old']); }
281
    // hardcoded changelog because it is now a cache that lives in meta
282
    $conf['changelog'] = $conf['metadir'].'/_dokuwiki.changes';
283
    $conf['media_changelog'] = $conf['metadir'].'/_media.changes';
284
}
285
286
/**
287
 * Load the language strings
288
 *
289
 * @param string $langCode language code, as passed by event handler
290
 */
291
function init_lang($langCode) {
292
    //prepare language array
293
    global $lang, $config_cascade;
294
    $lang = array();
295
296
    //load the language files
297
    require(DOKU_INC.'inc/lang/en/lang.php');
298
    foreach ($config_cascade['lang']['core'] as $config_file) {
299
        if (file_exists($config_file . 'en/lang.php')) {
300
            include($config_file . 'en/lang.php');
301
        }
302
    }
303
304
    if ($langCode && $langCode != 'en') {
305
        if (file_exists(DOKU_INC."inc/lang/$langCode/lang.php")) {
306
            require(DOKU_INC."inc/lang/$langCode/lang.php");
307
        }
308
        foreach ($config_cascade['lang']['core'] as $config_file) {
309
            if (file_exists($config_file . "$langCode/lang.php")) {
310
                include($config_file . "$langCode/lang.php");
311
            }
312
        }
313
    }
314
}
315
316
/**
317
 * Checks the existence of certain files and creates them if missing.
318
 */
319
function init_files(){
320
    global $conf;
321
322
    $files = array($conf['indexdir'].'/page.idx');
323
324
    foreach($files as $file){
325
        if(!file_exists($file)){
326
            $fh = @fopen($file,'a');
327
            if($fh){
328
                fclose($fh);
329
                if(!empty($conf['fperm'])) chmod($file, $conf['fperm']);
330
            }else{
331
                nice_die("$file is not writable. Check your permissions settings!");
332
            }
333
        }
334
    }
335
336
    # create title index (needs to have same length as page.idx)
337
    /*
338
    $file = $conf['indexdir'].'/title.idx';
339
    if(!file_exists($file)){
340
        $pages = file($conf['indexdir'].'/page.idx');
341
        $pages = count($pages);
342
        $fh = @fopen($file,'a');
343
        if($fh){
344
            for($i=0; $i<$pages; $i++){
345
                fwrite($fh,"\n");
346
            }
347
            fclose($fh);
348
        }else{
349
            nice_die("$file is not writable. Check your permissions settings!");
350
        }
351
    }
352
    */
353
}
354
355
/**
356
 * Returns absolute path
357
 *
358
 * This tries the given path first, then checks in DOKU_INC.
359
 * Check for accessibility on directories as well.
360
 *
361
 * @author Andreas Gohr <[email protected]>
362
 */
363
function init_path($path){
364
    // check existence
365
    $p = fullpath($path);
366
    if(!file_exists($p)){
367
        $p = fullpath(DOKU_INC.$path);
368
        if(!file_exists($p)){
369
            return '';
370
        }
371
    }
372
373
    // check writability
374
    if(!@is_writable($p)){
375
        return '';
376
    }
377
378
    // check accessability (execute bit) for directories
379
    if(@is_dir($p) && !file_exists("$p/.")){
380
        return '';
381
    }
382
383
    return $p;
384
}
385
386
/**
387
 * Sets the internal config values fperm and dperm which, when set,
388
 * will be used to change the permission of a newly created dir or
389
 * file with chmod. Considers the influence of the system's umask
390
 * setting the values only if needed.
391
 */
392
function init_creationmodes(){
393
    global $conf;
394
395
    // Legacy support for old umask/dmask scheme
396
    unset($conf['dmask']);
397
    unset($conf['fmask']);
398
    unset($conf['umask']);
399
    unset($conf['fperm']);
400
    unset($conf['dperm']);
401
402
    // get system umask, fallback to 0 if none available
403
    $umask = @umask();
404
    if(!$umask) $umask = 0000;
405
406
    // check what is set automatically by the system on file creation
407
    // and set the fperm param if it's not what we want
408
    $auto_fmode = 0666 & ~$umask;
409
    if($auto_fmode != $conf['fmode']) $conf['fperm'] = $conf['fmode'];
410
411
    // check what is set automatically by the system on file creation
412
    // and set the dperm param if it's not what we want
413
    $auto_dmode = $conf['dmode'] & ~$umask;
414
    if($auto_dmode != $conf['dmode']) $conf['dperm'] = $conf['dmode'];
415
}
416
417
/**
418
 * remove magic quotes recursivly
419
 *
420
 * @author Andreas Gohr <[email protected]>
421
 */
422
function remove_magic_quotes(&$array) {
423
    foreach (array_keys($array) as $key) {
424
        // handle magic quotes in keynames (breaks order)
425
        $sk = stripslashes($key);
426
        if($sk != $key){
427
            $array[$sk] = $array[$key];
428
            unset($array[$key]);
429
            $key = $sk;
430
        }
431
432
        // do recursion if needed
433
        if (is_array($array[$key])) {
434
            remove_magic_quotes($array[$key]);
435
        }else {
436
            $array[$key] = stripslashes($array[$key]);
437
        }
438
    }
439
}
440
441
/**
442
 * Returns the full absolute URL to the directory where
443
 * DokuWiki is installed in (includes a trailing slash)
444
 *
445
 * !! Can not access $_SERVER values through $INPUT
446
 * !! here as this function is called before $INPUT is
447
 * !! initialized.
448
 *
449
 * @author Andreas Gohr <[email protected]>
450
 */
451
function getBaseURL($abs=null){
452
    global $conf;
453
    //if canonical url enabled always return absolute
454
    if(is_null($abs)) $abs = $conf['canonical'];
455
456
    if(!empty($conf['basedir'])){
457
        $dir = $conf['basedir'];
458
    }elseif(substr($_SERVER['SCRIPT_NAME'],-4) == '.php'){
459
        $dir = dirname($_SERVER['SCRIPT_NAME']);
460
    }elseif(substr($_SERVER['PHP_SELF'],-4) == '.php'){
461
        $dir = dirname($_SERVER['PHP_SELF']);
462
    }elseif($_SERVER['DOCUMENT_ROOT'] && $_SERVER['SCRIPT_FILENAME']){
463
        $dir = preg_replace ('/^'.preg_quote($_SERVER['DOCUMENT_ROOT'],'/').'/','',
464
                $_SERVER['SCRIPT_FILENAME']);
465
        $dir = dirname('/'.$dir);
466
    }else{
467
        $dir = '.'; //probably wrong
468
    }
469
470
    $dir = str_replace('\\','/',$dir);             // bugfix for weird WIN behaviour
471
    $dir = preg_replace('#//+#','/',"/$dir/");     // ensure leading and trailing slashes
472
473
    //handle script in lib/exe dir
474
    $dir = preg_replace('!lib/exe/$!','',$dir);
475
476
    //handle script in lib/plugins dir
477
    $dir = preg_replace('!lib/plugins/.*$!','',$dir);
478
479
    //finish here for relative URLs
480
    if(!$abs) return $dir;
481
482
    //use config option if available, trim any slash from end of baseurl to avoid multiple consecutive slashes in the path
483
    if(!empty($conf['baseurl'])) return rtrim($conf['baseurl'],'/').$dir;
484
485
    //split hostheader into host and port
486
    if(isset($_SERVER['HTTP_HOST'])){
487
        $parsed_host = parse_url('http://'.$_SERVER['HTTP_HOST']);
488
        $host = isset($parsed_host['host']) ? $parsed_host['host'] : null;
489
        $port = isset($parsed_host['port']) ? $parsed_host['port'] : null;
490
    }elseif(isset($_SERVER['SERVER_NAME'])){
491
        $parsed_host = parse_url('http://'.$_SERVER['SERVER_NAME']);
492
        $host = isset($parsed_host['host']) ? $parsed_host['host'] : null;
493
        $port = isset($parsed_host['port']) ? $parsed_host['port'] : null;
494
    }else{
495
        $host = php_uname('n');
496
        $port = '';
497
    }
498
499
    if(is_null($port)){
500
        $port = '';
501
    }
502
503
    if(!is_ssl()){
504
        $proto = 'http://';
505
        if ($port == '80') {
506
            $port = '';
507
        }
508
    }else{
509
        $proto = 'https://';
510
        if ($port == '443') {
511
            $port = '';
512
        }
513
    }
514
515
    if($port !== '') $port = ':'.$port;
516
517
    return $proto.$host.$port.$dir;
518
}
519
520
/**
521
 * Check if accessed via HTTPS
522
 *
523
 * Apache leaves ,$_SERVER['HTTPS'] empty when not available, IIS sets it to 'off'.
524
 * 'false' and 'disabled' are just guessing
525
 *
526
 * @returns bool true when SSL is active
527
 */
528
function is_ssl(){
529
    // check if we are behind a reverse proxy
530
    if (isset($_SERVER['HTTP_X_FORWARDED_PROTO'])) {
531
        if ($_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https') {
532
	    return true;
533
	} else {
534
	    return false;
535
	}
536
    }
537
    if (!isset($_SERVER['HTTPS']) ||
538
        preg_match('/^(|off|false|disabled)$/i',$_SERVER['HTTPS'])){
539
        return false;
540
    }else{
541
        return true;
542
    }
543
}
544
545
/**
546
 * print a nice message even if no styles are loaded yet.
547
 */
548
function nice_die($msg){
549
    echo<<<EOT
550
<!DOCTYPE html>
551
<html>
552
<head><title>DokuWiki Setup Error</title></head>
553
<body style="font-family: Arial, sans-serif">
554
    <div style="width:60%; margin: auto; background-color: #fcc;
555
                border: 1px solid #faa; padding: 0.5em 1em;">
556
        <h1 style="font-size: 120%">DokuWiki Setup Error</h1>
557
        <p>$msg</p>
558
    </div>
559
</body>
560
</html>
561
EOT;
562
    exit(1);
563
}
564
565
/**
566
 * A realpath() replacement
567
 *
568
 * This function behaves similar to PHP's realpath() but does not resolve
569
 * symlinks or accesses upper directories
570
 *
571
 * @author Andreas Gohr <[email protected]>
572
 * @author <richpageau at yahoo dot co dot uk>
573
 * @link   http://php.net/manual/en/function.realpath.php#75992
574
 */
575
function fullpath($path,$exists=false){
576
    static $run = 0;
577
    $root  = '';
578
    $iswin = (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN' || @$GLOBALS['DOKU_UNITTEST_ASSUME_WINDOWS']);
579
580
    // find the (indestructable) root of the path - keeps windows stuff intact
581
    if($path{0} == '/'){
582
        $root = '/';
583
    }elseif($iswin){
584
        // match drive letter and UNC paths
585
        if(preg_match('!^([a-zA-z]:)(.*)!',$path,$match)){
586
            $root = $match[1].'/';
587
            $path = $match[2];
588
        }else if(preg_match('!^(\\\\\\\\[^\\\\/]+\\\\[^\\\\/]+[\\\\/])(.*)!',$path,$match)){
589
            $root = $match[1];
590
            $path = $match[2];
591
        }
592
    }
593
    $path = str_replace('\\','/',$path);
594
595
    // if the given path wasn't absolute already, prepend the script path and retry
596
    if(!$root){
597
        $base = dirname($_SERVER['SCRIPT_FILENAME']);
598
        $path = $base.'/'.$path;
599
        if($run == 0){ // avoid endless recursion when base isn't absolute for some reason
600
            $run++;
601
            return fullpath($path,$exists);
602
        }
603
    }
604
    $run = 0;
605
606
    // canonicalize
607
    $path=explode('/', $path);
608
    $newpath=array();
609
    foreach($path as $p) {
610
        if ($p === '' || $p === '.') continue;
611
        if ($p==='..') {
612
            array_pop($newpath);
613
            continue;
614
        }
615
        array_push($newpath, $p);
616
    }
617
    $finalpath = $root.implode('/', $newpath);
618
619
    // check for existence when needed (except when unit testing)
620
    if($exists && !defined('DOKU_UNITTEST') && !file_exists($finalpath)) {
621
        return false;
622
    }
623
    return $finalpath;
624
}
625
626