1
0
mirror of https://github.com/processwire/processwire.git synced 2025-08-13 18:24:57 +02:00

Some updates to ProcessPageView and additions for processwire/processwire-issues#366 to better handle URLs with unrecognized characters

This commit is contained in:
Ryan Cramer
2017-09-21 11:37:46 -04:00
parent 8bcb31359f
commit f822292eb3

View File

@@ -115,7 +115,7 @@ class ProcessPageView extends Process {
// check if there is an 'it' GET variable present in the request URL query string, which we don't want here // check if there is an 'it' GET variable present in the request URL query string, which we don't want here
if(isset($_GET['it']) && strpos($this->dirtyURL, '?it=') !== false || strpos($this->dirtyURL, '&it=')) { if(isset($_GET['it']) && strpos($this->dirtyURL, '?it=') !== false || strpos($this->dirtyURL, '&it=')) {
// force to use path in request url rather than contents of 'it' var // force to use path in request url rather than contents of 'it' var
list($it, $x) = explode('?', $this->dirtyURL); list($it,) = explode('?', $this->dirtyURL);
$rootURL = $this->wire('config')->urls->root; $rootURL = $this->wire('config')->urls->root;
if(strlen($rootURL) > 1 && strpos($it, $rootURL) === 0) $it = substr($it, strlen($rootURL)-1); if(strlen($rootURL) > 1 && strpos($it, $rootURL) === 0) $it = substr($it, strlen($rootURL)-1);
$it = str_replace('index.php', '', $it); $it = str_replace('index.php', '', $it);
@@ -214,12 +214,13 @@ class ProcessPageView extends Process {
return $this->pageNotFound(new NullPage(), $this->requestURL, true, 'requested page resolved to NullPage'); return $this->pageNotFound(new NullPage(), $this->requestURL, true, 'requested page resolved to NullPage');
} }
return '';
} }
/** /**
* Method executed when externally bootstrapped * Method executed when externally bootstrapped
* *
* @return blank string * @return string blank string
* *
*/ */
public function ___executeExternal() { public function ___executeExternal() {
@@ -258,8 +259,11 @@ class ProcessPageView extends Process {
* *
* Sends a copy of the exception that occurred. * Sends a copy of the exception that occurred.
* *
* @param \Exception $e
*
*/ */
public function ___failed(\Exception $e) { public function ___failed(\Exception $e) {
if($e) {}
$this->wire()->setStatus(ProcessWire::statusFailed); $this->wire()->setStatus(ProcessWire::statusFailed);
} }
@@ -271,20 +275,69 @@ class ProcessPageView extends Process {
*/ */
protected function getPage() { protected function getPage() {
/** @var Config $config */
$config = $this->wire('config'); $config = $this->wire('config');
$shit = isset($_GET['it']) ? trim($_GET['it']) : "/"; // dirty
$it = preg_replace('{[^-_./a-zA-Z0-9]}', '', $shit); // clean // force redirect to actual page URL? (if different from request URL)
$forceRedirect = false;
// did URL end with index.php|htm|html? If so we might redirect if a page matches without it.
$indexRedirect = false;
/** @var string $shit Dirty URL */
/** @var string $it Clean URL */
if(isset($_GET['it'])) {
// normal request
$shit = trim($_GET['it']);
} else if(isset($_SERVER['REQUEST_URI'])) {
// abnormal request, something about request URL made .htaccess skip it, or index.php called directly
$shit = trim($_SERVER['REQUEST_URI']);
if(strpos($shit, '?') !== false) list($shit,) = explode('?', $shit);
if($config->urls->root != '/') {
if(strpos($shit, $config->urls->root) === 0) {
// remove root URL from request
$shit = substr($shit, strlen($config->urls->root) - 1);
} else {
// request URL outside of our root directory
return null;
}
}
} else {
$shit = '/';
}
if($shit === '/') {
$it = '/';
} else {
$it = preg_replace('{[^-_./a-zA-Z0-9]}', '', $shit); // clean
}
unset($_GET['it']); unset($_GET['it']);
if($shit !== $it && $config->pageNameCharset == 'UTF8') { if($shit !== $it) {
$it = $this->wire('sanitizer')->pagePathNameUTF8($shit); // sanitized URL does not match requested URL
if($config->pageNameCharset == 'UTF8') {
// test for extended page name URL
$it = $this->wire('sanitizer')->pagePathNameUTF8($shit);
}
if($shit !== $it) {
// if still does not match then fail
return null;
}
} }
if(!isset($it[0]) || $it[0] != '/') $it = "/$it"; if(!isset($it[0]) || $it[0] != '/') $it = "/$it";
if(strpos($it, '//') !== false) return null; if(strpos($it, '//') !== false) return null;
// if request contains index.php and the $it string does not, make it redirect to correct version if(strpos($it, '/index.') !== false && preg_match('{/index\.(php|html?)$}', $it, $matches)) {
$forceRedirect = strpos($this->dirtyURL, 'index.php') !== false && strpos($it, 'index.php') === false; // if request is to index.php|htm|html, make note of it to determine if we can redirect later
$indexRedirect = true;
} else if(strpos($this->dirtyURL, 'index.php') !== false && strpos($it, 'index.php') === false) {
// if request contains index.php and the $it string does not, make it redirect to correct version
$forceRedirect = true;
}
$numParts = substr_count($it, '/'); $numParts = substr_count($it, '/');
if($numParts > $config->maxUrlDepth) return null; if($numParts > $config->maxUrlDepth) return null;
@@ -351,7 +404,14 @@ class ProcessPageView extends Process {
if(!$page || !$page->id) return null; if(!$page || !$page->id) return null;
// if URL segments and/or page numbers are present and not allowed then abort // if URL segments and/or page numbers are present and not allowed then abort
if(!$this->checkUrlSegments($urlSegments, $page)) return null; if(!$this->checkUrlSegments($urlSegments, $page)) {
if($indexRedirect && $cnt === 1) {
// index.php|htm|html segments if not used by page can redirect to URL without it
$forceRedirect = true;
} else {
return null;
}
}
if($forceRedirect && !$this->redirectURL) $this->redirectURL = $page->url; if($forceRedirect && !$this->redirectURL) $this->redirectURL = $page->url;
@@ -429,7 +489,7 @@ class ProcessPageView extends Process {
if(!$maxPageNum) $maxPageNum = 999; if(!$maxPageNum) $maxPageNum = 999;
if($pageNum > $maxPageNum) return false; if($pageNum > $maxPageNum) return false;
} }
$page->pageNum = $pageNum; // backwards compatibility $page->setQuietly('pageNum', $pageNum); // backwards compatibility
$this->input->setPageNum($pageNum); $this->input->setPageNum($pageNum);
array_pop($urlSegments); array_pop($urlSegments);
} }
@@ -536,7 +596,7 @@ class ProcessPageView extends Process {
* *
* If the user doesn't have access, then a login Page or NULL (for 404) is returned instead. * If the user doesn't have access, then a login Page or NULL (for 404) is returned instead.
* *
* @param $page * @param Page $page
* @return Page|null * @return Page|null
* *
*/ */
@@ -589,7 +649,7 @@ class ProcessPageView extends Process {
* if a similar check is needed somewhere else in the core. * if a similar check is needed somewhere else in the core.
* *
* @param Page $page * @param Page $page
* @return Page|null * @return Page|null|bool
* *
*/ */
protected function checkAccessDelegated(Page $page) { protected function checkAccessDelegated(Page $page) {
@@ -686,6 +746,10 @@ class ProcessPageView extends Process {
* *
* If the page is public, then it just does a 301 redirect to the file. * If the page is public, then it just does a 301 redirect to the file.
* *
* @param Page $page
* @param string $basename
* @throws Wire404Exception
*
*/ */
protected function ___sendFile($page, $basename) { protected function ___sendFile($page, $basename) {
@@ -721,6 +785,7 @@ class ProcessPageView extends Process {
* @return string * @return string
*/ */
protected function ___pageNotFound($page, $url, $triggerReady = false, $reason = '') { protected function ___pageNotFound($page, $url, $triggerReady = false, $reason = '') {
if($page || $url || $reason) {} // variables provided for hooks only
$this->responseType = self::responseTypeError; $this->responseType = self::responseTypeError;
$config = $this->config; $config = $this->config;