Add Pico::getNormalizedPath()

This commit is contained in:
Daniel Rudolf 2019-04-30 15:22:49 +02:00
parent 8ce3b0c224
commit f016c8a937
No known key found for this signature in database
GPG key ID: A061F02CD8DE4538

View file

@ -1155,39 +1155,22 @@ class Pico
if (!$requestUrl) {
return $contentDir . 'index' . $contentExt;
} else {
// prevent content_dir breakouts
$requestUrl = str_replace('\\', '/', $requestUrl);
$requestUrlParts = explode('/', $requestUrl);
$requestFileParts = array();
foreach ($requestUrlParts as $requestUrlPart) {
if (($requestUrlPart === '') || ($requestUrlPart === '.')) {
continue;
} elseif ($requestUrlPart === '..') {
array_pop($requestFileParts);
continue;
}
$requestFileParts[] = $requestUrlPart;
}
if (!$requestFileParts) {
return $contentDir . 'index' . $contentExt;
}
// normalize path and prevent content_dir breakouts
$requestFile = $this->getNormalizedPath($requestUrl, false, false);
// discover the content file to serve
// Note: $requestFileParts neither contains a trailing nor a leading slash
$requestFile = $contentDir . implode('/', $requestFileParts);
if (is_dir($requestFile)) {
if (!$requestFile) {
return $contentDir . 'index' . $contentExt;
} elseif (is_dir($contentDir . $requestFile)) {
// if no index file is found, try a accordingly named file in the previous dir
// if this file doesn't exist either, show the 404 page, but assume the index
// file as being requested (maintains backward compatibility to Pico < 1.0)
$indexFile = $requestFile . '/index' . $contentExt;
if (file_exists($indexFile) || !file_exists($requestFile . $contentExt)) {
$indexFile = $contentDir . $requestFile . '/index' . $contentExt;
if (file_exists($indexFile) || !file_exists($contentDir . $requestFile . $contentExt)) {
return $indexFile;
}
}
return $requestFile . $contentExt;
return $contentDir . $requestFile . $contentExt;
}
}
@ -2506,6 +2489,61 @@ class Pico
return rtrim($path, '/\\') . '/';
}
/**
* Normalizes a path by taking care of '', '.' and '..' parts
*
* @param string $path path to normalize
* @param bool $allowsAbsolutePath whether absolute paths are allowed
* @param bool $endSlash whether to add a trailing slash to the
* normalized path or not (defaults to TRUE)
*
* @return string normalized path
*
* @throws UnexpectedValueException thrown when a absolute path is passed
* although absolute paths aren't allowed
*/
public function getNormalizedPath($path, $allowsAbsolutePath = false, $endSlash = true)
{
$absolutePath = '';
if (DIRECTORY_SEPARATOR === '\\') {
if (preg_match('/^(?>[a-zA-Z]:\\\\|\\\\\\\\)/', $path, $pathMatches) === 1) {
$absolutePath = $pathMatches[0];
$path = substr($path, strlen($absolutePath));
}
} else {
if ($path[0] === '/') {
$absolutePath = '/';
$path = substr($path, 1);
}
}
if ($absolutePath && !$allowsAbsolutePath) {
throw new UnexpectedValueException(
'Argument 1 passed to ' . __METHOD__ . ' must be a relative path, absolute path "' . $path . '" given'
);
}
$path = str_replace('\\', '/', $path);
$pathParts = explode('/', $path);
$resultParts = array();
foreach ($pathParts as $pathPart) {
if (($pathPart === '') || ($pathPart === '.')) {
continue;
} elseif ($pathPart === '..') {
array_pop($resultParts);
continue;
}
$resultParts[] = $pathPart;
}
if (!$resultParts) {
return $absolutePath ?: '/';
}
return $absolutePath . implode('/', $resultParts) . ($endSlash ? '/' : '');
}
/**
* Triggers events on plugins using the current API version
*