diff --git a/system/Router/RouteCollection.php b/system/Router/RouteCollection.php index c89c0717a510..e95282432790 100644 --- a/system/Router/RouteCollection.php +++ b/system/Router/RouteCollection.php @@ -1348,7 +1348,7 @@ protected function fillRouteParams(string $from, array $params = null): string // the expected param type. $pos = strpos($from, $pattern); - if (preg_match('#' . $pattern . '#', $params[$index])) + if (preg_match('#^' . $pattern . '$#u', $params[$index])) { $from = substr_replace($from, $params[$index], $pos, strlen($pattern)); } diff --git a/system/Router/Router.php b/system/Router/Router.php index 888928a494db..91c399edfa44 100644 --- a/system/Router/Router.php +++ b/system/Router/Router.php @@ -171,6 +171,9 @@ public function handle(string $uri = null) : $this->controller; } + // Decode URL-encoded string + $uri = urldecode($uri); + if ($this->checkRoutes($uri)) { if ($this->collection->isFiltered($this->matchedRoute[0])) @@ -420,12 +423,12 @@ protected function checkRoutes(string $uri): bool // Replace it with a regex so it // will actually match. - $key = str_replace('/', '\/', $key); + $key = str_replace('/', '\/', $key); $key = str_replace('{locale}', '[^\/]+', $key); } // Does the RegEx match? - if (preg_match('#^' . $key . '$#', $uri, $matches)) + if (preg_match('#^' . $key . '$#u', $uri, $matches)) { // Is this route supposed to redirect to another? if ($this->collection->isRedirect($key)) @@ -470,12 +473,12 @@ protected function checkRoutes(string $uri): bool if (strpos($val, '$') !== false && strpos($key, '(') !== false && strpos($key, '/') !== false) { $replacekey = str_replace('/(.*)', '', $key); - $val = preg_replace('#^' . $key . '$#', $val, $uri); + $val = preg_replace('#^' . $key . '$#u', $val, $uri); $val = str_replace($replacekey, str_replace('/', '\\', $replacekey), $val); } elseif (strpos($val, '$') !== false && strpos($key, '(') !== false) { - $val = preg_replace('#^' . $key . '$#', $val, $uri); + $val = preg_replace('#^' . $key . '$#u', $val, $uri); } elseif (strpos($val, '/') !== false) { diff --git a/tests/system/Router/RouterTest.php b/tests/system/Router/RouterTest.php index 44459876c3b7..9ccf2ae4934c 100644 --- a/tests/system/Router/RouterTest.php +++ b/tests/system/Router/RouterTest.php @@ -531,4 +531,45 @@ public function testAutoRouteMethodEmpty() $this->assertEquals('Home', $router->controllerName()); $this->assertEquals('index', $router->methodName()); } + + //-------------------------------------------------------------------- + + /** + * @see https://github.com/codeigniter4/CodeIgniter4/issues/3169 + */ + public function testRegularExpressionWithUnicode() + { + $this->collection->get('news/([a-z0-9\x{0980}-\x{09ff}-]+)', 'News::view/$1'); + + $router = new Router($this->collection, $this->request); + + $router->handle('news/a0%E0%A6%80%E0%A7%BF-'); + $this->assertEquals('\News', $router->controllerName()); + $this->assertEquals('view', $router->methodName()); + + $expected = [ + 'a0ঀ৿-', + ]; + $this->assertEquals($expected, $router->params()); + } + + /** + * @see https://github.com/codeigniter4/CodeIgniter4/issues/3169 + */ + public function testRegularExpressionPlaceholderWithUnicode() + { + $this->collection->addPlaceholder('custom', '[a-z0-9\x{0980}-\x{09ff}-]+'); + $this->collection->get('news/(:custom)', 'News::view/$1'); + + $router = new Router($this->collection, $this->request); + + $router->handle('news/a0%E0%A6%80%E0%A7%BF-'); + $this->assertEquals('\News', $router->controllerName()); + $this->assertEquals('view', $router->methodName()); + + $expected = [ + 'a0ঀ৿-', + ]; + $this->assertEquals($expected, $router->params()); + } }