mirror of
https://github.com/e107inc/e107.git
synced 2025-08-01 20:30:39 +02:00
#3867: Accurate relative path calculations in e107::set_paths()
e107 historically conflated e_BASE with a URI path and a local file system path. e_BASE seems to have been redefined later to mean a relative path to the e107 root from the calling script, and e_HTTP was introduced to resolve URIs from the web browser. e_ROOT is the absolute path represented by e_BASE. Because of legacy usage of e_BASE depending on it being a relative path, e_BASE must remain as a relative path, but how the path was determined was incorrectly implemented. This commit fixes multiple issues with e107::set_paths(): * e_BASE is now a relative path calculated reliably by a helper function * If ./e107_handlers/e107_class.php is in a sensible place and ./class2.php can be found one directory up, this path will be used as the traversal target. * If ./e107_handlers/e107_class.php is at an exotic path, debug_backtrace() will be inspected to find "class2.php", and a relative path will be made to the dirname() of that class2.php * In CLI mode, chdir() is now called to set the working directory to the e107 root. This is to maintain relative path consistency. Previously, the absolute path would be stored in e_BASE, which may lead to inconsistent behavior. * e_HTTP is now resolved from $_SERVER['SCRIPT_NAME'] instead of $_SERVER['PHP_SELF'] because arbitrary strings and slashes can be added to the end of $_SERVER['PHP_SELF'] and could lead to e_HTTP storing URIs that descended too far. Fixes: #3867
This commit is contained in:
@@ -4512,35 +4512,33 @@ class e107
|
|||||||
$this->HTTP_SCHEME = 'https';
|
$this->HTTP_SCHEME = 'https';
|
||||||
}
|
}
|
||||||
|
|
||||||
$path = ""; $i = 0;
|
$path = "";
|
||||||
|
|
||||||
// FIXME - Again, what if someone moves handlers under the webroot?
|
$needle = "/class2.php";
|
||||||
if(!self::isCli())
|
if (file_exists(__DIR__."/..".$needle))
|
||||||
{
|
{
|
||||||
while (!file_exists("{$path}class2.php"))
|
$target_path = realpath(__DIR__."/..".$needle);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$debug_backtrace = array_reverse(debug_backtrace());
|
||||||
|
foreach ($debug_backtrace as $stack_item)
|
||||||
{
|
{
|
||||||
$path .= "../";
|
$target_path = isset($stack_item["file"]) ? $stack_item["file"] : "";
|
||||||
$i++;
|
if (substr_compare($target_path, $needle, -strlen($needle)) === 0) break;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (empty($_SERVER['PHP_SELF']) && !empty($_SERVER['SCRIPT_NAME']))
|
if (e107::isCli()) chdir(e_ROOT); // Maintain relative path consistency in CLI mode
|
||||||
{
|
$path = dirname(self::getRelativePath(getcwd(), $target_path))."/";
|
||||||
$_SERVER['PHP_SELF'] = $_SERVER['SCRIPT_NAME'];
|
|
||||||
}
|
|
||||||
|
|
||||||
$http_path = dirname($_SERVER['PHP_SELF']);
|
$http_path = dirname($_SERVER['SCRIPT_NAME']);
|
||||||
$http_path = explode("/", $http_path);
|
$http_path = explode("/", $http_path);
|
||||||
$http_path = array_reverse($http_path);
|
for ($i = 0; $i < substr_count($path, "../"); $i ++)
|
||||||
$j = 0;
|
|
||||||
while ($j < $i)
|
|
||||||
{
|
{
|
||||||
unset($http_path[$j]);
|
array_pop($http_path);
|
||||||
$j++;
|
|
||||||
}
|
}
|
||||||
$http_path = array_reverse((array) $http_path);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
$this->server_path = implode("/", $http_path)."/";
|
$this->server_path = implode("/", $http_path)."/";
|
||||||
$this->server_path = $this->fix_windows_paths($this->server_path);
|
$this->server_path = $this->fix_windows_paths($this->server_path);
|
||||||
@@ -4556,10 +4554,7 @@ class e107
|
|||||||
// Absolute file-path of directory containing class2.php
|
// Absolute file-path of directory containing class2.php
|
||||||
// define("e_ROOT", realpath(dirname(__FILE__)."/../")."/");
|
// define("e_ROOT", realpath(dirname(__FILE__)."/../")."/");
|
||||||
|
|
||||||
|
$this->relative_base_path = $path;
|
||||||
|
|
||||||
|
|
||||||
$this->relative_base_path = (!self::isCli()) ? $path : e_ROOT;
|
|
||||||
$_SERVER['HTTP_HOST'] = isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : 'localhost';
|
$_SERVER['HTTP_HOST'] = isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : 'localhost';
|
||||||
$this->http_path = filter_var("http://{$_SERVER['HTTP_HOST']}{$this->server_path}", FILTER_SANITIZE_URL);
|
$this->http_path = filter_var("http://{$_SERVER['HTTP_HOST']}{$this->server_path}", FILTER_SANITIZE_URL);
|
||||||
$this->https_path = filter_var("https://{$_SERVER['HTTP_HOST']}{$this->server_path}", FILTER_SANITIZE_URL);
|
$this->https_path = filter_var("https://{$_SERVER['HTTP_HOST']}{$this->server_path}", FILTER_SANITIZE_URL);
|
||||||
@@ -4713,6 +4708,50 @@ class e107
|
|||||||
return $fixed_path;
|
return $fixed_path;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert two absolute paths to a relative path between them
|
||||||
|
* @license https://creativecommons.org/licenses/by-sa/3.0/ CC BY-SA 3.0
|
||||||
|
* @see https://stackoverflow.com/a/2638272
|
||||||
|
* @param $from string Absolute path of traversal source
|
||||||
|
* @param $to string Absolute path of traversal destination
|
||||||
|
* @return string Relative path from the source to the destination
|
||||||
|
*/
|
||||||
|
private static function getRelativePath($from, $to)
|
||||||
|
{
|
||||||
|
$from = is_dir($from) ? rtrim($from, '\/') . '/' : $from;
|
||||||
|
$to = is_dir($to) ? rtrim($to, '\/') . '/' : $to;
|
||||||
|
$from = str_replace('\\', '/', $from);
|
||||||
|
$to = str_replace('\\', '/', $to);
|
||||||
|
|
||||||
|
$from = explode('/', $from);
|
||||||
|
$to = explode('/', $to);
|
||||||
|
$relPath = $to;
|
||||||
|
|
||||||
|
foreach ($from as $depth => $dir)
|
||||||
|
{
|
||||||
|
if ($dir === $to[$depth])
|
||||||
|
{
|
||||||
|
array_shift($relPath);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$remaining = count($from) - $depth;
|
||||||
|
if ($remaining > 1)
|
||||||
|
{
|
||||||
|
$padLength = (count($relPath) + $remaining - 1) * -1;
|
||||||
|
$relPath = array_pad($relPath, $padLength, '..');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$relPath[0] = './' . $relPath[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return implode('/', $relPath);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Define e_PAGE, e_SELF, e_ADMIN_AREA and USER_AREA;
|
* Define e_PAGE, e_SELF, e_ADMIN_AREA and USER_AREA;
|
||||||
* The following files are assumed to use admin theme:
|
* The following files are assumed to use admin theme:
|
||||||
|
Reference in New Issue
Block a user