1
0
mirror of https://github.com/processwire/processwire.git synced 2025-08-16 03:34:33 +02:00

Update to allow spaces in URL segments when allowed by config.pageNameWhitelist and config.pageNameCharset=UTF8 per processwire/processwire-issues#720

This commit is contained in:
Ryan Cramer
2019-03-21 09:19:01 -04:00
parent 7905fb5180
commit 02f05c6f67
2 changed files with 34 additions and 22 deletions

View File

@@ -652,27 +652,34 @@ class Sanitizer extends Wire {
// word separators that we always allow // word separators that we always allow
$separators = array('.', '-', '_'); $separators = array('.', '-', '_');
// we let regular pageName handle chars like these, if they appear without other UTF-8 // whitelist of allowed characters and blacklist of disallowed characters
$extras = array('.', '-', '_', ' ', ',', ';', ':', '(', ')', '!', '?', '&', '%', '$', '#', '@');
// proceed only if value has some non-ascii characters
if(ctype_alnum(str_replace($extras, '', $value))) return $this->pageName($value, false, $maxLength);
// validate that all characters are in our whitelist
$whitelist = $this->wire('config')->pageNameWhitelist; $whitelist = $this->wire('config')->pageNameWhitelist;
if(!strlen($whitelist)) $whitelist = false; if(!strlen($whitelist)) $whitelist = false;
$blacklist = '/\\%"\'<>?#@:;,+=*^$()[]{}|&'; $blacklist = '/\\%"\'<>?#@:;,+=*^$()[]{}|&';
// we let regular pageName handle chars like these, if they appear without other UTF-8
$extras = array('.', '-', '_', ',', ';', ':', '(', ')', '!', '?', '&', '%', '$', '#', '@');
if($whitelist === false || strpos($whitelist, ' ') === false) $extras[] = ' ';
// proceed only if value has some non-ascii characters
if(ctype_alnum(str_replace($extras, '', $value))) {
// let regular pageName sanitizer handle this
return $this->pageName($value, false, $maxLength);
}
// validate that all characters are in our whitelist
$replacements = array(); $replacements = array();
for($n = 0; $n < mb_strlen($value); $n++) { for($n = 0; $n < mb_strlen($value); $n++) {
$c = mb_substr($value, $n, 1); $c = mb_substr($value, $n, 1);
if(!strlen(trim($c)) || ctype_cntrl($c)) { $inBlacklist = mb_strpos($blacklist, $c) !== false || strpos($blacklist, $c) !== false;
// character does not resolve to something visible $inWhitelist = !$inBlacklist && $whitelist !== false && mb_strpos($whitelist, $c) !== false;
if($inWhitelist && !$inBlacklist) {
// in whitelist
} else if($inBlacklist || !strlen(trim($c)) || ctype_cntrl($c)) {
// character does not resolve to something visible or is in blacklist
$replacements[] = $c; $replacements[] = $c;
} else if(mb_strpos($blacklist, $c) !== false || strpos($blacklist, $c) !== false) { } else {
// character that is in blacklist
$replacements[] = $c;
} else if($whitelist !== false && mb_strpos($whitelist, $c) === false) {
// character that is not in whitelist, double check case variants // character that is not in whitelist, double check case variants
$cLower = mb_strtolower($c); $cLower = mb_strtolower($c);
$cUpper = mb_strtoupper($c); $cUpper = mb_strtoupper($c);

View File

@@ -281,6 +281,10 @@ class ProcessPageView extends Process {
/** @var Config $config */ /** @var Config $config */
$config = $this->wire('config'); $config = $this->wire('config');
/** @var Sanitizer $sanitizer */
$sanitizer = $this->wire('sanitizer');
/** @var Pages $pages */
$pages = $this->wire('pages');
// force redirect to actual page URL? (if different from request URL) // force redirect to actual page URL? (if different from request URL)
$forceRedirect = false; $forceRedirect = false;
@@ -324,7 +328,7 @@ class ProcessPageView extends Process {
// sanitized URL does not match requested URL // sanitized URL does not match requested URL
if($config->pageNameCharset == 'UTF8') { if($config->pageNameCharset == 'UTF8') {
// test for extended page name URL // test for extended page name URL
$it = $this->wire('sanitizer')->pagePathNameUTF8($shit); $it = $sanitizer->pagePathNameUTF8($shit);
} }
if($shit !== $it) { if($shit !== $it) {
// if still does not match then fail // if still does not match then fail
@@ -368,7 +372,8 @@ class ProcessPageView extends Process {
$this->pageNum = (int) $matches[2]; $this->pageNum = (int) $matches[2];
$page = null; $page = null;
} else { } else {
$page = $this->pages->get("path=$it, status<" . Page::statusMax); $spit = $sanitizer->selectorValue($it);
$page = $pages->get("path=$spit, status<" . Page::statusMax);
} }
$hasTrailingSlash = substr($it, -1) == '/'; $hasTrailingSlash = substr($it, -1) == '/';
@@ -389,11 +394,11 @@ class ProcessPageView extends Process {
} else { } else {
// check for globally unique page which can redirect // check for globally unique page which can redirect
$trit = trim($it, '/'); $trit = trim($it, '/');
$spit = $this->wire('sanitizer')->pageNameUTF8($trit); $spit = $sanitizer->pageNameUTF8($trit);
if($trit === $spit) { if($trit === $spit) {
// one segment off root // one segment off root
$spit = $this->wire('sanitizer')->selectorValue($spit); $spit = $sanitizer->selectorValue($spit);
$page = $this->wire('pages')->get("name=$spit, status=" . Page::statusUnique); $page = $pages->get("name=$spit, status=" . Page::statusUnique);
if($page->id && $page->viewable()) { if($page->id && $page->viewable()) {
$this->redirectURL = $page->url; $this->redirectURL = $page->url;
} else { } else {
@@ -416,8 +421,8 @@ class ProcessPageView extends Process {
$urlSegment = substr($it, $pos); $urlSegment = substr($it, $pos);
$urlSegments[$cnt] = $urlSegment; $urlSegments[$cnt] = $urlSegment;
$it = substr($it, 0, $pos); // $it no longer includes the urlSegment $it = substr($it, 0, $pos); // $it no longer includes the urlSegment
$selector = "path=" . $this->wire('sanitizer')->selectorValue($it, 2048) . ", status<" . Page::statusMax; $selector = "path=" . $sanitizer->selectorValue($it, 2048) . ", status<" . Page::statusMax;
$page = $this->pages->get($selector); $page = $pages->get($selector);
$cnt++; $cnt++;
} }
@@ -570,7 +575,7 @@ class ProcessPageView extends Process {
// now set the URL segments to the $input API variable // now set the URL segments to the $input API variable
$cnt = 1; $cnt = 1;
foreach($urlSegments as $urlSegment) { foreach($urlSegments as $urlSegment) {
if($cnt == 1) $page->urlSegment = $urlSegment; // backwards compatibility if($cnt == 1) $page->setQuietly('urlSegment', $urlSegment); // backwards compatibility
$this->input->setUrlSegment($cnt, $urlSegment); $this->input->setUrlSegment($cnt, $urlSegment);
$cnt++; $cnt++;
} }