rewrote the fullpath function FS#1462

The fullpath function now correctly handles windows drive letter paths and UNC
paths making sure that those are not destroyed with upper dir .. notation.

Unit tests where added.

darcs-hash:20080914134744-7ad00-9abf5931d910a0b12979b1f69b090e8ecd568c71.gz
This commit is contained in:
Andreas Gohr 2008-09-14 15:47:44 +02:00
parent f5c6743cf7
commit 4761d30ceb
3 changed files with 114 additions and 24 deletions

View File

@ -0,0 +1,75 @@
<?php
require_once DOKU_INC.'inc/init.php';
class init_fullpath_test extends UnitTestCase {
function test_unix_paths(){
$base = $_SERVER['SCRIPT_FILENAME'];
$_SERVER['SCRIPT_FILENAME'] = '/absolute/path/self.php';
$GLOBALS['DOKU_UNITTEST_ASSUME_WINDOWS'] = false;
// paths to check
$tests = array(
'/foo/bar/baz' => '/foo/bar/baz',
'/foo//bar/baz' => '/foo/bar/baz',
'/foo/../bar/baz' => '/bar/baz',
'/foo/./bar/baz' => '/foo/bar/baz',
'/foo/bar/..' => '/foo',
'/foo/bar/../../../baz' => '/baz',
'foo/bar/baz' => '/absolute/path/foo/bar/baz',
'foo//bar/baz' => '/absolute/path/foo/bar/baz',
'foo/../bar/baz' => '/absolute/path/bar/baz',
'foo/./bar/baz' => '/absolute/path/foo/bar/baz',
'foo/bar/..' => '/absolute/path/foo',
'foo/bar/../../../baz' => '/absolute/baz',
);
foreach($tests as $from => $to){
$info = "Testing '$from' resulted in '".fullpath($from)."'";
$this->signal('failinfo',$info);
$this->assertEqual(fullpath($from),$to);
}
$_SERVER['SCRIPT_FILENAME'] = $base;
unset($GLOBALS['DOKU_UNITTEST_ASSUME_WINDOWS']);
}
function test_windows_paths(){
$base = $_SERVER['SCRIPT_FILENAME'];
$_SERVER['SCRIPT_FILENAME'] = '/absolute/path/self.php';
$GLOBALS['DOKU_UNITTEST_ASSUME_WINDOWS'] = true;
// paths to check
$tests = array(
'c:foo/bar/baz' => 'c:foo/bar/baz',
'c:foo//bar/baz' => 'c:foo/bar/baz',
'c:foo/../bar/baz' => 'c:bar/baz',
'c:foo/./bar/baz' => 'c:foo/bar/baz',
'c:foo/bar/..' => 'c:foo',
'c:foo/bar/../../../baz' => 'c:baz',
'\\\\server\\share/foo/bar/baz' => '\\\\server\\share/foo/bar/baz',
'\\\\server\\share/foo//bar/baz' => '\\\\server\\share/foo/bar/baz',
'\\\\server\\share/foo/../bar/baz' => '\\\\server\\share/bar/baz',
'\\\\server\\share/foo/./bar/baz' => '\\\\server\\share/foo/bar/baz',
'\\\\server\\share/foo/bar/..' => '\\\\server\\share/foo',
'\\\\server\\share/foo/bar/../../../baz' => '\\\\server\\share/baz',
);
foreach($tests as $from => $to){
$info = "Testing '$from' resulted in '".fullpath($from)."'";
$this->signal('failinfo',$info);
$this->assertEqual(fullpath($from),$to);
}
$_SERVER['SCRIPT_FILENAME'] = $base;
unset($GLOBALS['DOKU_UNITTEST_ASSUME_WINDOWS']);
}
}
//Setup VIM: ex: et ts=4 enc=utf-8 :

View File

