From aa1c391166e61d811342d17f4b72d49f51bafc31 Mon Sep 17 00:00:00 2001 From: grandeljay Date: Fri, 11 Nov 2022 13:40:40 +0100 Subject: [PATCH] Rework pretty URLs --- .htaccess | 6 +- src/api/url.php | 9 +-- src/assets/js/wishlists.js | 2 +- src/classes/page.php | 37 ++++------- src/classes/url.php | 128 ++++++++++++++++++++++++------------- src/pages/changelog.php | 2 +- 6 files changed, 106 insertions(+), 78 deletions(-) diff --git a/.htaccess b/.htaccess index 48090ef8..6c895b2e 100644 --- a/.htaccess +++ b/.htaccess @@ -10,11 +10,11 @@ RewriteRule ^([a-z\-]+)$ /?page=$1 [QSA,L] # Wishlists (My lists) - RewriteRule ^(wishlists)/([0-9]+)$ /?page=$1&id=$2 [QSA,L] - RewriteRule ^(wishlists)/([0-9]+)/add$ /?page=$1&id=$2&wish_add=true [QSA,L] + RewriteRule ^wishlists/([0-9]+)$ /?page=wishlists&id=$1 [QSA,L] + RewriteRule ^wishlists/([0-9]+)/add$ /?page=wishlists&id=$1&wish_add=true [QSA,L] # Wishlist - RewriteRule ^(wishlist)/([0-9a-f]{40})$ /?page=$1&hash=$2 [QSA,L] + RewriteRule ^wishlist/([0-9a-f]{40})$ /?page=wishlist&hash=$1 [QSA,L] # Blog Post RewriteRule ^blog/([a-z\-0-9]+)$ /?page=post&slug=$1 [QSA,L] diff --git a/src/api/url.php b/src/api/url.php index b99164b6..18424610 100644 --- a/src/api/url.php +++ b/src/api/url.php @@ -18,12 +18,13 @@ if (!isset($page)) { switch ($_SERVER['REQUEST_METHOD']) { case 'GET': if (isset($_GET['url'])) { - $url = new URL(base64_decode($_GET['url'])); + $url_old = base64_decode($_GET['url']); + $url = new URL($url_old); $response['data'] = array( - 'url' => $url->getPretty(), - 'url_old' => $url->url, - 'url_old_pretty' => $url->isPretty(), + 'url' => $url_old, + 'url_pretty' => $url->getPretty(), + 'url_is_pretty' => $url->isPretty(), ); } break; diff --git a/src/assets/js/wishlists.js b/src/assets/js/wishlists.js index 979e1ad2..39e94e52 100644 --- a/src/assets/js/wishlists.js +++ b/src/assets/js/wishlists.js @@ -81,7 +81,7 @@ $(function () { .then(handleFetchError) .then(handleFetchResponse) .then(function(response) { - window.history.pushState(null, document.title, response.data.url); + window.history.pushState(null, document.title, response.data.url_pretty); $('.ui.dropdown.filter.priority') .dropdown('restore default value') diff --git a/src/classes/page.php b/src/classes/page.php index ad28dcec..4c3b1926 100644 --- a/src/classes/page.php +++ b/src/classes/page.php @@ -149,35 +149,26 @@ class Page /** * Session */ - - $user = isset($_SESSION['user']->id) ? $_SESSION['user'] : new User(); - $ignorePower = array( - 'blog', - 'changelog', - 'home', - 'install', - 'login', - 'maintenance', - 'post', - 'register', - 'wishlist', - ); - - if ( - false === $user->isLoggedIn() - && isset($_GET['page']) - && false === in_array($_GET['page'], $ignorePower) - ) { - redirect(Page::PAGE_LOGIN); - } + $user = isset($_SESSION['user']->id) ? $_SESSION['user'] : new User(); /** * Power */ - if (isset($user->power) && $user->power < $this->power) { + if (isset($user->power) && $user->power < $this->power && 0 !== $this->power) { redirect(Page::PAGE_POWER . '&required=' . $this->power); } + /** + * Login + */ + if ( + false === $user->isLoggedIn() + && isset($_GET['page']) + && 0 !== $this->power + ) { + redirect(Page::PAGE_LOGIN); + } + /** * Update */ @@ -200,7 +191,7 @@ class Page * Redirect */ if ($options && $options->getOption('isInstalled') && isset($_GET)) { - $url = new URL(http_build_query($_GET)); + $url = new URL($_SERVER['REQUEST_URI']); if ($url->url && false === $url->isPretty()) { redirect($url->getPretty()); diff --git a/src/classes/url.php b/src/classes/url.php index 7ea5c1b1..e7074146 100644 --- a/src/classes/url.php +++ b/src/classes/url.php @@ -11,7 +11,11 @@ namespace wishthis; class URL { /** - * Static + * Returns the HTTP status code of a URL. + * + * @param string $url + * + * @return integer */ public static function getResponseCode(string $url): int { @@ -43,24 +47,41 @@ class URL } /** - * Non-Static + * The current URL. Can be pretty or not. + * + * @var string */ public string $url; + /** + * Constructor + * + * @param string $url + */ public function __construct(string $url) { $this->url = urldecode($url); - $_GET = $this->get_GET(); + $_GET = $this->getGET(); } + /** + * Returns whether the current URL is pretty. + * + * @return boolean + */ public function isPretty(): bool { - $isPretty = 1 === preg_match('/^\/[a-z0-9\/]+/', $this->url); + $isPretty = 1 === preg_match('/^\/[a-z0-9\/\-]+$/', $this->url); return $isPretty; } + /** + * Returns the original, un-pretty URL or an empty string on failure. + * + * @return string + */ public function getPermalink(): string { $htaccess = preg_split('/\r\n|\r|\n/', file_get_contents(ROOT . '/.htaccess')); @@ -95,10 +116,14 @@ class URL return $permalink; } + /** + * Returns a pretty version of the current URL. + * + * @return string + */ public function getPretty(): string { - $htaccess = preg_split('/\r\n|\r|\n/', file_get_contents(ROOT . '/.htaccess')); - $pretty_url = ''; + $htaccess = preg_split('/\r\n|\r|\n/', file_get_contents(ROOT . '/.htaccess')); if (!$this->url) { return ''; @@ -121,63 +146,74 @@ class URL explode('&', parse_url($target, PHP_URL_QUERY)) ); $flags = explode(',', substr($parts[3], 1, -1)) ?? array(); - parse_str($this->url, $getParameters); - uasort( - $getParameters, - function ($a, $b) { - return strlen($a) <=> strlen($b); + parse_str(ltrim($target, '/?'), $parameters); + /** */ + + /** Determine a potential URL. */ + $potential_url = $rewriteRule; + + preg_match_all('/\(.+?\)/', $rewriteRule, $groups); + $groups = $groups[0]; + + for ($i = 0; $i < count($groups); $i++) { + foreach ($parameters as $key => $value) { + $replacement = '$' . $i + 1; + + if ($replacement === $value && isset($_GET[$key])) { + $potential_url = str_replace( + $groups[$i], + $_GET[$key], + $potential_url + ); + } } + } + + $match = preg_match( + '/^' . str_replace(array('/'), array('\/'), $rewriteRule) . '$/', + $potential_url ); - $getParameters = array_reverse($getParameters, true); - preg_match_all('/\(.+?\)/', $rewriteRule, $regexes); - - $countMatches = 0; - - foreach ($regexes as $matches) { - foreach ($matches as $match) { - foreach ($getParameters as $key => $value) { - if ( - preg_match('/^' . $match . '$/', $value) - && in_array($key, $keys) - && count($getParameters) === count($keys) - ) { - $rewriteRule = str_replace($match, $value, $rewriteRule); - - $countMatches++; - break; - } - } - } - - if ($countMatches > 0 && $countMatches === count($matches)) { - $pretty_url = '/' . $rewriteRule; - - if (in_array('L', $flags)) { - break 3; - } - } + if (1 === $match && count($_GET) === count(explode('/', $rewriteRule))) { + return '/' . $potential_url; } break; } } } - return $pretty_url ?: '/?' . $this->url; + if ('/?' === substr($this->url, 0, 2)) { + return $this->url; + } + + return '/?' . $this->url; } - public function get_GET(): array + /** + * Returns the current URL parameters, even for pretty URLs. + * + * @return array + */ + public function getGET(): array { - $queryString = parse_url($this->getPermalink(), PHP_URL_QUERY); + $queryString = $this->url; $GET = array(); - if ($this->isPretty() && $queryString) { - parse_str($queryString, $GET); - } else { - $GET = $_GET; + if ($this->isPretty()) { + $queryString = parse_url($this->getPermalink(), PHP_URL_QUERY); } + if (null === $queryString) { + return array(); + } + + if ('/?' === substr($queryString, 0, 2)) { + $queryString = substr($queryString, 2); + } + + parse_str($queryString, $GET); + return $GET; } } diff --git a/src/pages/changelog.php b/src/pages/changelog.php index 6d95503c..b129c073 100644 --- a/src/pages/changelog.php +++ b/src/pages/changelog.php @@ -43,7 +43,7 @@ $page->navigation();