Replace Pico::discoverRequestFile() with public Pico::resolveFilePath()

This allows plugins (e.g. PicoAdmin) to safely resolve file paths without the need of re-implementing the method.
This commit is contained in:
Daniel Rudolf 2016-07-20 19:23:19 +02:00
parent e27be7a80f
commit 21bd18bcf0
No known key found for this signature in database
GPG Key ID: A061F02CD8DE4538

View File

@ -308,7 +308,7 @@ class Pico
$this->triggerEvent('onRequestUrl', array(&$this->requestUrl)); $this->triggerEvent('onRequestUrl', array(&$this->requestUrl));
// discover requested file // discover requested file
$this->discoverRequestFile(); $this->requestFile = $this->resolveFilePath($this->requestUrl);
$this->triggerEvent('onRequestFile', array(&$this->requestFile)); $this->triggerEvent('onRequestFile', array(&$this->requestFile));
// load raw file content // load raw file content
@ -735,24 +735,29 @@ class Pico
} }
/** /**
* Uses the request URL to discover the content file to serve * Resolves a given file path to its corresponding content file
*
* This method also prevents `content_dir` breakouts using malicious
* request URLs. We don't use `realpath()`, because we neither want to
* check for file existance, nor prohibit symlinks which intentionally
* point to somewhere outside the `content_dir` folder. It is STRONGLY
* RECOMMENDED to use PHP's `open_basedir` feature - always, not just
* with Pico!
* *
* @see Pico::getRequestFile() * @see Pico::getRequestFile()
* @return void * @param string $requestUrl path name (likely from a URL) to resolve
* @return string path to the resolved content file
*/ */
protected function discoverRequestFile() public function resolveFilePath($requestUrl)
{ {
$contentDir = $this->getConfig('content_dir'); $contentDir = $this->getConfig('content_dir');
$contentExt = $this->getConfig('content_ext'); $contentExt = $this->getConfig('content_ext');
if (empty($this->requestUrl)) { if (empty($requestUrl)) {
$this->requestFile = $contentDir . 'index' . $contentExt; return $contentDir . 'index' . $contentExt;
} else { } else {
// prevent content_dir breakouts using malicious request URLs // prevent content_dir breakouts
// we don't use realpath() here because we neither want to check for file existance $requestUrl = str_replace('\\', '/', $requestUrl);
// nor prohibit symlinks which intentionally point to somewhere outside the content_dir
// it is STRONGLY RECOMMENDED to use open_basedir - always, not just with Pico!
$requestUrl = str_replace('\\', '/', $this->requestUrl);
$requestUrlParts = explode('/', $requestUrl); $requestUrlParts = explode('/', $requestUrl);
$requestFileParts = array(); $requestFileParts = array();
@ -768,31 +773,29 @@ class Pico
} }
if (empty($requestFileParts)) { if (empty($requestFileParts)) {
$this->requestFile = $contentDir . 'index' . $contentExt; return $contentDir . 'index' . $contentExt;
return;
} }
// discover the content file to serve // discover the content file to serve
// Note: $requestFileParts neither contains a trailing nor a leading slash // Note: $requestFileParts neither contains a trailing nor a leading slash
$this->requestFile = $contentDir . implode('/', $requestFileParts); $requestFile = $contentDir . implode('/', $requestFileParts);
if (is_dir($this->requestFile)) { if (is_dir($requestFile)) {
// if no index file is found, try a accordingly named file in the previous dir // 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 // 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) // file as being requested (maintains backward compatibility to Pico < 1.0)
$indexFile = $this->requestFile . '/index' . $contentExt; $indexFile = $requestFile . '/index' . $contentExt;
if (file_exists($indexFile) || !file_exists($this->requestFile . $contentExt)) { if (file_exists($indexFile) || !file_exists($requestFile . $contentExt)) {
$this->requestFile = $indexFile; return $indexFile;
return;
} }
} }
$this->requestFile .= $contentExt; return $requestFile . $contentExt;
} }
} }
/** /**
* Returns the absolute path to the content file to serve * Returns the absolute path to the content file to serve
* *
* @see Pico::discoverRequestFile() * @see Pico::resolveFilePath()
* @return string|null file path * @return string|null file path
*/ */
public function getRequestFile() public function getRequestFile()