From 538ebe4d15e96d3e468b6a219af371d0ddc8480b Mon Sep 17 00:00:00 2001 From: michalsn Date: Fri, 26 Jun 2020 16:02:40 +0200 Subject: [PATCH 1/2] Support unicode for regular expressions in router. Fix #3169 --- system/Router/RouteCollection.php | 2 +- system/Router/Router.php | 11 +++++++---- tests/system/Router/RouterTest.php | 21 +++++++++++++++++++++ 3 files changed, 29 insertions(+), 5 deletions(-) diff --git a/system/Router/RouteCollection.php b/system/Router/RouteCollection.php index c89c0717a5..e952824327 100644 --- a/system/Router/RouteCollection.php +++ b/system/Router/RouteCollection.php @@ -1348,7 +1348,7 @@ class RouteCollection implements RouteCollectionInterface // 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 888928a494..91c399edfa 100644 --- a/system/Router/Router.php +++ b/system/Router/Router.php @@ -171,6 +171,9 @@ class Router implements RouterInterface : $this->controller; } + // Decode URL-encoded string + $uri = urldecode($uri); + if ($this->checkRoutes($uri)) { if ($this->collection->isFiltered($this->matchedRoute[0])) @@ -420,12 +423,12 @@ class Router implements RouterInterface // 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 @@ class Router implements RouterInterface 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 44459876c3..6786154d68 100644 --- a/tests/system/Router/RouterTest.php +++ b/tests/system/Router/RouterTest.php @@ -531,4 +531,25 @@ class RouterTest extends \CodeIgniter\Test\CIUnitTestCase $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()); + } } From 6203e425c6d5d3c9926ed94ededae4ede5838d17 Mon Sep 17 00:00:00 2001 From: michalsn Date: Sun, 28 Jun 2020 08:30:18 +0200 Subject: [PATCH 2/2] Test regex unicode with placeholder --- tests/system/Router/RouterTest.php | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/tests/system/Router/RouterTest.php b/tests/system/Router/RouterTest.php index 6786154d68..9ccf2ae493 100644 --- a/tests/system/Router/RouterTest.php +++ b/tests/system/Router/RouterTest.php @@ -552,4 +552,24 @@ class RouterTest extends \CodeIgniter\Test\CIUnitTestCase ]; $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()); + } }