From b6282d9a98e4e52c839c3da8da6c63db64283f77 Mon Sep 17 00:00:00 2001 From: Luca Tumedei Date: Fri, 24 Nov 2023 16:38:15 +0100 Subject: [PATCH] fix(MysqlDatabase) remove brittle db name validation, fix #667 and #671 --- CHANGELOG.md | 1 + src/WordPress/Database/MysqlDatabase.php | 10 +--- .../WPBrowser/Events/Module/WPLoaderTest.php | 55 +++++++++++++++++++ .../WordPress/Database/MysqlDatabaseTest.php | 50 ++++++++--------- .../WPBrowser/WordPress/InstallationTest.php | 26 --------- 5 files changed, 80 insertions(+), 62 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 26bb0b17f..ea06dda4d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ This project adheres to [Semantic Versioning](http://semver.org/). ### Fixed - Correctly activate themes during bootstrap. +- Remove brittle database name validation, fix #667 and #671. #### Changed diff --git a/src/WordPress/Database/MysqlDatabase.php b/src/WordPress/Database/MysqlDatabase.php index 2bf8d11b7..5b9bcd7fa 100644 --- a/src/WordPress/Database/MysqlDatabase.php +++ b/src/WordPress/Database/MysqlDatabase.php @@ -30,13 +30,6 @@ public function __construct( private string $dbHost, private string $tablePrefix = 'wp_' ) { - if (!preg_match('/^[a-zA-Z][\w_-]{0,64}$/', $dbName) || str_starts_with('ii', $dbName)) { - throw new DbException( - "Invalid database name: $dbName", - DbException::INVALID_DB_NAME - ); - } - $this->dbName = $dbName; $this->dsnWithoutDbName = DbUtil::dbDsnString(DbUtil::dbDsnMap($dbHost)); $this->dsn = $this->dsnWithoutDbName . ';dbname=' . $dbName; @@ -154,7 +147,8 @@ public function drop(): self public function exists(): bool { - $result = $this->getPDO()->query("SHOW DATABASES LIKE '{$this->dbName}'", PDO::FETCH_COLUMN, 0); + $query = "SHOW DATABASES WHERE `Database` = '{$this->dbName}'"; + $result = $this->getPDO()->query($query, PDO::FETCH_COLUMN, 0); if ($result === false) { return false; diff --git a/tests/unit/lucatume/WPBrowser/Events/Module/WPLoaderTest.php b/tests/unit/lucatume/WPBrowser/Events/Module/WPLoaderTest.php index baab47f62..3bc30d5ab 100644 --- a/tests/unit/lucatume/WPBrowser/Events/Module/WPLoaderTest.php +++ b/tests/unit/lucatume/WPBrowser/Events/Module/WPLoaderTest.php @@ -1873,4 +1873,59 @@ function plugin_2_canary() {} Assert::assertEquals('theme-1', wp_get_theme()->get_stylesheet()); }); } + + public function differentDbNamesProvider(): array + { + return [ + 'with dashes, underscores and dots' => ['test-db_db.db'], + 'only words and numbers' => ['testdb1234567890'], + 'all together' => ['test-db_db.db1234567890'], + 'mydatabase.dev' => ['mydatabase.dev'], + 'my_dbname_n8h96prxar4r' => ['my_dbname_n8h96prxar4r'], + '!funny~db-name' => ['!funny~db-name'], + ]; + } + + /** + * It should correctly load with different database names + * + * @test + * @dataProvider differentDbNamesProvider + */ + public function should_correctly_load_with_different_database_names(string $dbName): void + { + $wpRootDir = FS::tmpDir('wploader_'); + $installation = Installation::scaffold($wpRootDir); + $dbHost = Env::get('WORDPRESS_DB_HOST'); + $dbUser = Env::get('WORDPRESS_DB_USER'); + $dbPassword = Env::get('WORDPRESS_DB_PASSWORD'); + $db = new MysqlDatabase($dbName, $dbUser, $dbPassword, $dbHost, 'test_'); + $db->drop(); + $installation->configure($db); + $installation->install( + 'https://wp.local', + 'admin', + 'password', + 'admin@wp.local', + 'Test' + ); + + $this->config = [ + 'wpRootFolder' => $wpRootDir, + 'dbUrl' => $db->getDbUrl() + ]; + $wpLoader = $this->module(); + + $this->assertEquals( + $db->getDbName(), + $this->assertInIsolation(static function () use ($wpLoader) { + $wpLoader->_initialize(); + + Assert::assertTrue(function_exists('do_action')); + Assert::assertInstanceOf(\WP_User::class, wp_get_current_user()); + + return $wpLoader->getInstallation()->getDb()->getDbName(); + }) + ); + } } diff --git a/tests/unit/lucatume/WPBrowser/WordPress/Database/MysqlDatabaseTest.php b/tests/unit/lucatume/WPBrowser/WordPress/Database/MysqlDatabaseTest.php index edc25eb67..e20389512 100644 --- a/tests/unit/lucatume/WPBrowser/WordPress/Database/MysqlDatabaseTest.php +++ b/tests/unit/lucatume/WPBrowser/WordPress/Database/MysqlDatabaseTest.php @@ -24,19 +24,6 @@ class MysqlDatabaseTest extends Unit use UopzFunctions; use TmpFilesCleanup; - /** - * It should throw when building with invalid db name - * - * @test - */ - public function should_throw_when_building_with_invalid_db_name(): void - { - $this->expectException(DbException::class); - $this->expectExceptionCode(DbException::INVALID_DB_NAME); - - new MysqlDatabase('!invalid~db-name', 'root', 'root', 'localhost'); - } - /** * It should allow getting the db credentials and DSN * @@ -52,8 +39,10 @@ public function should_allow_getting_the_db_credentials_and_dsn(): void $this->assertEquals('192.1.2.3:4415', $db->getDbHost()); $this->assertEquals('test_', $db->getTablePrefix()); $this->assertEquals('mysql:host=192.1.2.3;port=4415;dbname=test', $db->getDsn()); - $this->assertEquals('mysql://bob:secret@192.1.2.3:4415/test', - $db->getDbUrl()); + $this->assertEquals( + 'mysql://bob:secret@192.1.2.3:4415/test', + $db->getDbUrl() + ); } /** @@ -77,8 +66,10 @@ public function should_build_correctly_from_wp_config_file(): void $this->assertEquals('192.1.2.3:4415', $db->getDbHost()); $this->assertEquals('test_', $db->getTablePrefix()); $this->assertEquals('mysql:host=192.1.2.3;port=4415;dbname=test', $db->getDsn()); - $this->assertEquals('mysql://bob:secret@192.1.2.3:4415/test', - $db->getDbUrl()); + $this->assertEquals( + 'mysql://bob:secret@192.1.2.3:4415/test', + $db->getDbUrl() + ); } /** @@ -126,21 +117,24 @@ public function should_allow_options_operations(): void 'admin', 'password', 'admin@wp.local', - 'Test'); + 'Test' + ); new Single($wpRootDir, $wpRootDir . '/wp-config.php'); $this->assertEquals('lorem', $db->getOption('non-existent-option', 'lorem')); - foreach ([ - 'foo' => 'bar', - 'bar' => 2389, - 'object' => (object)['foo' => 'bar'], - 'array' => ['foo' => 'bar'], - 'associative array' => ['foo' => 'bar', 'bar' => 'foo'], - 'null' => null, - 'true' => true, - 'false' => false, - ] as $name => $value) { + foreach ( + [ + 'foo' => 'bar', + 'bar' => 2389, + 'object' => (object)['foo' => 'bar'], + 'array' => ['foo' => 'bar'], + 'associative array' => ['foo' => 'bar', 'bar' => 'foo'], + 'null' => null, + 'true' => true, + 'false' => false, + ] as $name => $value + ) { $this->assertEquals(1, $db->updateOption($name, $value)); $this->assertEquals($value, $db->getOption($name)); } diff --git a/tests/unit/lucatume/WPBrowser/WordPress/InstallationTest.php b/tests/unit/lucatume/WPBrowser/WordPress/InstallationTest.php index e5384624e..db448ba5e 100644 --- a/tests/unit/lucatume/WPBrowser/WordPress/InstallationTest.php +++ b/tests/unit/lucatume/WPBrowser/WordPress/InstallationTest.php @@ -642,30 +642,4 @@ public function should_throw_if_word_press_installation_cannot_be_found_in_direc Installation::findInDir($dir); } - - /** - * It should find WordPress installation in directory - * - * @test - */ - public function should_find_word_press_installation_in_directory(): void - { - if (PHP_VERSION < 8.0) { - $this->markTestSkipped('PHP 8.0 required.'); - } - - $db = new MysqlDatabase( - Random::dbName(), - Env::get('WORDPRESS_DB_USER'), - Env::get('WORDPRESS_DB_PASSWORD'), - Env::get('WORDPRESS_DB_HOST') - ); - $dir = (new BedrockProject($db, 'http://example.com'))->scaffold(FS::tmpDir('installation_')); - - $installation = Installation::findInDir($dir); - - $this->assertInstanceOf(Installation::class, $installation); - $this->assertInstanceOf(Configured::class, $installation->getState()); - $this->assertEquals($dir . '/web/wp/', $installation->getRootDir()); - } }