@ -2,6 +2,7 @@
<?php <?php
ini_set('memory_limit','128M'); ini_set('memory_limit','128M');
if(!defined('DOKU_INC')) define('DOKU_INC',realpath(dirname(__FILE__).'/../').'/'); if(!defined('DOKU_INC')) define('DOKU_INC',realpath(dirname(__FILE__).'/../').'/');
define('DOKU_UNITTEST',true);
require_once(DOKU_INC.'inc/init.php'); require_once(DOKU_INC.'inc/init.php');
require_once(DOKU_INC.'inc/events.php'); require_once(DOKU_INC.'inc/events.php');

View File

@ -42,14 +42,12 @@
//prepare config array() //prepare config array()
global $conf; global $conf;
if (!defined('DOKU_UNITTEST')) { $conf = array();
$conf = array();
// load the config file(s) // load the config file(s)
require_once(DOKU_CONF.'dokuwiki.php'); require_once(DOKU_CONF.'dokuwiki.php');
if(@file_exists(DOKU_CONF.'local.php')){ if(@file_exists(DOKU_CONF.'local.php')){
require_once(DOKU_CONF.'local.php'); require_once(DOKU_CONF.'local.php');
}
} }
//prepare language array //prepare language array
@ -443,22 +441,40 @@ EOT;
* This function behaves similar to PHP's realpath() but does not resolve * This function behaves similar to PHP's realpath() but does not resolve
* symlinks or accesses upper directories * symlinks or accesses upper directories
* *
* @author Andreas Gohr <andi@splitbrain.org>
* @author <richpageau at yahoo dot co dot uk> * @author <richpageau at yahoo dot co dot uk>
* @link http://de3.php.net/manual/en/function.realpath.php#75992 * @link http://de3.php.net/manual/en/function.realpath.php#75992
*/ */
function fullpath($path){ function fullpath($path){
$iswin = (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN'); static $run = 0;
$isunc = 0===strpos($path,'\\\\'); $root = '';
if($iswin) $path = str_replace('\\','/',$path); // windows compatibility $iswin = (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN' || $GLOBALS['DOKU_UNITTEST_ASSUME_WINDOWS']);
// check if path begins with "/" or "c:" ie. is absolute // find the (indestructable) root of the path - keeps windows stuff intact
// if it isnt concat with script path if($path{0} == '/'){
if (!$isunc && $root = '/';
((!$iswin && $path{0} !== '/') || }elseif($iswin){
($iswin && $path{1} !== ':'))) { // match drive letter and UNC paths
$base=dirname($_SERVER['SCRIPT_FILENAME']); if(preg_match('!^([a-zA-z]:)(.*)!',$path,$match)){
$path=$base."/".$path; $root = $match[1];
$path = $match[2];
}else if(preg_match('!^(\\\\\\\\[^\\\\/]+\\\\[^\\\\/]+[\\\\/])(.*)!',$path,$match)){
$root = $match[1];
$path = $match[2];
}
} }
$path = str_replace('\\','/',$path);
// if the given path wasn't absolute already, prepend the script path and retry
if(!$root){
$base = dirname($_SERVER['SCRIPT_FILENAME']);
$path = $base.'/'.$path;
if($run == 0){ // avoid endless recursion when base isn't absolute for some reason
$run++;
return fullpath($path,1);
}
}
$run = 0;
// canonicalize // canonicalize
$path=explode('/', $path); $path=explode('/', $path);
@ -471,15 +487,13 @@ function fullpath($path){
} }
array_push($newpath, $p); array_push($newpath, $p);
} }
$finalpath = implode('/', $newpath); $finalpath = $root.implode('/', $newpath);
if($isunc) $finalpath = '//'.$finalpath;
if(!$iswin) $finalpath = '/'.$finalpath;
// check then return valid path or filename // check for existance (except when unit testing)
if (@file_exists($finalpath)) { if(!defined('DOKU_UNITTEST') && !@file_exists($finalpath)) {
return ($finalpath); return false;
} }
else return false; return $finalpath;
} }