From 680e59eb5f390279d09cc071a1b951942be5d593 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maur=C3=ADcio=20Meneghini=20Fauth?= Date: Fri, 13 May 2022 16:45:21 -0300 Subject: [PATCH] Ignore invalid routes cache file MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If the `libraries/cache/routes.cache.php` file is invalid (usually from 5.1), ignores it and try to write a new one instead of failing. Fixes https://github.com/phpmyadmin/phpmyadmin/issues/17522. Signed-off-by: MaurĂ­cio Meneghini Fauth --- libraries/classes/Routing.php | 26 +++++++--- test/classes/RoutingTest.php | 51 +++++++++++++++++++ .../test_data/routes/routes-invalid.cache.txt | 34 +++++++++++++ test/test_data/routes/routes-valid.cache.txt | 18 +++++++ 4 files changed, 123 insertions(+), 6 deletions(-) create mode 100644 test/test_data/routes/routes-invalid.cache.txt create mode 100644 test/test_data/routes/routes-valid.cache.txt diff --git a/libraries/classes/Routing.php b/libraries/classes/Routing.php index afff4babf7..5318d5fb67 100644 --- a/libraries/classes/Routing.php +++ b/libraries/classes/Routing.php @@ -9,9 +9,9 @@ use FastRoute\Dispatcher; use FastRoute\Dispatcher\GroupCountBased as DispatcherGroupCountBased; use FastRoute\RouteCollector; use FastRoute\RouteParser\Std as RouteParserStd; +use PhpMyAdmin\Controllers\HomeController; use PhpMyAdmin\Http\ServerRequest; use Psr\Container\ContainerInterface; -use RuntimeException; use function __; use function file_exists; @@ -28,6 +28,7 @@ use function var_export; use const CACHE_DIR; use const E_USER_WARNING; +use const ROOT_PATH; /** * Class used to warm up the routing cache and manage routing. @@ -73,13 +74,11 @@ class Routing // If skip cache is enabled, do not try to read the file // If no cache skipping then read it and use it if (! $skipCache && file_exists(self::ROUTES_CACHE_FILE)) { - /** @psalm-suppress MissingFile, UnresolvableInclude */ + /** @psalm-suppress MissingFile, UnresolvableInclude, MixedAssignment */ $dispatchData = require self::ROUTES_CACHE_FILE; - if (! is_array($dispatchData)) { - throw new RuntimeException('Invalid cache file "' . self::ROUTES_CACHE_FILE . '"'); + if (self::isRoutesCacheFileValid($dispatchData)) { + return new DispatcherGroupCountBased($dispatchData); } - - return new DispatcherGroupCountBased($dispatchData); } $routeCollector = new RouteCollector( @@ -191,4 +190,19 @@ class Routing $controller = $container->get($controllerName); $controller($request, $vars); } + + /** + * @param mixed $dispatchData + * + * @psalm-assert-if-true array[] $dispatchData + */ + private static function isRoutesCacheFileValid($dispatchData): bool + { + return is_array($dispatchData) + && isset($dispatchData[0], $dispatchData[1]) + && is_array($dispatchData[0]) && is_array($dispatchData[1]) + && isset($dispatchData[0]['GET']) && is_array($dispatchData[0]['GET']) + && isset($dispatchData[0]['GET']['/']) && is_string($dispatchData[0]['GET']['/']) + && $dispatchData[0]['GET']['/'] === HomeController::class; + } } diff --git a/test/classes/RoutingTest.php b/test/classes/RoutingTest.php index 3408311bea..ef8c412843 100644 --- a/test/classes/RoutingTest.php +++ b/test/classes/RoutingTest.php @@ -8,6 +8,11 @@ use FastRoute\Dispatcher; use PhpMyAdmin\Controllers\HomeController; use PhpMyAdmin\Routing; +use function copy; + +use const CACHE_DIR; +use const ROOT_PATH; + /** * @covers \PhpMyAdmin\Routing */ @@ -26,6 +31,52 @@ class RoutingTest extends AbstractTestCase ); } + public function testGetDispatcherWithValidCacheFile(): void + { + $GLOBALS['cfg']['environment'] = null; + + $this->assertDirectoryIsWritable(CACHE_DIR); + $this->assertTrue(copy( + ROOT_PATH . 'test/test_data/routes/routes-valid.cache.txt', + CACHE_DIR . 'routes.cache.php' + )); + + $dispatcher = Routing::getDispatcher(); + $this->assertInstanceOf(Dispatcher::class, $dispatcher); + $this->assertSame( + [Dispatcher::FOUND, HomeController::class, []], + $dispatcher->dispatch('GET', '/') + ); + + $this->assertFileEquals( + CACHE_DIR . 'routes.cache.php', + ROOT_PATH . 'test/test_data/routes/routes-valid.cache.txt' + ); + } + + public function testGetDispatcherWithInvalidCacheFile(): void + { + $GLOBALS['cfg']['environment'] = null; + + $this->assertDirectoryIsWritable(CACHE_DIR); + $this->assertTrue(copy( + ROOT_PATH . 'test/test_data/routes/routes-invalid.cache.txt', + CACHE_DIR . 'routes.cache.php' + )); + + $dispatcher = Routing::getDispatcher(); + $this->assertInstanceOf(Dispatcher::class, $dispatcher); + $this->assertSame( + [Dispatcher::FOUND, HomeController::class, []], + $dispatcher->dispatch('GET', '/') + ); + + $this->assertFileNotEquals( + CACHE_DIR . 'routes.cache.php', + ROOT_PATH . 'test/test_data/routes/routes-invalid.cache.txt' + ); + } + /** * Test for Routing::getCurrentRoute */ diff --git a/test/test_data/routes/routes-invalid.cache.txt b/test/test_data/routes/routes-invalid.cache.txt new file mode 100644 index 0000000000..90196e860e --- /dev/null +++ b/test/test_data/routes/routes-invalid.cache.txt @@ -0,0 +1,34 @@ + + array ( + 'GET' => + array ( + '' => + array ( + 0 => 'PhpMyAdmin\\Controllers\\HomeController', + 1 => 'index', + ), + '/' => + array ( + 0 => 'PhpMyAdmin\\Controllers\\HomeController', + 1 => 'index', + ), + ), + 'POST' => + array ( + '' => + array ( + 0 => 'PhpMyAdmin\\Controllers\\HomeController', + 1 => 'index', + ), + '/' => + array ( + 0 => 'PhpMyAdmin\\Controllers\\HomeController', + 1 => 'index', + ), + ), + ), + 1 => + array ( + ), +); \ No newline at end of file diff --git a/test/test_data/routes/routes-valid.cache.txt b/test/test_data/routes/routes-valid.cache.txt new file mode 100644 index 0000000000..8f828cba0c --- /dev/null +++ b/test/test_data/routes/routes-valid.cache.txt @@ -0,0 +1,18 @@ + + array ( + 'GET' => + array ( + '' => 'PhpMyAdmin\\Controllers\\HomeController', + '/' => 'PhpMyAdmin\\Controllers\\HomeController', + ), + 'POST' => + array ( + '' => 'PhpMyAdmin\\Controllers\\HomeController', + '/' => 'PhpMyAdmin\\Controllers\\HomeController', + ), + ), + 1 => + array ( + ), +); \ No newline at end of file