From 63e64107282cc826209124b500c2d3402b1fcd20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maur=C3=ADcio=20Meneghini=20Fauth?= Date: Sat, 5 Aug 2023 19:27:06 -0300 Subject: [PATCH] Refactor the DbTableExists class MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Changes static methods to instance methods - Extract response handling to the controllers - Add unit tests for the DbTableExists class - Remove the AbstractController::hasDatabase() method Signed-off-by: MaurĂ­cio Meneghini Fauth --- .../Controllers/AbstractController.php | 49 ---- .../Database/DesignerController.php | 16 +- .../Controllers/Database/EventsController.php | 8 +- .../Controllers/Database/ExportController.php | 15 +- .../Controllers/Database/ImportController.php | 15 +- .../Operations/CollationController.php | 9 +- .../Database/OperationsController.php | 14 +- .../Database/RoutinesController.php | 22 +- .../Controllers/Database/SearchController.php | 22 +- .../Controllers/Database/SqlController.php | 17 +- .../Structure/FavoriteTableController.php | 17 +- .../Structure/RealRowCountController.php | 22 +- .../Database/StructureController.php | 16 +- .../Database/TrackingController.php | 15 +- .../Controllers/Table/AddFieldController.php | 30 +- .../Controllers/Table/ChangeController.php | 32 ++- .../Controllers/Table/ChartController.php | 63 ++++- .../Table/DeleteConfirmController.php | 41 ++- .../DropColumnConfirmationController.php | 37 ++- .../Table/FindReplaceController.php | 32 ++- .../Table/GisVisualizationController.php | 15 +- .../Controllers/Table/ImportController.php | 31 ++- .../Table/IndexRenameController.php | 33 ++- .../Controllers/Table/IndexesController.php | 33 ++- .../Table/OperationsController.php | 31 ++- .../Controllers/Table/SearchController.php | 33 ++- .../Controllers/Table/SqlController.php | 33 ++- .../Table/Structure/PrimaryController.php | 31 ++- .../Controllers/Table/StructureController.php | 32 ++- .../Controllers/Table/TrackingController.php | 19 +- .../Table/ZoomSearchController.php | 33 ++- .../Transformation/WrapperController.php | 15 +- .../Controllers/Triggers/IndexController.php | 22 +- .../Controllers/View/CreateController.php | 22 +- .../Controllers/View/OperationsController.php | 31 ++- libraries/classes/DbTableExists.php | 160 +++++------ libraries/services.php | 2 + libraries/services_controllers.php | 86 +++++- phpstan-baseline.neon | 260 ++---------------- psalm-baseline.xml | 36 --- .../Database/EventsControllerTest.php | 15 +- .../Database/RoutinesControllerTest.php | 15 +- .../Structure/FavoriteTableControllerTest.php | 2 + .../Structure/RealRowCountControllerTest.php | 37 +-- .../Database/StructureControllerTest.php | 9 + .../Table/AddFieldControllerTest.php | 9 +- .../Table/ChangeControllerTest.php | 8 +- .../Controllers/Table/ChartControllerTest.php | 14 +- .../Table/DeleteConfirmControllerTest.php | 12 +- .../DropColumnConfirmationControllerTest.php | 7 +- .../Table/FindReplaceControllerTest.php | 9 +- .../Table/GisVisualizationControllerTest.php | 8 +- .../Table/ImportControllerTest.php | 8 +- .../Table/IndexRenameControllerTest.php | 9 +- .../Table/IndexesControllerTest.php | 2 + .../Table/OperationsControllerTest.php | 7 +- .../Table/ReplaceControllerTest.php | 19 +- .../Table/SearchControllerTest.php | 2 + .../Controllers/Table/SqlControllerTest.php | 16 +- .../Table/StructureControllerTest.php | 8 +- .../Table/TrackingControllerTest.php | 9 +- .../Table/ZoomSearchControllerTest.php | 9 +- .../Triggers/IndexControllerTest.php | 15 +- test/classes/DbTableExistsTest.php | 107 +++++++ .../Plugins/Auth/AuthenticationHttpTest.php | 4 +- 65 files changed, 1265 insertions(+), 545 deletions(-) create mode 100644 test/classes/DbTableExistsTest.php diff --git a/libraries/classes/Controllers/AbstractController.php b/libraries/classes/Controllers/AbstractController.php index ec1e37233d..dfe6f6a639 100644 --- a/libraries/classes/Controllers/AbstractController.php +++ b/libraries/classes/Controllers/AbstractController.php @@ -6,7 +6,6 @@ namespace PhpMyAdmin\Controllers; use PhpMyAdmin\Core; use PhpMyAdmin\Html\MySQLDocumentation; -use PhpMyAdmin\Identifiers\DatabaseName; use PhpMyAdmin\Message; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\Template; @@ -35,54 +34,6 @@ abstract class AbstractController $scripts->addFiles($files); } - protected function hasDatabase(): bool - { - $GLOBALS['errno'] ??= null; - $GLOBALS['message'] ??= null; - - if (isset($GLOBALS['is_db']) && $GLOBALS['is_db']) { - return true; - } - - $GLOBALS['is_db'] = false; - $db = DatabaseName::tryFrom($GLOBALS['db']); - - if ($db !== null) { - $GLOBALS['is_db'] = $GLOBALS['dbi']->selectDb($db->getName()); - // This "Command out of sync" 2014 error may happen, for example - // after calling a MySQL procedure; at this point we can't select - // the db but it's not necessarily wrong - if ($GLOBALS['dbi']->getError() && $GLOBALS['errno'] == 2014) { - $GLOBALS['is_db'] = true; - unset($GLOBALS['errno']); - } - } - - if ($db === null || ! $GLOBALS['is_db']) { - if ($this->response->isAjax()) { - $this->response->setRequestStatus(false); - $this->response->addJSON( - 'message', - Message::error(__('No databases selected.')), - ); - - return false; - } - - // Not a valid db name -> back to the welcome page - $params = ['reload' => '1']; - if (isset($GLOBALS['message'])) { - $params['message'] = $GLOBALS['message']; - } - - $this->redirect('/', $params); - - return false; - } - - return $GLOBALS['is_db']; - } - /** @param array $params */ protected function redirect(string $route, array $params = []): void { diff --git a/libraries/classes/Controllers/Database/DesignerController.php b/libraries/classes/Controllers/Database/DesignerController.php index 3eb7211d18..8decd03dfe 100644 --- a/libraries/classes/Controllers/Database/DesignerController.php +++ b/libraries/classes/Controllers/Database/DesignerController.php @@ -7,7 +7,10 @@ namespace PhpMyAdmin\Controllers\Database; use PhpMyAdmin\Controllers\AbstractController; use PhpMyAdmin\Database\Designer; use PhpMyAdmin\Database\Designer\Common as DesignerCommon; +use PhpMyAdmin\DbTableExists; use PhpMyAdmin\Http\ServerRequest; +use PhpMyAdmin\Identifiers\DatabaseName; +use PhpMyAdmin\Message; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\Template; use PhpMyAdmin\Url; @@ -25,6 +28,7 @@ class DesignerController extends AbstractController Template $template, private Designer $databaseDesigner, private DesignerCommon $designerCommon, + private readonly DbTableExists $dbTableExists, ) { parent::__construct($response, $template); } @@ -147,7 +151,17 @@ class DesignerController extends AbstractController $GLOBALS['errorUrl'] = Util::getScriptNameForOption($GLOBALS['cfg']['DefaultTabDatabase'], 'database'); $GLOBALS['errorUrl'] .= Url::getCommon(['db' => $GLOBALS['db']], '&'); - if (! $this->hasDatabase()) { + $databaseName = DatabaseName::tryFrom($request->getParam('db')); + if ($databaseName === null || ! $this->dbTableExists->hasDatabase($databaseName)) { + if ($request->isAjax()) { + $this->response->setRequestStatus(false); + $this->response->addJSON('message', Message::error(__('No databases selected.'))); + + return; + } + + $this->redirect('/', ['reload' => true, 'message' => __('No databases selected.')]); + return; } diff --git a/libraries/classes/Controllers/Database/EventsController.php b/libraries/classes/Controllers/Database/EventsController.php index 28b210f006..17905d6c85 100644 --- a/libraries/classes/Controllers/Database/EventsController.php +++ b/libraries/classes/Controllers/Database/EventsController.php @@ -7,7 +7,9 @@ namespace PhpMyAdmin\Controllers\Database; use PhpMyAdmin\Controllers\AbstractController; use PhpMyAdmin\Database\Events; use PhpMyAdmin\DatabaseInterface; +use PhpMyAdmin\DbTableExists; use PhpMyAdmin\Http\ServerRequest; +use PhpMyAdmin\Identifiers\DatabaseName; use PhpMyAdmin\Message; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\Template; @@ -29,6 +31,7 @@ final class EventsController extends AbstractController Template $template, private Events $events, private DatabaseInterface $dbi, + private readonly DbTableExists $dbTableExists, ) { parent::__construct($response, $template); } @@ -47,7 +50,10 @@ final class EventsController extends AbstractController $GLOBALS['errorUrl'] = Util::getScriptNameForOption($GLOBALS['cfg']['DefaultTabDatabase'], 'database'); $GLOBALS['errorUrl'] .= Url::getCommon(['db' => $GLOBALS['db']], '&'); - if (! $this->hasDatabase()) { + $databaseName = DatabaseName::tryFrom($request->getParam('db')); + if ($databaseName === null || ! $this->dbTableExists->hasDatabase($databaseName)) { + $this->redirect('/', ['reload' => true, 'message' => __('No databases selected.')]); + return; } } elseif (strlen($GLOBALS['db']) > 0) { diff --git a/libraries/classes/Controllers/Database/ExportController.php b/libraries/classes/Controllers/Database/ExportController.php index 4b35adf5ec..ed06084ebf 100644 --- a/libraries/classes/Controllers/Database/ExportController.php +++ b/libraries/classes/Controllers/Database/ExportController.php @@ -6,9 +6,11 @@ namespace PhpMyAdmin\Controllers\Database; use PhpMyAdmin\Config\PageSettings; use PhpMyAdmin\Controllers\AbstractController; +use PhpMyAdmin\DbTableExists; use PhpMyAdmin\Export\Export; use PhpMyAdmin\Export\Options; use PhpMyAdmin\Http\ServerRequest; +use PhpMyAdmin\Identifiers\DatabaseName; use PhpMyAdmin\Message; use PhpMyAdmin\Plugins; use PhpMyAdmin\ResponseRenderer; @@ -28,6 +30,7 @@ final class ExportController extends AbstractController private Export $export, private Options $exportOptions, private PageSettings $pageSettings, + private readonly DbTableExists $dbTableExists, ) { parent::__construct($response, $template); } @@ -51,7 +54,17 @@ final class ExportController extends AbstractController $GLOBALS['errorUrl'] = Util::getScriptNameForOption($GLOBALS['cfg']['DefaultTabDatabase'], 'database'); $GLOBALS['errorUrl'] .= Url::getCommon(['db' => $GLOBALS['db']], '&'); - if (! $this->hasDatabase()) { + $databaseName = DatabaseName::tryFrom($request->getParam('db')); + if ($databaseName === null || ! $this->dbTableExists->hasDatabase($databaseName)) { + if ($request->isAjax()) { + $this->response->setRequestStatus(false); + $this->response->addJSON('message', Message::error(__('No databases selected.'))); + + return; + } + + $this->redirect('/', ['reload' => true, 'message' => __('No databases selected.')]); + return; } diff --git a/libraries/classes/Controllers/Database/ImportController.php b/libraries/classes/Controllers/Database/ImportController.php index 1d794c115e..fdcbc37389 100644 --- a/libraries/classes/Controllers/Database/ImportController.php +++ b/libraries/classes/Controllers/Database/ImportController.php @@ -8,8 +8,10 @@ use PhpMyAdmin\Charsets; use PhpMyAdmin\Config\PageSettings; use PhpMyAdmin\Controllers\AbstractController; use PhpMyAdmin\DatabaseInterface; +use PhpMyAdmin\DbTableExists; use PhpMyAdmin\Encoding; use PhpMyAdmin\Http\ServerRequest; +use PhpMyAdmin\Identifiers\DatabaseName; use PhpMyAdmin\Import\Ajax; use PhpMyAdmin\Import\Import; use PhpMyAdmin\Message; @@ -31,6 +33,7 @@ final class ImportController extends AbstractController Template $template, private DatabaseInterface $dbi, private PageSettings $pageSettings, + private readonly DbTableExists $dbTableExists, ) { parent::__construct($response, $template); } @@ -51,7 +54,17 @@ final class ImportController extends AbstractController $GLOBALS['errorUrl'] = Util::getScriptNameForOption($GLOBALS['cfg']['DefaultTabDatabase'], 'database'); $GLOBALS['errorUrl'] .= Url::getCommon(['db' => $GLOBALS['db']], '&'); - if (! $this->hasDatabase()) { + $databaseName = DatabaseName::tryFrom($request->getParam('db')); + if ($databaseName === null || ! $this->dbTableExists->hasDatabase($databaseName)) { + if ($request->isAjax()) { + $this->response->setRequestStatus(false); + $this->response->addJSON('message', Message::error(__('No databases selected.'))); + + return; + } + + $this->redirect('/', ['reload' => true, 'message' => __('No databases selected.')]); + return; } diff --git a/libraries/classes/Controllers/Database/Operations/CollationController.php b/libraries/classes/Controllers/Database/Operations/CollationController.php index 56dd7f9d18..4944201e06 100644 --- a/libraries/classes/Controllers/Database/Operations/CollationController.php +++ b/libraries/classes/Controllers/Database/Operations/CollationController.php @@ -6,7 +6,9 @@ namespace PhpMyAdmin\Controllers\Database\Operations; use PhpMyAdmin\Controllers\AbstractController; use PhpMyAdmin\DatabaseInterface; +use PhpMyAdmin\DbTableExists; use PhpMyAdmin\Http\ServerRequest; +use PhpMyAdmin\Identifiers\DatabaseName; use PhpMyAdmin\Message; use PhpMyAdmin\Operations; use PhpMyAdmin\ResponseRenderer; @@ -23,6 +25,7 @@ final class CollationController extends AbstractController Template $template, private Operations $operations, private DatabaseInterface $dbi, + private readonly DbTableExists $dbTableExists, ) { parent::__construct($response, $template); } @@ -48,7 +51,11 @@ final class CollationController extends AbstractController $GLOBALS['errorUrl'] = Util::getScriptNameForOption($GLOBALS['cfg']['DefaultTabDatabase'], 'database'); $GLOBALS['errorUrl'] .= Url::getCommon(['db' => $GLOBALS['db']], '&'); - if (! $this->hasDatabase()) { + $databaseName = DatabaseName::tryFrom($request->getParam('db')); + if ($databaseName === null || ! $this->dbTableExists->hasDatabase($databaseName)) { + $this->response->setRequestStatus(false); + $this->response->addJSON('message', Message::error(__('No databases selected.'))); + return; } diff --git a/libraries/classes/Controllers/Database/OperationsController.php b/libraries/classes/Controllers/Database/OperationsController.php index e5434e44a7..dfdf61c232 100644 --- a/libraries/classes/Controllers/Database/OperationsController.php +++ b/libraries/classes/Controllers/Database/OperationsController.php @@ -10,6 +10,7 @@ use PhpMyAdmin\ConfigStorage\Relation; use PhpMyAdmin\ConfigStorage\RelationCleanup; use PhpMyAdmin\Controllers\AbstractController; use PhpMyAdmin\DatabaseInterface; +use PhpMyAdmin\DbTableExists; use PhpMyAdmin\Html\Generator; use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\Identifiers\DatabaseName; @@ -40,6 +41,7 @@ class OperationsController extends AbstractController private Relation $relation, private RelationCleanup $relationCleanup, private DatabaseInterface $dbi, + private readonly DbTableExists $dbTableExists, ) { parent::__construct($response, $template); } @@ -220,7 +222,17 @@ class OperationsController extends AbstractController $GLOBALS['errorUrl'] = Util::getScriptNameForOption($GLOBALS['cfg']['DefaultTabDatabase'], 'database'); $GLOBALS['errorUrl'] .= Url::getCommon(['db' => $GLOBALS['db']], '&'); - if (! $this->hasDatabase()) { + $databaseName = DatabaseName::tryFrom($request->getParam('db')); + if ($databaseName === null || ! $this->dbTableExists->hasDatabase($databaseName)) { + if ($request->isAjax()) { + $this->response->setRequestStatus(false); + $this->response->addJSON('message', Message::error(__('No databases selected.'))); + + return; + } + + $this->redirect('/', ['reload' => true, 'message' => __('No databases selected.')]); + return; } diff --git a/libraries/classes/Controllers/Database/RoutinesController.php b/libraries/classes/Controllers/Database/RoutinesController.php index c6989d96e4..de93556681 100644 --- a/libraries/classes/Controllers/Database/RoutinesController.php +++ b/libraries/classes/Controllers/Database/RoutinesController.php @@ -11,6 +11,8 @@ use PhpMyAdmin\Database\Routines; use PhpMyAdmin\DatabaseInterface; use PhpMyAdmin\DbTableExists; use PhpMyAdmin\Http\ServerRequest; +use PhpMyAdmin\Identifiers\DatabaseName; +use PhpMyAdmin\Identifiers\TableName; use PhpMyAdmin\Message; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\Template; @@ -39,6 +41,7 @@ class RoutinesController extends AbstractController private CheckUserPrivileges $checkUserPrivileges, private DatabaseInterface $dbi, private Routines $routines, + private readonly DbTableExists $dbTableExists, ) { parent::__construct($response, $template); } @@ -66,7 +69,19 @@ class RoutinesController extends AbstractController $GLOBALS['errorUrl'] = Util::getScriptNameForOption($GLOBALS['cfg']['DefaultTabTable'], 'table'); $GLOBALS['errorUrl'] .= Url::getCommon($GLOBALS['urlParams'], '&'); - DbTableExists::check($GLOBALS['db'], $GLOBALS['table']); + $databaseName = DatabaseName::tryFrom($request->getParam('db')); + if ($databaseName === null || ! $this->dbTableExists->hasDatabase($databaseName)) { + $this->redirect('/', ['reload' => true, 'message' => __('No databases selected.')]); + + return; + } + + $tableName = TableName::tryFrom($request->getParam('table')); + if ($tableName === null || ! $this->dbTableExists->hasTable($databaseName, $tableName)) { + $this->redirect('/', ['reload' => true, 'message' => __('No table selected.')]); + + return; + } } else { $GLOBALS['table'] = ''; @@ -75,7 +90,10 @@ class RoutinesController extends AbstractController $GLOBALS['errorUrl'] = Util::getScriptNameForOption($GLOBALS['cfg']['DefaultTabDatabase'], 'database'); $GLOBALS['errorUrl'] .= Url::getCommon(['db' => $GLOBALS['db']], '&'); - if (! $this->hasDatabase()) { + $databaseName = DatabaseName::tryFrom($request->getParam('db')); + if ($databaseName === null || ! $this->dbTableExists->hasDatabase($databaseName)) { + $this->redirect('/', ['reload' => true, 'message' => __('No databases selected.')]); + return; } } diff --git a/libraries/classes/Controllers/Database/SearchController.php b/libraries/classes/Controllers/Database/SearchController.php index 528bb1a1d8..8fe1bcbf77 100644 --- a/libraries/classes/Controllers/Database/SearchController.php +++ b/libraries/classes/Controllers/Database/SearchController.php @@ -7,8 +7,10 @@ namespace PhpMyAdmin\Controllers\Database; use PhpMyAdmin\Controllers\AbstractController; use PhpMyAdmin\Database\Search; use PhpMyAdmin\DatabaseInterface; +use PhpMyAdmin\DbTableExists; use PhpMyAdmin\Html\MySQLDocumentation; use PhpMyAdmin\Http\ServerRequest; +use PhpMyAdmin\Identifiers\DatabaseName; use PhpMyAdmin\Message; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\Template; @@ -19,8 +21,12 @@ use function __; class SearchController extends AbstractController { - public function __construct(ResponseRenderer $response, Template $template, private DatabaseInterface $dbi) - { + public function __construct( + ResponseRenderer $response, + Template $template, + private DatabaseInterface $dbi, + private readonly DbTableExists $dbTableExists, + ) { parent::__construct($response, $template); } @@ -36,7 +42,17 @@ class SearchController extends AbstractController $GLOBALS['errorUrl'] = Util::getScriptNameForOption($GLOBALS['cfg']['DefaultTabDatabase'], 'database'); $GLOBALS['errorUrl'] .= Url::getCommon(['db' => $GLOBALS['db']], '&'); - if (! $this->hasDatabase()) { + $databaseName = DatabaseName::tryFrom($request->getParam('db')); + if ($databaseName === null || ! $this->dbTableExists->hasDatabase($databaseName)) { + if ($request->isAjax()) { + $this->response->setRequestStatus(false); + $this->response->addJSON('message', Message::error(__('No databases selected.'))); + + return; + } + + $this->redirect('/', ['reload' => true, 'message' => __('No databases selected.')]); + return; } diff --git a/libraries/classes/Controllers/Database/SqlController.php b/libraries/classes/Controllers/Database/SqlController.php index 8882bddf60..f6c50f4560 100644 --- a/libraries/classes/Controllers/Database/SqlController.php +++ b/libraries/classes/Controllers/Database/SqlController.php @@ -6,13 +6,17 @@ namespace PhpMyAdmin\Controllers\Database; use PhpMyAdmin\Config\PageSettings; use PhpMyAdmin\Controllers\AbstractController; +use PhpMyAdmin\DbTableExists; use PhpMyAdmin\Http\ServerRequest; +use PhpMyAdmin\Identifiers\DatabaseName; +use PhpMyAdmin\Message; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\SqlQueryForm; use PhpMyAdmin\Template; use PhpMyAdmin\Url; use PhpMyAdmin\Util; +use function __; use function htmlspecialchars; /** @@ -25,6 +29,7 @@ class SqlController extends AbstractController Template $template, private SqlQueryForm $sqlQueryForm, private PageSettings $pageSettings, + private readonly DbTableExists $dbTableExists, ) { parent::__construct($response, $template); } @@ -46,7 +51,17 @@ class SqlController extends AbstractController $GLOBALS['errorUrl'] = Util::getScriptNameForOption($GLOBALS['cfg']['DefaultTabDatabase'], 'database'); $GLOBALS['errorUrl'] .= Url::getCommon(['db' => $GLOBALS['db']], '&'); - if (! $this->hasDatabase()) { + $databaseName = DatabaseName::tryFrom($request->getParam('db')); + if ($databaseName === null || ! $this->dbTableExists->hasDatabase($databaseName)) { + if ($request->isAjax()) { + $this->response->setRequestStatus(false); + $this->response->addJSON('message', Message::error(__('No databases selected.'))); + + return; + } + + $this->redirect('/', ['reload' => true, 'message' => __('No databases selected.')]); + return; } diff --git a/libraries/classes/Controllers/Database/Structure/FavoriteTableController.php b/libraries/classes/Controllers/Database/Structure/FavoriteTableController.php index 59b8f1b472..46e2af5085 100644 --- a/libraries/classes/Controllers/Database/Structure/FavoriteTableController.php +++ b/libraries/classes/Controllers/Database/Structure/FavoriteTableController.php @@ -6,7 +6,10 @@ namespace PhpMyAdmin\Controllers\Database\Structure; use PhpMyAdmin\ConfigStorage\Relation; use PhpMyAdmin\Controllers\AbstractController; +use PhpMyAdmin\DbTableExists; use PhpMyAdmin\Http\ServerRequest; +use PhpMyAdmin\Identifiers\DatabaseName; +use PhpMyAdmin\Message; use PhpMyAdmin\RecentFavoriteTable; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\Template; @@ -22,8 +25,12 @@ use function sha1; final class FavoriteTableController extends AbstractController { - public function __construct(ResponseRenderer $response, Template $template, private Relation $relation) - { + public function __construct( + ResponseRenderer $response, + Template $template, + private Relation $relation, + private readonly DbTableExists $dbTableExists, + ) { parent::__construct($response, $template); } @@ -72,7 +79,11 @@ final class FavoriteTableController extends AbstractController return; } - if (! $this->hasDatabase()) { + $databaseName = DatabaseName::tryFrom($request->getParam('db')); + if ($databaseName === null || ! $this->dbTableExists->hasDatabase($databaseName)) { + $this->response->setRequestStatus(false); + $this->response->addJSON('message', Message::error(__('No databases selected.'))); + return; } diff --git a/libraries/classes/Controllers/Database/Structure/RealRowCountController.php b/libraries/classes/Controllers/Database/Structure/RealRowCountController.php index b097184957..2be88184e0 100644 --- a/libraries/classes/Controllers/Database/Structure/RealRowCountController.php +++ b/libraries/classes/Controllers/Database/Structure/RealRowCountController.php @@ -6,12 +6,16 @@ namespace PhpMyAdmin\Controllers\Database\Structure; use PhpMyAdmin\Controllers\AbstractController; use PhpMyAdmin\DatabaseInterface; +use PhpMyAdmin\DbTableExists; use PhpMyAdmin\Http\ServerRequest; +use PhpMyAdmin\Identifiers\DatabaseName; +use PhpMyAdmin\Message; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\Template; use PhpMyAdmin\Url; use PhpMyAdmin\Util; +use function __; use function json_encode; /** @@ -19,8 +23,12 @@ use function json_encode; */ final class RealRowCountController extends AbstractController { - public function __construct(ResponseRenderer $response, Template $template, private DatabaseInterface $dbi) - { + public function __construct( + ResponseRenderer $response, + Template $template, + private DatabaseInterface $dbi, + private readonly DbTableExists $dbTableExists, + ) { parent::__construct($response, $template); } @@ -38,7 +46,15 @@ final class RealRowCountController extends AbstractController $GLOBALS['errorUrl'] = Util::getScriptNameForOption($GLOBALS['cfg']['DefaultTabDatabase'], 'database'); $GLOBALS['errorUrl'] .= Url::getCommon(['db' => $GLOBALS['db']], '&'); - if (! $this->hasDatabase() || ! $request->isAjax()) { + if (! $request->isAjax()) { + return; + } + + $databaseName = DatabaseName::tryFrom($request->getParam('db')); + if ($databaseName === null || ! $this->dbTableExists->hasDatabase($databaseName)) { + $this->response->setRequestStatus(false); + $this->response->addJSON('message', Message::error(__('No databases selected.'))); + return; } diff --git a/libraries/classes/Controllers/Database/StructureController.php b/libraries/classes/Controllers/Database/StructureController.php index bbc25d2a37..84da4bed74 100644 --- a/libraries/classes/Controllers/Database/StructureController.php +++ b/libraries/classes/Controllers/Database/StructureController.php @@ -10,8 +10,11 @@ use PhpMyAdmin\Config\PageSettings; use PhpMyAdmin\ConfigStorage\Relation; use PhpMyAdmin\Controllers\AbstractController; use PhpMyAdmin\DatabaseInterface; +use PhpMyAdmin\DbTableExists; use PhpMyAdmin\Html\Generator; use PhpMyAdmin\Http\ServerRequest; +use PhpMyAdmin\Identifiers\DatabaseName; +use PhpMyAdmin\Message; use PhpMyAdmin\Query\Utilities; use PhpMyAdmin\RecentFavoriteTable; use PhpMyAdmin\Replication\Replication; @@ -78,6 +81,7 @@ class StructureController extends AbstractController private DatabaseInterface $dbi, private TrackingChecker $trackingChecker, private PageSettings $pageSettings, + private readonly DbTableExists $dbTableExists, ) { parent::__construct($response, $template); @@ -125,7 +129,17 @@ class StructureController extends AbstractController $GLOBALS['errorUrl'] = Util::getScriptNameForOption($GLOBALS['cfg']['DefaultTabDatabase'], 'database'); $GLOBALS['errorUrl'] .= Url::getCommon(['db' => $GLOBALS['db']], '&'); - if (! $this->hasDatabase()) { + $databaseName = DatabaseName::tryFrom($request->getParam('db')); + if ($databaseName === null || ! $this->dbTableExists->hasDatabase($databaseName)) { + if ($request->isAjax()) { + $this->response->setRequestStatus(false); + $this->response->addJSON('message', Message::error(__('No databases selected.'))); + + return; + } + + $this->redirect('/', ['reload' => true, 'message' => __('No databases selected.')]); + return; } diff --git a/libraries/classes/Controllers/Database/TrackingController.php b/libraries/classes/Controllers/Database/TrackingController.php index 4b1e776fc1..70da57cd74 100644 --- a/libraries/classes/Controllers/Database/TrackingController.php +++ b/libraries/classes/Controllers/Database/TrackingController.php @@ -7,8 +7,10 @@ namespace PhpMyAdmin\Controllers\Database; use PhpMyAdmin\CheckUserPrivileges; use PhpMyAdmin\Controllers\AbstractController; use PhpMyAdmin\DatabaseInterface; +use PhpMyAdmin\DbTableExists; use PhpMyAdmin\Html\Generator; use PhpMyAdmin\Http\ServerRequest; +use PhpMyAdmin\Identifiers\DatabaseName; use PhpMyAdmin\Message; use PhpMyAdmin\Query\Utilities; use PhpMyAdmin\ResponseRenderer; @@ -31,6 +33,7 @@ class TrackingController extends AbstractController Template $template, private Tracking $tracking, private DatabaseInterface $dbi, + private readonly DbTableExists $dbTableExists, ) { parent::__construct($response, $template); } @@ -48,7 +51,17 @@ class TrackingController extends AbstractController $GLOBALS['errorUrl'] = Util::getScriptNameForOption($GLOBALS['cfg']['DefaultTabDatabase'], 'database'); $GLOBALS['errorUrl'] .= Url::getCommon(['db' => $GLOBALS['db']], '&'); - if (! $this->hasDatabase()) { + $databaseName = DatabaseName::tryFrom($request->getParam('db')); + if ($databaseName === null || ! $this->dbTableExists->hasDatabase($databaseName)) { + if ($request->isAjax()) { + $this->response->setRequestStatus(false); + $this->response->addJSON('message', Message::error(__('No databases selected.'))); + + return; + } + + $this->redirect('/', ['reload' => true, 'message' => __('No databases selected.')]); + return; } diff --git a/libraries/classes/Controllers/Table/AddFieldController.php b/libraries/classes/Controllers/Table/AddFieldController.php index 80bca6cc96..f89d3cbb4b 100644 --- a/libraries/classes/Controllers/Table/AddFieldController.php +++ b/libraries/classes/Controllers/Table/AddFieldController.php @@ -13,6 +13,7 @@ use PhpMyAdmin\DbTableExists; use PhpMyAdmin\Html\Generator; use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\Identifiers\DatabaseName; +use PhpMyAdmin\Identifiers\TableName; use PhpMyAdmin\Message; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\Table\ColumnsDefinition; @@ -40,6 +41,7 @@ class AddFieldController extends AbstractController private Config $config, private DatabaseInterface $dbi, private ColumnsDefinition $columnsDefinition, + private readonly DbTableExists $dbTableExists, ) { parent::__construct($response, $template); } @@ -165,7 +167,33 @@ class AddFieldController extends AbstractController $GLOBALS['errorUrl'] = Util::getScriptNameForOption($cfg['DefaultTabTable'], 'table'); $GLOBALS['errorUrl'] .= Url::getCommon($urlParams, '&'); - DbTableExists::check($GLOBALS['db'], $GLOBALS['table']); + $databaseName = DatabaseName::tryFrom($request->getParam('db')); + if ($databaseName === null || ! $this->dbTableExists->hasDatabase($databaseName)) { + if ($request->isAjax()) { + $this->response->setRequestStatus(false); + $this->response->addJSON('message', Message::error(__('No databases selected.'))); + + return; + } + + $this->redirect('/', ['reload' => true, 'message' => __('No databases selected.')]); + + return; + } + + $tableName = TableName::tryFrom($request->getParam('table')); + if ($tableName === null || ! $this->dbTableExists->hasTable($databaseName, $tableName)) { + if ($request->isAjax()) { + $this->response->setRequestStatus(false); + $this->response->addJSON('message', Message::error(__('No table selected.'))); + + return; + } + + $this->redirect('/', ['reload' => true, 'message' => __('No table selected.')]); + + return; + } $GLOBALS['active_page'] = Url::getFromRoute('/table/structure'); diff --git a/libraries/classes/Controllers/Table/ChangeController.php b/libraries/classes/Controllers/Table/ChangeController.php index 766f06850f..5c9318dd40 100644 --- a/libraries/classes/Controllers/Table/ChangeController.php +++ b/libraries/classes/Controllers/Table/ChangeController.php @@ -11,7 +11,10 @@ use PhpMyAdmin\Core; use PhpMyAdmin\DbTableExists; use PhpMyAdmin\Html\Generator; use PhpMyAdmin\Http\ServerRequest; +use PhpMyAdmin\Identifiers\DatabaseName; +use PhpMyAdmin\Identifiers\TableName; use PhpMyAdmin\InsertEdit; +use PhpMyAdmin\Message; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\Template; use PhpMyAdmin\Url; @@ -37,6 +40,7 @@ class ChangeController extends AbstractController private InsertEdit $insertEdit, private Relation $relation, private PageSettings $pageSettings, + private readonly DbTableExists $dbTableExists, ) { parent::__construct($response, $template); } @@ -56,7 +60,33 @@ class ChangeController extends AbstractController $this->response->addHTML($this->pageSettings->getErrorHTML()); $this->response->addHTML($this->pageSettings->getHTML()); - DbTableExists::check($GLOBALS['db'], $GLOBALS['table']); + $databaseName = DatabaseName::tryFrom($request->getParam('db')); + if ($databaseName === null || ! $this->dbTableExists->hasDatabase($databaseName)) { + if ($request->isAjax()) { + $this->response->setRequestStatus(false); + $this->response->addJSON('message', Message::error(__('No databases selected.'))); + + return; + } + + $this->redirect('/', ['reload' => true, 'message' => __('No databases selected.')]); + + return; + } + + $tableName = TableName::tryFrom($request->getParam('table')); + if ($tableName === null || ! $this->dbTableExists->hasTable($databaseName, $tableName)) { + if ($request->isAjax()) { + $this->response->setRequestStatus(false); + $this->response->addJSON('message', Message::error(__('No table selected.'))); + + return; + } + + $this->redirect('/', ['reload' => true, 'message' => __('No table selected.')]); + + return; + } if ($request->hasQueryParam('where_clause') && $request->hasQueryParam('where_clause_signature')) { $whereClause = $request->getQueryParam('where_clause'); diff --git a/libraries/classes/Controllers/Table/ChartController.php b/libraries/classes/Controllers/Table/ChartController.php index c7a2e29be5..cda36541c8 100644 --- a/libraries/classes/Controllers/Table/ChartController.php +++ b/libraries/classes/Controllers/Table/ChartController.php @@ -10,6 +10,8 @@ use PhpMyAdmin\DbTableExists; use PhpMyAdmin\FieldMetadata; use PhpMyAdmin\Html\Generator; use PhpMyAdmin\Http\ServerRequest; +use PhpMyAdmin\Identifiers\DatabaseName; +use PhpMyAdmin\Identifiers\TableName; use PhpMyAdmin\Message; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\SqlParser\Components\Limit; @@ -35,6 +37,7 @@ class ChartController extends AbstractController ResponseRenderer $response, Template $template, private DatabaseInterface $dbi, + private readonly DbTableExists $dbTableExists, ) { parent::__construct($response, $template); } @@ -44,7 +47,7 @@ class ChartController extends AbstractController $GLOBALS['errorUrl'] ??= null; if (isset($_REQUEST['pos'], $_REQUEST['session_max_rows']) && $request->isAjax()) { - $this->ajax(); + $this->ajax($request); return; } @@ -86,7 +89,33 @@ class ChartController extends AbstractController $GLOBALS['errorUrl'] = Util::getScriptNameForOption($GLOBALS['cfg']['DefaultTabTable'], 'table'); $GLOBALS['errorUrl'] .= Url::getCommon($urlParams, '&'); - DbTableExists::check($GLOBALS['db'], $GLOBALS['table']); + $databaseName = DatabaseName::tryFrom($request->getParam('db')); + if ($databaseName === null || ! $this->dbTableExists->hasDatabase($databaseName)) { + if ($request->isAjax()) { + $this->response->setRequestStatus(false); + $this->response->addJSON('message', Message::error(__('No databases selected.'))); + + return; + } + + $this->redirect('/', ['reload' => true, 'message' => __('No databases selected.')]); + + return; + } + + $tableName = TableName::tryFrom($request->getParam('table')); + if ($tableName === null || ! $this->dbTableExists->hasTable($databaseName, $tableName)) { + if ($request->isAjax()) { + $this->response->setRequestStatus(false); + $this->response->addJSON('message', Message::error(__('No table selected.'))); + + return; + } + + $this->redirect('/', ['reload' => true, 'message' => __('No table selected.')]); + + return; + } $urlParams['goto'] = Util::getScriptNameForOption($GLOBALS['cfg']['DefaultTabTable'], 'table'); $urlParams['back'] = Url::getFromRoute('/table/sql'); @@ -100,7 +129,17 @@ class ChartController extends AbstractController $GLOBALS['errorUrl'] = Util::getScriptNameForOption($GLOBALS['cfg']['DefaultTabDatabase'], 'database'); $GLOBALS['errorUrl'] .= Url::getCommon(['db' => $GLOBALS['db']], '&'); - if (! $this->hasDatabase()) { + $databaseName = DatabaseName::tryFrom($request->getParam('db')); + if ($databaseName === null || ! $this->dbTableExists->hasDatabase($databaseName)) { + if ($request->isAjax()) { + $this->response->setRequestStatus(false); + $this->response->addJSON('message', Message::error(__('No databases selected.'))); + + return; + } + + $this->redirect('/', ['reload' => true, 'message' => __('No databases selected.')]); + return; } } else { @@ -164,7 +203,7 @@ class ChartController extends AbstractController /** * Handle ajax request */ - public function ajax(): void + public function ajax(ServerRequest $request): void { $GLOBALS['urlParams'] ??= null; $GLOBALS['errorUrl'] ??= null; @@ -175,7 +214,21 @@ class ChartController extends AbstractController $GLOBALS['errorUrl'] = Util::getScriptNameForOption($GLOBALS['cfg']['DefaultTabTable'], 'table'); $GLOBALS['errorUrl'] .= Url::getCommon($GLOBALS['urlParams'], '&'); - DbTableExists::check($GLOBALS['db'], $GLOBALS['table']); + $databaseName = DatabaseName::tryFrom($request->getParam('db')); + if ($databaseName === null || ! $this->dbTableExists->hasDatabase($databaseName)) { + $this->response->setRequestStatus(false); + $this->response->addJSON('message', Message::error(__('No databases selected.'))); + + return; + } + + $tableName = TableName::tryFrom($request->getParam('table')); + if ($tableName === null || ! $this->dbTableExists->hasTable($databaseName, $tableName)) { + $this->response->setRequestStatus(false); + $this->response->addJSON('message', Message::error(__('No table selected.'))); + + return; + } } $parser = new Parser($GLOBALS['sql_query']); diff --git a/libraries/classes/Controllers/Table/DeleteConfirmController.php b/libraries/classes/Controllers/Table/DeleteConfirmController.php index af115a5141..ca35a56450 100644 --- a/libraries/classes/Controllers/Table/DeleteConfirmController.php +++ b/libraries/classes/Controllers/Table/DeleteConfirmController.php @@ -7,6 +7,11 @@ namespace PhpMyAdmin\Controllers\Table; use PhpMyAdmin\Controllers\AbstractController; use PhpMyAdmin\DbTableExists; use PhpMyAdmin\Http\ServerRequest; +use PhpMyAdmin\Identifiers\DatabaseName; +use PhpMyAdmin\Identifiers\TableName; +use PhpMyAdmin\Message; +use PhpMyAdmin\ResponseRenderer; +use PhpMyAdmin\Template; use PhpMyAdmin\Url; use PhpMyAdmin\Util; use PhpMyAdmin\Utils\ForeignKey; @@ -16,6 +21,14 @@ use function is_array; final class DeleteConfirmController extends AbstractController { + public function __construct( + protected ResponseRenderer $response, + protected Template $template, + private readonly DbTableExists $dbTableExists, + ) { + parent::__construct($response, $template); + } + public function __invoke(ServerRequest $request): void { $GLOBALS['urlParams'] ??= null; @@ -36,7 +49,33 @@ final class DeleteConfirmController extends AbstractController $GLOBALS['errorUrl'] = Util::getScriptNameForOption($GLOBALS['cfg']['DefaultTabTable'], 'table'); $GLOBALS['errorUrl'] .= Url::getCommon($GLOBALS['urlParams'], '&'); - DbTableExists::check($GLOBALS['db'], $GLOBALS['table']); + $databaseName = DatabaseName::tryFrom($request->getParam('db')); + if ($databaseName === null || ! $this->dbTableExists->hasDatabase($databaseName)) { + if ($request->isAjax()) { + $this->response->setRequestStatus(false); + $this->response->addJSON('message', Message::error(__('No databases selected.'))); + + return; + } + + $this->redirect('/', ['reload' => true, 'message' => __('No databases selected.')]); + + return; + } + + $tableName = TableName::tryFrom($request->getParam('table')); + if ($tableName === null || ! $this->dbTableExists->hasTable($databaseName, $tableName)) { + if ($request->isAjax()) { + $this->response->setRequestStatus(false); + $this->response->addJSON('message', Message::error(__('No table selected.'))); + + return; + } + + $this->redirect('/', ['reload' => true, 'message' => __('No table selected.')]); + + return; + } $this->render('table/delete/confirm', [ 'db' => $GLOBALS['db'], diff --git a/libraries/classes/Controllers/Table/DropColumnConfirmationController.php b/libraries/classes/Controllers/Table/DropColumnConfirmationController.php index 34fcf9e888..29c1b84aeb 100644 --- a/libraries/classes/Controllers/Table/DropColumnConfirmationController.php +++ b/libraries/classes/Controllers/Table/DropColumnConfirmationController.php @@ -10,6 +10,9 @@ use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\Identifiers\DatabaseName; use PhpMyAdmin\Identifiers\InvalidIdentifier; use PhpMyAdmin\Identifiers\TableName; +use PhpMyAdmin\Message; +use PhpMyAdmin\ResponseRenderer; +use PhpMyAdmin\Template; use Webmozart\Assert\Assert; use Webmozart\Assert\InvalidArgumentException; @@ -17,6 +20,14 @@ use function __; final class DropColumnConfirmationController extends AbstractController { + public function __construct( + protected ResponseRenderer $response, + protected Template $template, + private readonly DbTableExists $dbTableExists, + ) { + parent::__construct($response, $template); + } + public function __invoke(ServerRequest $request): void { $fields = $request->getParsedBodyParam('selected_fld'); @@ -34,7 +45,31 @@ final class DropColumnConfirmationController extends AbstractController return; } - DbTableExists::check($db->getName(), $table->getName()); + if (! $this->dbTableExists->hasDatabase($db)) { + if ($request->isAjax()) { + $this->response->setRequestStatus(false); + $this->response->addJSON('message', Message::error(__('No databases selected.'))); + + return; + } + + $this->redirect('/', ['reload' => true, 'message' => __('No databases selected.')]); + + return; + } + + if (! $this->dbTableExists->hasTable($db, $table)) { + if ($request->isAjax()) { + $this->response->setRequestStatus(false); + $this->response->addJSON('message', Message::error(__('No table selected.'))); + + return; + } + + $this->redirect('/', ['reload' => true, 'message' => __('No table selected.')]); + + return; + } $this->render('table/structure/drop_confirm', [ 'db' => $db->getName(), diff --git a/libraries/classes/Controllers/Table/FindReplaceController.php b/libraries/classes/Controllers/Table/FindReplaceController.php index d67c61c586..531c5ac7f3 100644 --- a/libraries/classes/Controllers/Table/FindReplaceController.php +++ b/libraries/classes/Controllers/Table/FindReplaceController.php @@ -9,6 +9,9 @@ use PhpMyAdmin\DatabaseInterface; use PhpMyAdmin\DbTableExists; use PhpMyAdmin\Html\Generator; use PhpMyAdmin\Http\ServerRequest; +use PhpMyAdmin\Identifiers\DatabaseName; +use PhpMyAdmin\Identifiers\TableName; +use PhpMyAdmin\Message; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\Template; use PhpMyAdmin\Url; @@ -44,6 +47,7 @@ class FindReplaceController extends AbstractController ResponseRenderer $response, Template $template, private DatabaseInterface $dbi, + private readonly DbTableExists $dbTableExists, ) { parent::__construct($response, $template); @@ -61,7 +65,33 @@ class FindReplaceController extends AbstractController $GLOBALS['errorUrl'] = Util::getScriptNameForOption($GLOBALS['cfg']['DefaultTabTable'], 'table'); $GLOBALS['errorUrl'] .= Url::getCommon($GLOBALS['urlParams'], '&'); - DbTableExists::check($GLOBALS['db'], $GLOBALS['table']); + $databaseName = DatabaseName::tryFrom($request->getParam('db')); + if ($databaseName === null || ! $this->dbTableExists->hasDatabase($databaseName)) { + if ($request->isAjax()) { + $this->response->setRequestStatus(false); + $this->response->addJSON('message', Message::error(__('No databases selected.'))); + + return; + } + + $this->redirect('/', ['reload' => true, 'message' => __('No databases selected.')]); + + return; + } + + $tableName = TableName::tryFrom($request->getParam('table')); + if ($tableName === null || ! $this->dbTableExists->hasTable($databaseName, $tableName)) { + if ($request->isAjax()) { + $this->response->setRequestStatus(false); + $this->response->addJSON('message', Message::error(__('No table selected.'))); + + return; + } + + $this->redirect('/', ['reload' => true, 'message' => __('No table selected.')]); + + return; + } if (isset($_POST['find'])) { $this->findAction(); diff --git a/libraries/classes/Controllers/Table/GisVisualizationController.php b/libraries/classes/Controllers/Table/GisVisualizationController.php index 43d708ac29..413b58f10b 100644 --- a/libraries/classes/Controllers/Table/GisVisualizationController.php +++ b/libraries/classes/Controllers/Table/GisVisualizationController.php @@ -7,10 +7,12 @@ namespace PhpMyAdmin\Controllers\Table; use PhpMyAdmin\Controllers\AbstractController; use PhpMyAdmin\Core; use PhpMyAdmin\DatabaseInterface; +use PhpMyAdmin\DbTableExists; use PhpMyAdmin\FieldMetadata; use PhpMyAdmin\Gis\GisVisualization; use PhpMyAdmin\Html\Generator; use PhpMyAdmin\Http\ServerRequest; +use PhpMyAdmin\Identifiers\DatabaseName; use PhpMyAdmin\Message; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\Template; @@ -31,6 +33,7 @@ final class GisVisualizationController extends AbstractController ResponseRenderer $response, Template $template, private DatabaseInterface $dbi, + private readonly DbTableExists $dbTableExists, ) { parent::__construct($response, $template); } @@ -42,7 +45,17 @@ final class GisVisualizationController extends AbstractController $GLOBALS['errorUrl'] = Util::getScriptNameForOption($GLOBALS['cfg']['DefaultTabDatabase'], 'database'); $GLOBALS['errorUrl'] .= Url::getCommon(['db' => $GLOBALS['db']], '&'); - if (! $this->hasDatabase()) { + $databaseName = DatabaseName::tryFrom($request->getParam('db')); + if ($databaseName === null || ! $this->dbTableExists->hasDatabase($databaseName)) { + if ($request->isAjax()) { + $this->response->setRequestStatus(false); + $this->response->addJSON('message', Message::error(__('No databases selected.'))); + + return; + } + + $this->redirect('/', ['reload' => true, 'message' => __('No databases selected.')]); + return; } diff --git a/libraries/classes/Controllers/Table/ImportController.php b/libraries/classes/Controllers/Table/ImportController.php index 9d5da02b70..9890e429a3 100644 --- a/libraries/classes/Controllers/Table/ImportController.php +++ b/libraries/classes/Controllers/Table/ImportController.php @@ -11,6 +11,8 @@ use PhpMyAdmin\DatabaseInterface; use PhpMyAdmin\DbTableExists; use PhpMyAdmin\Encoding; use PhpMyAdmin\Http\ServerRequest; +use PhpMyAdmin\Identifiers\DatabaseName; +use PhpMyAdmin\Identifiers\TableName; use PhpMyAdmin\Import\Ajax; use PhpMyAdmin\Import\Import; use PhpMyAdmin\Message; @@ -32,6 +34,7 @@ final class ImportController extends AbstractController Template $template, private DatabaseInterface $dbi, private PageSettings $pageSettings, + private readonly DbTableExists $dbTableExists, ) { parent::__construct($response, $template); } @@ -54,7 +57,33 @@ final class ImportController extends AbstractController $GLOBALS['errorUrl'] = Util::getScriptNameForOption($GLOBALS['cfg']['DefaultTabTable'], 'table'); $GLOBALS['errorUrl'] .= Url::getCommon($GLOBALS['urlParams'], '&'); - DbTableExists::check($GLOBALS['db'], $GLOBALS['table']); + $databaseName = DatabaseName::tryFrom($request->getParam('db')); + if ($databaseName === null || ! $this->dbTableExists->hasDatabase($databaseName)) { + if ($request->isAjax()) { + $this->response->setRequestStatus(false); + $this->response->addJSON('message', Message::error(__('No databases selected.'))); + + return; + } + + $this->redirect('/', ['reload' => true, 'message' => __('No databases selected.')]); + + return; + } + + $tableName = TableName::tryFrom($request->getParam('table')); + if ($tableName === null || ! $this->dbTableExists->hasTable($databaseName, $tableName)) { + if ($request->isAjax()) { + $this->response->setRequestStatus(false); + $this->response->addJSON('message', Message::error(__('No table selected.'))); + + return; + } + + $this->redirect('/', ['reload' => true, 'message' => __('No table selected.')]); + + return; + } $GLOBALS['urlParams']['goto'] = Url::getFromRoute('/table/import'); $GLOBALS['urlParams']['back'] = Url::getFromRoute('/table/import'); diff --git a/libraries/classes/Controllers/Table/IndexRenameController.php b/libraries/classes/Controllers/Table/IndexRenameController.php index ccc966d173..ca7613e2ed 100644 --- a/libraries/classes/Controllers/Table/IndexRenameController.php +++ b/libraries/classes/Controllers/Table/IndexRenameController.php @@ -8,13 +8,17 @@ use PhpMyAdmin\Controllers\AbstractController; use PhpMyAdmin\DatabaseInterface; use PhpMyAdmin\DbTableExists; use PhpMyAdmin\Http\ServerRequest; +use PhpMyAdmin\Identifiers\DatabaseName; +use PhpMyAdmin\Identifiers\TableName; use PhpMyAdmin\Index; +use PhpMyAdmin\Message; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\Table\Indexes; use PhpMyAdmin\Template; use PhpMyAdmin\Url; use PhpMyAdmin\Util; +use function __; use function is_array; final class IndexRenameController extends AbstractController @@ -24,6 +28,7 @@ final class IndexRenameController extends AbstractController Template $template, private DatabaseInterface $dbi, private Indexes $indexes, + private readonly DbTableExists $dbTableExists, ) { parent::__construct($response, $template); } @@ -40,7 +45,33 @@ final class IndexRenameController extends AbstractController $GLOBALS['errorUrl'] = Util::getScriptNameForOption($GLOBALS['cfg']['DefaultTabTable'], 'table'); $GLOBALS['errorUrl'] .= Url::getCommon($GLOBALS['urlParams'], '&'); - DbTableExists::check($GLOBALS['db'], $GLOBALS['table']); + $databaseName = DatabaseName::tryFrom($request->getParam('db')); + if ($databaseName === null || ! $this->dbTableExists->hasDatabase($databaseName)) { + if ($request->isAjax()) { + $this->response->setRequestStatus(false); + $this->response->addJSON('message', Message::error(__('No databases selected.'))); + + return; + } + + $this->redirect('/', ['reload' => true, 'message' => __('No databases selected.')]); + + return; + } + + $tableName = TableName::tryFrom($request->getParam('table')); + if ($tableName === null || ! $this->dbTableExists->hasTable($databaseName, $tableName)) { + if ($request->isAjax()) { + $this->response->setRequestStatus(false); + $this->response->addJSON('message', Message::error(__('No table selected.'))); + + return; + } + + $this->redirect('/', ['reload' => true, 'message' => __('No table selected.')]); + + return; + } } if (isset($_POST['index'])) { diff --git a/libraries/classes/Controllers/Table/IndexesController.php b/libraries/classes/Controllers/Table/IndexesController.php index 511fa9b09a..9942631c05 100644 --- a/libraries/classes/Controllers/Table/IndexesController.php +++ b/libraries/classes/Controllers/Table/IndexesController.php @@ -8,13 +8,17 @@ use PhpMyAdmin\Controllers\AbstractController; use PhpMyAdmin\DatabaseInterface; use PhpMyAdmin\DbTableExists; use PhpMyAdmin\Http\ServerRequest; +use PhpMyAdmin\Identifiers\DatabaseName; +use PhpMyAdmin\Identifiers\TableName; use PhpMyAdmin\Index; +use PhpMyAdmin\Message; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\Table\Indexes; use PhpMyAdmin\Template; use PhpMyAdmin\Url; use PhpMyAdmin\Util; +use function __; use function count; use function is_array; use function is_numeric; @@ -31,6 +35,7 @@ class IndexesController extends AbstractController Template $template, private DatabaseInterface $dbi, private Indexes $indexes, + private readonly DbTableExists $dbTableExists, ) { parent::__construct($response, $template); } @@ -47,7 +52,33 @@ class IndexesController extends AbstractController $GLOBALS['errorUrl'] = Util::getScriptNameForOption($GLOBALS['cfg']['DefaultTabTable'], 'table'); $GLOBALS['errorUrl'] .= Url::getCommon($GLOBALS['urlParams'], '&'); - DbTableExists::check($GLOBALS['db'], $GLOBALS['table']); + $databaseName = DatabaseName::tryFrom($request->getParam('db')); + if ($databaseName === null || ! $this->dbTableExists->hasDatabase($databaseName)) { + if ($request->isAjax()) { + $this->response->setRequestStatus(false); + $this->response->addJSON('message', Message::error(__('No databases selected.'))); + + return; + } + + $this->redirect('/', ['reload' => true, 'message' => __('No databases selected.')]); + + return; + } + + $tableName = TableName::tryFrom($request->getParam('table')); + if ($tableName === null || ! $this->dbTableExists->hasTable($databaseName, $tableName)) { + if ($request->isAjax()) { + $this->response->setRequestStatus(false); + $this->response->addJSON('message', Message::error(__('No table selected.'))); + + return; + } + + $this->redirect('/', ['reload' => true, 'message' => __('No table selected.')]); + + return; + } } if (isset($_POST['index'])) { diff --git a/libraries/classes/Controllers/Table/OperationsController.php b/libraries/classes/Controllers/Table/OperationsController.php index 8e160c0bd1..26f26bb5b2 100644 --- a/libraries/classes/Controllers/Table/OperationsController.php +++ b/libraries/classes/Controllers/Table/OperationsController.php @@ -12,6 +12,8 @@ use PhpMyAdmin\DatabaseInterface; use PhpMyAdmin\DbTableExists; use PhpMyAdmin\Html\Generator; use PhpMyAdmin\Http\ServerRequest; +use PhpMyAdmin\Identifiers\DatabaseName; +use PhpMyAdmin\Identifiers\TableName; use PhpMyAdmin\Index; use PhpMyAdmin\Message; use PhpMyAdmin\Operations; @@ -45,6 +47,7 @@ class OperationsController extends AbstractController private CheckUserPrivileges $checkUserPrivileges, private Relation $relation, private DatabaseInterface $dbi, + private readonly DbTableExists $dbTableExists, ) { parent::__construct($response, $template); } @@ -80,7 +83,33 @@ class OperationsController extends AbstractController $GLOBALS['errorUrl'] = Util::getScriptNameForOption($GLOBALS['cfg']['DefaultTabTable'], 'table'); $GLOBALS['errorUrl'] .= Url::getCommon($GLOBALS['urlParams'], '&'); - DbTableExists::check($GLOBALS['db'], $GLOBALS['table']); + $databaseName = DatabaseName::tryFrom($request->getParam('db')); + if ($databaseName === null || ! $this->dbTableExists->hasDatabase($databaseName)) { + if ($request->isAjax()) { + $this->response->setRequestStatus(false); + $this->response->addJSON('message', Message::error(__('No databases selected.'))); + + return; + } + + $this->redirect('/', ['reload' => true, 'message' => __('No databases selected.')]); + + return; + } + + $tableName = TableName::tryFrom($request->getParam('table')); + if ($tableName === null || ! $this->dbTableExists->hasTable($databaseName, $tableName)) { + if ($request->isAjax()) { + $this->response->setRequestStatus(false); + $this->response->addJSON('message', Message::error(__('No table selected.'))); + + return; + } + + $this->redirect('/', ['reload' => true, 'message' => __('No table selected.')]); + + return; + } $GLOBALS['urlParams']['goto'] = $GLOBALS['urlParams']['back'] = Url::getFromRoute('/table/operations'); diff --git a/libraries/classes/Controllers/Table/SearchController.php b/libraries/classes/Controllers/Table/SearchController.php index 4f394bf576..3b1efdfbde 100644 --- a/libraries/classes/Controllers/Table/SearchController.php +++ b/libraries/classes/Controllers/Table/SearchController.php @@ -11,6 +11,9 @@ use PhpMyAdmin\Core; use PhpMyAdmin\DatabaseInterface; use PhpMyAdmin\DbTableExists; use PhpMyAdmin\Http\ServerRequest; +use PhpMyAdmin\Identifiers\DatabaseName; +use PhpMyAdmin\Identifiers\TableName; +use PhpMyAdmin\Message; use PhpMyAdmin\Operations; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\Sql; @@ -21,6 +24,7 @@ use PhpMyAdmin\Url; use PhpMyAdmin\Util; use PhpMyAdmin\Utils\Gis; +use function __; use function in_array; use function intval; use function is_array; @@ -88,6 +92,7 @@ class SearchController extends AbstractController private Search $search, private Relation $relation, private DatabaseInterface $dbi, + private readonly DbTableExists $dbTableExists, ) { parent::__construct($response, $template); @@ -158,7 +163,33 @@ class SearchController extends AbstractController $GLOBALS['errorUrl'] = Util::getScriptNameForOption($GLOBALS['cfg']['DefaultTabTable'], 'table'); $GLOBALS['errorUrl'] .= Url::getCommon($GLOBALS['urlParams'], '&'); - DbTableExists::check($GLOBALS['db'], $GLOBALS['table']); + $databaseName = DatabaseName::tryFrom($request->getParam('db')); + if ($databaseName === null || ! $this->dbTableExists->hasDatabase($databaseName)) { + if ($request->isAjax()) { + $this->response->setRequestStatus(false); + $this->response->addJSON('message', Message::error(__('No databases selected.'))); + + return; + } + + $this->redirect('/', ['reload' => true, 'message' => __('No databases selected.')]); + + return; + } + + $tableName = TableName::tryFrom($request->getParam('table')); + if ($tableName === null || ! $this->dbTableExists->hasTable($databaseName, $tableName)) { + if ($request->isAjax()) { + $this->response->setRequestStatus(false); + $this->response->addJSON('message', Message::error(__('No table selected.'))); + + return; + } + + $this->redirect('/', ['reload' => true, 'message' => __('No table selected.')]); + + return; + } $this->addScriptFiles([ 'makegrid.js', diff --git a/libraries/classes/Controllers/Table/SqlController.php b/libraries/classes/Controllers/Table/SqlController.php index 51357b1072..073ae976a8 100644 --- a/libraries/classes/Controllers/Table/SqlController.php +++ b/libraries/classes/Controllers/Table/SqlController.php @@ -8,12 +8,16 @@ use PhpMyAdmin\Config\PageSettings; use PhpMyAdmin\Controllers\AbstractController; use PhpMyAdmin\DbTableExists; use PhpMyAdmin\Http\ServerRequest; +use PhpMyAdmin\Identifiers\DatabaseName; +use PhpMyAdmin\Identifiers\TableName; +use PhpMyAdmin\Message; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\SqlQueryForm; use PhpMyAdmin\Template; use PhpMyAdmin\Url; use PhpMyAdmin\Util; +use function __; use function htmlspecialchars; /** @@ -26,6 +30,7 @@ final class SqlController extends AbstractController Template $template, private SqlQueryForm $sqlQueryForm, private PageSettings $pageSettings, + private readonly DbTableExists $dbTableExists, ) { parent::__construct($response, $template); } @@ -48,7 +53,33 @@ final class SqlController extends AbstractController $GLOBALS['errorUrl'] = Util::getScriptNameForOption($GLOBALS['cfg']['DefaultTabTable'], 'table'); $GLOBALS['errorUrl'] .= Url::getCommon($urlParams, '&'); - DbTableExists::check($GLOBALS['db'], $GLOBALS['table']); + $databaseName = DatabaseName::tryFrom($request->getParam('db')); + if ($databaseName === null || ! $this->dbTableExists->hasDatabase($databaseName)) { + if ($request->isAjax()) { + $this->response->setRequestStatus(false); + $this->response->addJSON('message', Message::error(__('No databases selected.'))); + + return; + } + + $this->redirect('/', ['reload' => true, 'message' => __('No databases selected.')]); + + return; + } + + $tableName = TableName::tryFrom($request->getParam('table')); + if ($tableName === null || ! $this->dbTableExists->hasTable($databaseName, $tableName)) { + if ($request->isAjax()) { + $this->response->setRequestStatus(false); + $this->response->addJSON('message', Message::error(__('No table selected.'))); + + return; + } + + $this->redirect('/', ['reload' => true, 'message' => __('No table selected.')]); + + return; + } /** * After a syntax error, we return to this script diff --git a/libraries/classes/Controllers/Table/Structure/PrimaryController.php b/libraries/classes/Controllers/Table/Structure/PrimaryController.php index 6d88a53cdb..b28a5045c4 100644 --- a/libraries/classes/Controllers/Table/Structure/PrimaryController.php +++ b/libraries/classes/Controllers/Table/Structure/PrimaryController.php @@ -9,6 +9,8 @@ use PhpMyAdmin\Controllers\Table\StructureController; use PhpMyAdmin\DatabaseInterface; use PhpMyAdmin\DbTableExists; use PhpMyAdmin\Http\ServerRequest; +use PhpMyAdmin\Identifiers\DatabaseName; +use PhpMyAdmin\Identifiers\TableName; use PhpMyAdmin\Message; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\Template; @@ -26,6 +28,7 @@ final class PrimaryController extends AbstractController Template $template, private DatabaseInterface $dbi, private StructureController $structureController, + private readonly DbTableExists $dbTableExists, ) { parent::__construct($response, $template); } @@ -59,7 +62,33 @@ final class PrimaryController extends AbstractController $GLOBALS['errorUrl'] = Util::getScriptNameForOption($GLOBALS['cfg']['DefaultTabTable'], 'table'); $GLOBALS['errorUrl'] .= Url::getCommon($GLOBALS['urlParams'], '&'); - DbTableExists::check($GLOBALS['db'], $GLOBALS['table']); + $databaseName = DatabaseName::tryFrom($request->getParam('db')); + if ($databaseName === null || ! $this->dbTableExists->hasDatabase($databaseName)) { + if ($request->isAjax()) { + $this->response->setRequestStatus(false); + $this->response->addJSON('message', Message::error(__('No databases selected.'))); + + return; + } + + $this->redirect('/', ['reload' => true, 'message' => __('No databases selected.')]); + + return; + } + + $tableName = TableName::tryFrom($request->getParam('table')); + if ($tableName === null || ! $this->dbTableExists->hasTable($databaseName, $tableName)) { + if ($request->isAjax()) { + $this->response->setRequestStatus(false); + $this->response->addJSON('message', Message::error(__('No table selected.'))); + + return; + } + + $this->redirect('/', ['reload' => true, 'message' => __('No table selected.')]); + + return; + } $this->render('table/structure/primary', [ 'db' => $GLOBALS['db'], diff --git a/libraries/classes/Controllers/Table/StructureController.php b/libraries/classes/Controllers/Table/StructureController.php index 2e3b129697..a881cb13c4 100644 --- a/libraries/classes/Controllers/Table/StructureController.php +++ b/libraries/classes/Controllers/Table/StructureController.php @@ -16,7 +16,10 @@ use PhpMyAdmin\DbTableExists; use PhpMyAdmin\Engines\Innodb; use PhpMyAdmin\Html\Generator; use PhpMyAdmin\Http\ServerRequest; +use PhpMyAdmin\Identifiers\DatabaseName; +use PhpMyAdmin\Identifiers\TableName; use PhpMyAdmin\Index; +use PhpMyAdmin\Message; use PhpMyAdmin\Partitioning\Partition; use PhpMyAdmin\Query\Utilities; use PhpMyAdmin\ResponseRenderer; @@ -51,6 +54,7 @@ class StructureController extends AbstractController private Transformations $transformations, private DatabaseInterface $dbi, private PageSettings $pageSettings, + private readonly DbTableExists $dbTableExists, ) { parent::__construct($response, $template); @@ -103,7 +107,33 @@ class StructureController extends AbstractController $GLOBALS['errorUrl'] = Util::getScriptNameForOption($GLOBALS['cfg']['DefaultTabTable'], 'table'); $GLOBALS['errorUrl'] .= Url::getCommon($urlParams, '&'); - DbTableExists::check($GLOBALS['db'], $GLOBALS['table']); + $databaseName = DatabaseName::tryFrom($request->getParam('db')); + if ($databaseName === null || ! $this->dbTableExists->hasDatabase($databaseName)) { + if ($request->isAjax()) { + $this->response->setRequestStatus(false); + $this->response->addJSON('message', Message::error(__('No databases selected.'))); + + return; + } + + $this->redirect('/', ['reload' => true, 'message' => __('No databases selected.')]); + + return; + } + + $tableName = TableName::tryFrom($request->getParam('table')); + if ($tableName === null || ! $this->dbTableExists->hasTable($databaseName, $tableName)) { + if ($request->isAjax()) { + $this->response->setRequestStatus(false); + $this->response->addJSON('message', Message::error(__('No table selected.'))); + + return; + } + + $this->redirect('/', ['reload' => true, 'message' => __('No table selected.')]); + + return; + } $primary = Index::getPrimary($this->dbi, $GLOBALS['table'], $GLOBALS['db']); $columnsWithIndex = $this->dbi diff --git a/libraries/classes/Controllers/Table/TrackingController.php b/libraries/classes/Controllers/Table/TrackingController.php index fd61c27018..01aa239ce0 100644 --- a/libraries/classes/Controllers/Table/TrackingController.php +++ b/libraries/classes/Controllers/Table/TrackingController.php @@ -9,6 +9,7 @@ use PhpMyAdmin\Controllers\AbstractController; use PhpMyAdmin\Core; use PhpMyAdmin\DbTableExists; use PhpMyAdmin\Http\ServerRequest; +use PhpMyAdmin\Identifiers\DatabaseName; use PhpMyAdmin\Message; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\Template; @@ -23,7 +24,6 @@ use Webmozart\Assert\Assert; use function __; use function array_map; -use function define; use function explode; use function htmlspecialchars; use function in_array; @@ -39,6 +39,7 @@ final class TrackingController extends AbstractController Template $template, private Tracking $tracking, private TrackingChecker $trackingChecker, + private readonly DbTableExists $dbTableExists, ) { parent::__construct($response, $template); } @@ -51,15 +52,25 @@ final class TrackingController extends AbstractController $this->addScriptFiles(['vendor/jquery/jquery.tablesorter.js', 'table/tracking.js']); - define('TABLE_MAY_BE_ABSENT', true); - $this->checkParameters(['db', 'table']); $GLOBALS['urlParams'] = ['db' => $GLOBALS['db'], 'table' => $GLOBALS['table']]; $GLOBALS['errorUrl'] = Util::getScriptNameForOption($GLOBALS['cfg']['DefaultTabTable'], 'table'); $GLOBALS['errorUrl'] .= Url::getCommon($GLOBALS['urlParams'], '&'); - DbTableExists::check($GLOBALS['db'], $GLOBALS['table']); + $databaseName = DatabaseName::tryFrom($request->getParam('db')); + if ($databaseName === null || ! $this->dbTableExists->hasDatabase($databaseName)) { + if ($request->isAjax()) { + $this->response->setRequestStatus(false); + $this->response->addJSON('message', Message::error(__('No databases selected.'))); + + return; + } + + $this->redirect('/', ['reload' => true, 'message' => __('No databases selected.')]); + + return; + } $activeMessage = ''; $toggleActivation = $request->getParsedBodyParam('toggle_activation'); diff --git a/libraries/classes/Controllers/Table/ZoomSearchController.php b/libraries/classes/Controllers/Table/ZoomSearchController.php index 94d328c9d2..c42c0ecbc6 100644 --- a/libraries/classes/Controllers/Table/ZoomSearchController.php +++ b/libraries/classes/Controllers/Table/ZoomSearchController.php @@ -10,6 +10,9 @@ use PhpMyAdmin\Core; use PhpMyAdmin\DatabaseInterface; use PhpMyAdmin\DbTableExists; use PhpMyAdmin\Http\ServerRequest; +use PhpMyAdmin\Identifiers\DatabaseName; +use PhpMyAdmin\Identifiers\TableName; +use PhpMyAdmin\Message; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\Table\Search; use PhpMyAdmin\Template; @@ -17,6 +20,7 @@ use PhpMyAdmin\Url; use PhpMyAdmin\Util; use PhpMyAdmin\Utils\Gis; +use function __; use function array_search; use function array_values; use function count; @@ -69,6 +73,7 @@ class ZoomSearchController extends AbstractController private Search $search, private Relation $relation, private DatabaseInterface $dbi, + private readonly DbTableExists $dbTableExists, ) { parent::__construct($response, $template); @@ -86,7 +91,33 @@ class ZoomSearchController extends AbstractController $GLOBALS['errorUrl'] = Util::getScriptNameForOption($GLOBALS['cfg']['DefaultTabTable'], 'table'); $GLOBALS['errorUrl'] .= Url::getCommon($GLOBALS['urlParams'], '&'); - DbTableExists::check($GLOBALS['db'], $GLOBALS['table']); + $databaseName = DatabaseName::tryFrom($request->getParam('db')); + if ($databaseName === null || ! $this->dbTableExists->hasDatabase($databaseName)) { + if ($request->isAjax()) { + $this->response->setRequestStatus(false); + $this->response->addJSON('message', Message::error(__('No databases selected.'))); + + return; + } + + $this->redirect('/', ['reload' => true, 'message' => __('No databases selected.')]); + + return; + } + + $tableName = TableName::tryFrom($request->getParam('table')); + if ($tableName === null || ! $this->dbTableExists->hasTable($databaseName, $tableName)) { + if ($request->isAjax()) { + $this->response->setRequestStatus(false); + $this->response->addJSON('message', Message::error(__('No table selected.'))); + + return; + } + + $this->redirect('/', ['reload' => true, 'message' => __('No table selected.')]); + + return; + } $this->addScriptFiles([ 'makegrid.js', diff --git a/libraries/classes/Controllers/Transformation/WrapperController.php b/libraries/classes/Controllers/Transformation/WrapperController.php index 9f6d7db825..f5927e4064 100644 --- a/libraries/classes/Controllers/Transformation/WrapperController.php +++ b/libraries/classes/Controllers/Transformation/WrapperController.php @@ -8,7 +8,6 @@ use PhpMyAdmin\ConfigStorage\Relation; use PhpMyAdmin\Controllers\AbstractController; use PhpMyAdmin\Core; use PhpMyAdmin\DatabaseInterface; -use PhpMyAdmin\DbTableExists; use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\Identifiers\DatabaseName; use PhpMyAdmin\Identifiers\InvalidIdentifier; @@ -58,8 +57,18 @@ class WrapperController extends AbstractController return; } - DbTableExists::check($db->getName(), $table->getName(), true); - $this->dbi->selectDb($db); + if (! $this->dbi->selectDb($db)) { + return; + } + + $hasTable = (bool) $this->dbi->getCache()->getCachedTableContent([$db->getName(), $table->getName()]); + if (! $hasTable) { + $result = $this->dbi->tryQuery('SHOW TABLES LIKE ' . $this->dbi->quoteString($table->getName()) . ';'); + $hasTable = $result !== false && $result->numRows() > 0; + if (! $hasTable) { + return; + } + } $query = $this->getQuery($table, $request->getParam('where_clause'), $request->getParam('where_clause_sign')); if ($query === null) { diff --git a/libraries/classes/Controllers/Triggers/IndexController.php b/libraries/classes/Controllers/Triggers/IndexController.php index 8588555270..5cc928099b 100644 --- a/libraries/classes/Controllers/Triggers/IndexController.php +++ b/libraries/classes/Controllers/Triggers/IndexController.php @@ -8,6 +8,8 @@ use PhpMyAdmin\Controllers\AbstractController; use PhpMyAdmin\DatabaseInterface; use PhpMyAdmin\DbTableExists; use PhpMyAdmin\Http\ServerRequest; +use PhpMyAdmin\Identifiers\DatabaseName; +use PhpMyAdmin\Identifiers\TableName; use PhpMyAdmin\Identifiers\TriggerName; use PhpMyAdmin\Message; use PhpMyAdmin\ResponseRenderer; @@ -36,6 +38,7 @@ final class IndexController extends AbstractController Template $template, private DatabaseInterface $dbi, private Triggers $triggers, + private readonly DbTableExists $dbTableExists, ) { parent::__construct($response, $template); } @@ -59,7 +62,19 @@ final class IndexController extends AbstractController $GLOBALS['errorUrl'] = Util::getScriptNameForOption($GLOBALS['cfg']['DefaultTabTable'], 'table'); $GLOBALS['errorUrl'] .= Url::getCommon($GLOBALS['urlParams'], '&'); - DbTableExists::check($GLOBALS['db'], $GLOBALS['table']); + $databaseName = DatabaseName::tryFrom($request->getParam('db')); + if ($databaseName === null || ! $this->dbTableExists->hasDatabase($databaseName)) { + $this->redirect('/', ['reload' => true, 'message' => __('No databases selected.')]); + + return; + } + + $tableName = TableName::tryFrom($request->getParam('table')); + if ($tableName === null || ! $this->dbTableExists->hasTable($databaseName, $tableName)) { + $this->redirect('/', ['reload' => true, 'message' => __('No table selected.')]); + + return; + } } else { $GLOBALS['table'] = ''; @@ -68,7 +83,10 @@ final class IndexController extends AbstractController $GLOBALS['errorUrl'] = Util::getScriptNameForOption($GLOBALS['cfg']['DefaultTabDatabase'], 'database'); $GLOBALS['errorUrl'] .= Url::getCommon(['db' => $GLOBALS['db']], '&'); - if (! $this->hasDatabase()) { + $databaseName = DatabaseName::tryFrom($request->getParam('db')); + if ($databaseName === null || ! $this->dbTableExists->hasDatabase($databaseName)) { + $this->redirect('/', ['reload' => true, 'message' => __('No databases selected.')]); + return; } } diff --git a/libraries/classes/Controllers/View/CreateController.php b/libraries/classes/Controllers/View/CreateController.php index 0579a51d7b..9303e7e70c 100644 --- a/libraries/classes/Controllers/View/CreateController.php +++ b/libraries/classes/Controllers/View/CreateController.php @@ -8,8 +8,10 @@ use PhpMyAdmin\Controllers\AbstractController; use PhpMyAdmin\Controllers\Table\StructureController; use PhpMyAdmin\Core; use PhpMyAdmin\DatabaseInterface; +use PhpMyAdmin\DbTableExists; use PhpMyAdmin\Html\Generator; use PhpMyAdmin\Http\ServerRequest; +use PhpMyAdmin\Identifiers\DatabaseName; use PhpMyAdmin\Message; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\SqlParser\Parser; @@ -40,8 +42,12 @@ class CreateController extends AbstractController private const VIEW_WITH_OPTIONS = ['CASCADED', 'LOCAL']; - public function __construct(ResponseRenderer $response, Template $template, private DatabaseInterface $dbi) - { + public function __construct( + ResponseRenderer $response, + Template $template, + private DatabaseInterface $dbi, + private readonly DbTableExists $dbTableExists, + ) { parent::__construct($response, $template); } @@ -55,7 +61,17 @@ class CreateController extends AbstractController $GLOBALS['errorUrl'] = Util::getScriptNameForOption($GLOBALS['cfg']['DefaultTabDatabase'], 'database'); $GLOBALS['errorUrl'] .= Url::getCommon(['db' => $GLOBALS['db']], '&'); - if (! $this->hasDatabase()) { + $databaseName = DatabaseName::tryFrom($request->getParam('db')); + if ($databaseName === null || ! $this->dbTableExists->hasDatabase($databaseName)) { + if ($request->isAjax()) { + $this->response->setRequestStatus(false); + $this->response->addJSON('message', Message::error(__('No databases selected.'))); + + return; + } + + $this->redirect('/', ['reload' => true, 'message' => __('No databases selected.')]); + return; } diff --git a/libraries/classes/Controllers/View/OperationsController.php b/libraries/classes/Controllers/View/OperationsController.php index cadcdd1268..fcb5c40b18 100644 --- a/libraries/classes/Controllers/View/OperationsController.php +++ b/libraries/classes/Controllers/View/OperationsController.php @@ -9,6 +9,8 @@ use PhpMyAdmin\DatabaseInterface; use PhpMyAdmin\DbTableExists; use PhpMyAdmin\Html\Generator; use PhpMyAdmin\Http\ServerRequest; +use PhpMyAdmin\Identifiers\DatabaseName; +use PhpMyAdmin\Identifiers\TableName; use PhpMyAdmin\Message; use PhpMyAdmin\Operations; use PhpMyAdmin\ResponseRenderer; @@ -29,6 +31,7 @@ class OperationsController extends AbstractController Template $template, private Operations $operations, private DatabaseInterface $dbi, + private readonly DbTableExists $dbTableExists, ) { parent::__construct($response, $template); } @@ -49,7 +52,33 @@ class OperationsController extends AbstractController $GLOBALS['errorUrl'] = Util::getScriptNameForOption($GLOBALS['cfg']['DefaultTabTable'], 'table'); $GLOBALS['errorUrl'] .= Url::getCommon($GLOBALS['urlParams'], '&'); - DbTableExists::check($GLOBALS['db'], $GLOBALS['table']); + $databaseName = DatabaseName::tryFrom($request->getParam('db')); + if ($databaseName === null || ! $this->dbTableExists->hasDatabase($databaseName)) { + if ($request->isAjax()) { + $this->response->setRequestStatus(false); + $this->response->addJSON('message', Message::error(__('No databases selected.'))); + + return; + } + + $this->redirect('/', ['reload' => true, 'message' => __('No databases selected.')]); + + return; + } + + $tableName = TableName::tryFrom($request->getParam('table')); + if ($tableName === null || ! $this->dbTableExists->hasTable($databaseName, $tableName)) { + if ($request->isAjax()) { + $this->response->setRequestStatus(false); + $this->response->addJSON('message', Message::error(__('No table selected.'))); + + return; + } + + $this->redirect('/', ['reload' => true, 'message' => __('No table selected.')]); + + return; + } $GLOBALS['urlParams']['goto'] = $GLOBALS['urlParams']['back'] = Url::getFromRoute('/view/operations'); diff --git a/libraries/classes/DbTableExists.php b/libraries/classes/DbTableExists.php index 1aa9ff79cf..22fa5fde46 100644 --- a/libraries/classes/DbTableExists.php +++ b/libraries/classes/DbTableExists.php @@ -4,112 +4,88 @@ declare(strict_types=1); namespace PhpMyAdmin; -use PhpMyAdmin\Controllers\Database\SqlController; +use PhpMyAdmin\Identifiers\DatabaseName; +use PhpMyAdmin\Identifiers\TableName; -use function __; -use function defined; +use function in_array; +use function sprintf; +use function str_starts_with; final class DbTableExists { + /** @psalm-var list */ + private array $databases = []; + + /** @psalm-var list */ + private array $tables = []; + + public function __construct(private readonly DatabaseInterface $dbi) + { + } + + public function hasDatabase(DatabaseName $databaseName): bool + { + if (in_array($databaseName->getName(), $this->databases, true)) { + return true; + } + + if ($this->dbi->selectDb($databaseName) || $this->hasCommandsOutOfSyncError()) { + $this->databases[] = $databaseName->getName(); + + return true; + } + + return false; + } + + public function hasTable(DatabaseName $database, TableName $table): bool + { + if (in_array($database->getName() . '.' . $table->getName(), $this->tables, true)) { + return true; + } + + if ( + $this->hasCachedTableContent($database, $table) + || $this->isPermanentTable($table) + || $this->isTemporaryTable($table) + ) { + $this->tables[] = $database->getName() . '.' . $table->getName(); + + return true; + } + + return false; + } + /** - * Ensure the database and the table exist (else move to the "parent" script) and display headers. + * This "Commands out of sync" 2014 error may happen, for example after calling a MySQL procedure; + * at this point we can't select the db, but it's not necessarily wrong. + * + * @see https://dev.mysql.com/doc/mysql-errors/8.0/en/client-error-reference.html#error_cr_commands_out_of_sync */ - public static function check(string $db, string $table, bool $isTransformationWrapper = false): void + private function hasCommandsOutOfSyncError(): bool { - self::checkDatabase($db, $isTransformationWrapper); - self::checkTable($db, $table, $isTransformationWrapper); + return str_starts_with($this->dbi->getError(), '#2014 '); } - private static function checkDatabase(string $db, bool $isTransformationWrapper): void + private function hasCachedTableContent(DatabaseName $database, TableName $table): bool { - $GLOBALS['message'] ??= null; - $GLOBALS['show_as_php'] ??= null; - - if (! empty($GLOBALS['is_db'])) { - return; - } - - $GLOBALS['is_db'] = false; - if ($db !== '') { - $GLOBALS['is_db'] = @$GLOBALS['dbi']->selectDb($db); - } - - if ($GLOBALS['is_db'] || $isTransformationWrapper) { - return; - } - - $response = ResponseRenderer::getInstance(); - if ($response->isAjax()) { - $response->setRequestStatus(false); - $response->addJSON( - 'message', - Message::error(__('No databases selected.')), - ); - - $response->callExit(); - } - - $urlParams = ['reload' => 1]; - - if (isset($GLOBALS['message'])) { - $urlParams['message'] = $GLOBALS['message']; - } - - if (! empty($GLOBALS['sql_query'])) { - $urlParams['sql_query'] = $GLOBALS['sql_query']; - } - - if (isset($GLOBALS['show_as_php'])) { - $urlParams['show_as_php'] = $GLOBALS['show_as_php']; - } - - Core::sendHeaderLocation('./index.php?route=/' . Url::getCommonRaw($urlParams, '&')); - - $response->callExit(); + return (bool) $this->dbi->getCache()->getCachedTableContent([$database->getName(), $table->getName()]); } - private static function checkTable(string $db, string $table, bool $isTransformationWrapper): void + private function isPermanentTable(TableName $table): bool { - if (! empty($GLOBALS['is_table']) || defined('PMA_SUBMIT_MULT') || defined('TABLE_MAY_BE_ABSENT')) { - return; - } + $result = $this->dbi->tryQuery(sprintf('SHOW TABLES LIKE %s;', $this->dbi->quoteString($table->getName()))); - $GLOBALS['is_table'] = false; - if ($table !== '') { - $GLOBALS['is_table'] = $GLOBALS['dbi']->getCache()->getCachedTableContent([$db, $table], false); - if ($GLOBALS['is_table']) { - return; - } + return $result !== false && $result->numRows() > 0; + } - $result = $GLOBALS['dbi']->tryQuery('SHOW TABLES LIKE \'' . $GLOBALS['dbi']->escapeString($table) . '\';'); - $GLOBALS['is_table'] = $result && $result->numRows(); - } - - if ($GLOBALS['is_table']) { - return; - } - - if ($isTransformationWrapper) { - ResponseRenderer::getInstance()->callExit(); - } - - if ($table !== '') { - /** - * SHOW TABLES doesn't show temporary tables, so try select - * (as it can happen just in case temporary table, it should be fast): - */ - $result = $GLOBALS['dbi']->tryQuery('SELECT COUNT(*) FROM ' . Util::backquote($table) . ';'); - $GLOBALS['is_table'] = $result && $result->numRows(); - } - - if ($GLOBALS['is_table']) { - return; - } - - /** @var SqlController $controller */ - $controller = Core::getContainerBuilder()->get(SqlController::class); - $controller(Application::getRequest()); - - ResponseRenderer::getInstance()->callExit(); + /** + * SHOW TABLES doesn't show temporary tables, so try select + * as it can happen just in case temporary table. It should be fast. + */ + private function isTemporaryTable(TableName $table): bool + { + return $this->dbi->tryQuery(sprintf('SELECT 1 FROM %s LIMIT 1;', Util::backquote($table))) !== false; } } diff --git a/libraries/services.php b/libraries/services.php index 71b602dba1..d2d83de681 100644 --- a/libraries/services.php +++ b/libraries/services.php @@ -16,6 +16,7 @@ use PhpMyAdmin\Database\Designer\Common; use PhpMyAdmin\Database\Events; use PhpMyAdmin\Database\Routines; use PhpMyAdmin\DatabaseInterface; +use PhpMyAdmin\DbTableExists; use PhpMyAdmin\ErrorHandler; use PhpMyAdmin\ErrorReport; use PhpMyAdmin\Export\Export; @@ -82,6 +83,7 @@ return [ 'central_columns' => ['class' => CentralColumns::class, 'arguments' => ['@dbi']], 'check_user_privileges' => ['class' => CheckUserPrivileges::class, 'arguments' => ['@dbi']], 'create_add_field' => ['class' => CreateAddField::class, 'arguments' => ['@dbi']], + DbTableExists::class => ['class' => DbTableExists::class, 'arguments' => ['@dbi']], 'designer' => [ 'class' => Designer::class, 'arguments' => ['$dbi' => '@dbi', '$relation' => '@relation', '$template' => '@template'], diff --git a/libraries/services_controllers.php b/libraries/services_controllers.php index 73cbf1225b..21f534af73 100644 --- a/libraries/services_controllers.php +++ b/libraries/services_controllers.php @@ -39,6 +39,7 @@ use PhpMyAdmin\Controllers\Triggers; use PhpMyAdmin\Controllers\UserPasswordController; use PhpMyAdmin\Controllers\VersionCheckController; use PhpMyAdmin\Controllers\View; +use PhpMyAdmin\DbTableExists; use PhpMyAdmin\Http\Factory\ResponseFactory; use PhpMyAdmin\Plugins\AuthenticationPluginFactory; use PhpMyAdmin\Theme\ThemeManager; @@ -119,6 +120,7 @@ return [ '$template' => '@template', '$databaseDesigner' => '@designer', '$designerCommon' => '@designer_common', + '$dbTableExists' => '@' . DbTableExists::class, ], ], Database\EventsController::class => [ @@ -128,6 +130,7 @@ return [ '$template' => '@template', '$events' => '@events', '$dbi' => '@dbi', + '$dbTableExists' => '@' . DbTableExists::class, ], ], Database\ExportController::class => [ @@ -138,6 +141,7 @@ return [ '$export' => '@export', '$exportOptions' => '@export_options', '$pageSettings' => '@' . PageSettings::class, + '$dbTableExists' => '@' . DbTableExists::class, ], ], Database\ImportController::class => [ @@ -147,6 +151,7 @@ return [ '$template' => '@template', '$dbi' => '@dbi', '$pageSettings' => '@' . PageSettings::class, + '$dbTableExists' => '@' . DbTableExists::class, ], ], Database\MultiTableQuery\QueryController::class => [ @@ -168,6 +173,7 @@ return [ '$template' => '@template', '$operations' => '@operations', '$dbi' => '@dbi', + '$dbTableExists' => '@' . DbTableExists::class, ], ], Database\OperationsController::class => [ @@ -180,6 +186,7 @@ return [ '$relation' => '@relation', '$relationCleanup' => '@relation_cleanup', '$dbi' => '@dbi', + '$dbTableExists' => '@' . DbTableExists::class, ], ], Database\PrivilegesController::class => [ @@ -199,11 +206,17 @@ return [ '$checkUserPrivileges' => '@check_user_privileges', '$dbi' => '@dbi', '$routines' => '@routines', + '$dbTableExists' => '@' . DbTableExists::class, ], ], Database\SearchController::class => [ 'class' => Database\SearchController::class, - 'arguments' => ['$response' => '@response', '$template' => '@template', '$dbi' => '@dbi'], + 'arguments' => [ + '$response' => '@response', + '$template' => '@template', + '$dbi' => '@dbi', + '$dbTableExists' => '@' . DbTableExists::class, + ], ], Database\SqlAutoCompleteController::class => [ 'class' => Database\SqlAutoCompleteController::class, @@ -216,6 +229,7 @@ return [ '$template' => '@template', '$sqlQueryForm' => '@sql_query_form', '$pageSettings' => '@' . PageSettings::class, + '$dbTableExists' => '@' . DbTableExists::class, ], ], Database\SqlFormatController::class => [ @@ -320,11 +334,21 @@ return [ ], Database\Structure\FavoriteTableController::class => [ 'class' => Database\Structure\FavoriteTableController::class, - 'arguments' => ['$response' => '@response', '$template' => '@template', '$relation' => '@relation'], + 'arguments' => [ + '$response' => '@response', + '$template' => '@template', + '$relation' => '@relation', + '$dbTableExists' => '@' . DbTableExists::class, + ], ], Database\Structure\RealRowCountController::class => [ 'class' => Database\Structure\RealRowCountController::class, - 'arguments' => ['$response' => '@response', '$template' => '@template', '$dbi' => '@dbi'], + 'arguments' => [ + '$response' => '@response', + '$template' => '@template', + '$dbi' => '@dbi', + '$dbTableExists' => '@' . DbTableExists::class, + ], ], Database\Structure\ReplacePrefixController::class => [ 'class' => Database\Structure\ReplacePrefixController::class, @@ -349,6 +373,7 @@ return [ '$dbi' => '@dbi', '$trackingChecker' => '@tracking_checker', '$pageSettings' => '@' . PageSettings::class, + '$dbTableExists' => '@' . DbTableExists::class, ], ], Database\TrackingController::class => [ @@ -358,6 +383,7 @@ return [ '$template' => '@template', '$tracking' => '@tracking', '$dbi' => '@dbi', + '$dbTableExists' => '@' . DbTableExists::class, ], ], DatabaseController::class => [ @@ -1033,6 +1059,7 @@ return [ '$config' => '@config', '$dbi' => '@dbi', '$columnsDefinition' => '@table_columns_definition', + '$dbTableExists' => '@' . DbTableExists::class, ], ], Table\ChangeController::class => [ @@ -1043,6 +1070,7 @@ return [ '$insertEdit' => '@insert_edit', '$relation' => '@relation', '$pageSettings' => '@' . PageSettings::class, + '$dbTableExists' => '@' . DbTableExists::class, ], ], Table\ChangeRowsController::class => [ @@ -1055,7 +1083,12 @@ return [ ], Table\ChartController::class => [ 'class' => Table\ChartController::class, - 'arguments' => ['$response' => '@response', '$template' => '@template', '$dbi' => '@dbi'], + 'arguments' => [ + '$response' => '@response', + '$template' => '@template', + '$dbi' => '@dbi', + '$dbTableExists' => '@' . DbTableExists::class, + ], ], Table\CreateController::class => [ 'class' => Table\CreateController::class, @@ -1070,7 +1103,11 @@ return [ ], Table\DeleteConfirmController::class => [ 'class' => Table\DeleteConfirmController::class, - 'arguments' => ['$response' => '@response', '$template' => '@template'], + 'arguments' => [ + '$response' => '@response', + '$template' => '@template', + '$dbTableExists' => '@' . DbTableExists::class, + ], ], Table\DeleteRowsController::class => [ 'class' => Table\DeleteRowsController::class, @@ -1078,7 +1115,11 @@ return [ ], Table\DropColumnConfirmationController::class => [ 'class' => Table\DropColumnConfirmationController::class, - 'arguments' => ['$response' => '@response', '$template' => '@template'], + 'arguments' => [ + '$response' => '@response', + '$template' => '@template', + '$dbTableExists' => '@' . DbTableExists::class, + ], ], Table\DropColumnController::class => [ 'class' => Table\DropColumnController::class, @@ -1109,7 +1150,12 @@ return [ ], Table\FindReplaceController::class => [ 'class' => Table\FindReplaceController::class, - 'arguments' => ['$response' => '@response', '$template' => '@template', '$dbi' => '@dbi'], + 'arguments' => [ + '$response' => '@response', + '$template' => '@template', + '$dbi' => '@dbi', + '$dbTableExists' => '@' . DbTableExists::class, + ], ], Table\GetFieldController::class => [ 'class' => Table\GetFieldController::class, @@ -1117,7 +1163,12 @@ return [ ], Table\GisVisualizationController::class => [ 'class' => Table\GisVisualizationController::class, - 'arguments' => ['$response' => '@response', '$template' => '@template', '$dbi' => '@dbi'], + 'arguments' => [ + '$response' => '@response', + '$template' => '@template', + '$dbi' => '@dbi', + '$dbTableExists' => '@' . DbTableExists::class, + ], ], Table\ImportController::class => [ 'class' => Table\ImportController::class, @@ -1126,6 +1177,7 @@ return [ '$template' => '@template', '$dbi' => '@dbi', '$pageSettings' => '@' . PageSettings::class, + '$dbTableExists' => '@' . DbTableExists::class, ], ], Table\IndexesController::class => [ @@ -1135,6 +1187,7 @@ return [ '$template' => '@template', '$dbi' => '@dbi', '$indexes' => '@table_indexes', + '$dbTableExists' => '@' . DbTableExists::class, ], ], Table\IndexRenameController::class => [ @@ -1144,6 +1197,7 @@ return [ '$template' => '@template', '$dbi' => '@dbi', '$indexes' => '@table_indexes', + '$dbTableExists' => '@' . DbTableExists::class, ], ], Table\Maintenance\AnalyzeController::class => [ @@ -1256,6 +1310,7 @@ return [ '$checkUserPrivileges' => '@check_user_privileges', '$relation' => '@relation', '$dbi' => '@dbi', + '$dbTableExists' => '@' . DbTableExists::class, ], ], Table\PrivilegesController::class => [ @@ -1299,6 +1354,7 @@ return [ '$search' => '@table_search', '$relation' => '@relation', '$dbi' => '@dbi', + '$dbTableExists' => '@' . DbTableExists::class, ], ], Table\SqlController::class => [ @@ -1308,6 +1364,7 @@ return [ '$template' => '@template', '$sqlQueryForm' => '@sql_query_form', '$pageSettings' => '@' . PageSettings::class, + '$dbTableExists' => '@' . DbTableExists::class, ], ], Table\Structure\AddIndexController::class => [ @@ -1390,6 +1447,7 @@ return [ '$template' => '@template', '$dbi' => '@dbi', '$structureController' => '@' . Table\StructureController::class, + '$dbTableExists' => '@' . DbTableExists::class, ], ], Table\Structure\ReservedWordCheckController::class => [ @@ -1434,6 +1492,7 @@ return [ '$transformations' => '@transformations', '$dbi' => '@dbi', '$pageSettings' => '@' . PageSettings::class, + '$dbTableExists' => '@' . DbTableExists::class, ], ], Table\TrackingController::class => [ @@ -1443,6 +1502,7 @@ return [ '$template' => '@template', '$tracking' => '@tracking', '$trackingChecker' => '@tracking_checker', + '$dbTableExists' => '@' . DbTableExists::class, ], ], Triggers\IndexController::class => [ @@ -1452,6 +1512,7 @@ return [ '$template' => '@template', '$dbi' => '@dbi', '$triggers' => '@triggers', + '$dbTableExists' => '@' . DbTableExists::class, ], ], Table\ZoomSearchController::class => [ @@ -1462,6 +1523,7 @@ return [ '$search' => '@table_search', '$relation' => '@relation', '$dbi' => '@dbi', + '$dbTableExists' => '@' . DbTableExists::class, ], ], TableController::class => [ @@ -1522,7 +1584,12 @@ return [ ], View\CreateController::class => [ 'class' => View\CreateController::class, - 'arguments' => ['$response' => '@response', '$template' => '@template', '$dbi' => '@dbi'], + 'arguments' => [ + '$response' => '@response', + '$template' => '@template', + '$dbi' => '@dbi', + '$dbTableExists' => '@' . DbTableExists::class, + ], ], View\OperationsController::class => [ 'class' => View\OperationsController::class, @@ -1531,6 +1598,7 @@ return [ '$template' => '@template', '$operations' => '@operations', '$dbi' => '@dbi', + '$dbTableExists' => '@' . DbTableExists::class, ], ], ], diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 583d1fb16f..b64019831b 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -1855,21 +1855,6 @@ parameters: count: 1 path: libraries/classes/Console.php - - - message: "#^Cannot call method getError\\(\\) on mixed\\.$#" - count: 1 - path: libraries/classes/Controllers/AbstractController.php - - - - message: "#^Cannot call method selectDb\\(\\) on mixed\\.$#" - count: 1 - path: libraries/classes/Controllers/AbstractController.php - - - - message: "#^Method PhpMyAdmin\\\\Controllers\\\\AbstractController\\:\\:hasDatabase\\(\\) should return bool but returns mixed\\.$#" - count: 1 - path: libraries/classes/Controllers/AbstractController.php - - message: "#^Parameter \\#1 \\$params of static method PhpMyAdmin\\\\Url\\:\\:getCommonRaw\\(\\) expects array\\, array\\ given\\.$#" count: 1 @@ -2895,11 +2880,6 @@ parameters: count: 1 path: libraries/classes/Controllers/Database/RoutinesController.php - - - message: "#^Parameter \\#1 \\$db of static method PhpMyAdmin\\\\DbTableExists\\:\\:check\\(\\) expects string, mixed given\\.$#" - count: 1 - path: libraries/classes/Controllers/Database/RoutinesController.php - - message: "#^Parameter \\#1 \\$dbname of method PhpMyAdmin\\\\DatabaseInterface\\:\\:selectDb\\(\\) expects PhpMyAdmin\\\\Identifiers\\\\DatabaseName\\|string, mixed given\\.$#" count: 1 @@ -2975,11 +2955,6 @@ parameters: count: 1 path: libraries/classes/Controllers/Database/RoutinesController.php - - - message: "#^Parameter \\#2 \\$table of static method PhpMyAdmin\\\\DbTableExists\\:\\:check\\(\\) expects string, mixed given\\.$#" - count: 1 - path: libraries/classes/Controllers/Database/RoutinesController.php - - message: "#^Parameter \\#2 \\$type of method PhpMyAdmin\\\\Database\\\\Routines\\:\\:getDataFromName\\(\\) expects string, mixed given\\.$#" count: 3 @@ -6790,11 +6765,6 @@ parameters: count: 1 path: libraries/classes/Controllers/Table/AddFieldController.php - - - message: "#^Parameter \\#1 \\$db of static method PhpMyAdmin\\\\DbTableExists\\:\\:check\\(\\) expects string, mixed given\\.$#" - count: 1 - path: libraries/classes/Controllers/Table/AddFieldController.php - - message: "#^Parameter \\#1 \\$params of static method PhpMyAdmin\\\\Url\\:\\:getCommon\\(\\) expects array\\, array\\ given\\.$#" count: 1 @@ -6835,11 +6805,6 @@ parameters: count: 1 path: libraries/classes/Controllers/Table/AddFieldController.php - - - message: "#^Parameter \\#2 \\$table of static method PhpMyAdmin\\\\DbTableExists\\:\\:check\\(\\) expects string, mixed given\\.$#" - count: 1 - path: libraries/classes/Controllers/Table/AddFieldController.php - - message: "#^Parameter \\#3 \\$errorUrl of method PhpMyAdmin\\\\CreateAddField\\:\\:tryColumnCreationQuery\\(\\) expects string, mixed given\\.$#" count: 1 @@ -6940,11 +6905,6 @@ parameters: count: 1 path: libraries/classes/Controllers/Table/ChangeController.php - - - message: "#^Parameter \\#1 \\$db of static method PhpMyAdmin\\\\DbTableExists\\:\\:check\\(\\) expects string, mixed given\\.$#" - count: 1 - path: libraries/classes/Controllers/Table/ChangeController.php - - message: "#^Parameter \\#1 \\$files of method PhpMyAdmin\\\\Controllers\\\\AbstractController\\:\\:addScriptFiles\\(\\) expects array\\, mixed given\\.$#" count: 1 @@ -7080,11 +7040,6 @@ parameters: count: 1 path: libraries/classes/Controllers/Table/ChangeController.php - - - message: "#^Parameter \\#2 \\$table of static method PhpMyAdmin\\\\DbTableExists\\:\\:check\\(\\) expects string, mixed given\\.$#" - count: 1 - path: libraries/classes/Controllers/Table/ChangeController.php - - message: "#^Parameter \\#3 \\$table of method PhpMyAdmin\\\\InsertEdit\\:\\:determineInsertOrEdit\\(\\) expects string, mixed given\\.$#" count: 1 @@ -7140,11 +7095,6 @@ parameters: count: 1 path: libraries/classes/Controllers/Table/ChartController.php - - - message: "#^Parameter \\#1 \\$db of static method PhpMyAdmin\\\\DbTableExists\\:\\:check\\(\\) expects string, mixed given\\.$#" - count: 2 - path: libraries/classes/Controllers/Table/ChartController.php - - message: "#^Parameter \\#1 \\$dbname of method PhpMyAdmin\\\\DatabaseInterface\\:\\:selectDb\\(\\) expects PhpMyAdmin\\\\Identifiers\\\\DatabaseName\\|string, mixed given\\.$#" count: 1 @@ -7200,11 +7150,6 @@ parameters: count: 1 path: libraries/classes/Controllers/Table/ChartController.php - - - message: "#^Parameter \\#2 \\$table of static method PhpMyAdmin\\\\DbTableExists\\:\\:check\\(\\) expects string, mixed given\\.$#" - count: 2 - path: libraries/classes/Controllers/Table/ChartController.php - - message: "#^Cannot access offset \\(int\\|string\\) on mixed\\.$#" count: 7 @@ -7310,11 +7255,6 @@ parameters: count: 1 path: libraries/classes/Controllers/Table/DeleteConfirmController.php - - - message: "#^Parameter \\#1 \\$db of static method PhpMyAdmin\\\\DbTableExists\\:\\:check\\(\\) expects string, mixed given\\.$#" - count: 1 - path: libraries/classes/Controllers/Table/DeleteConfirmController.php - - message: "#^Parameter \\#1 \\$params of static method PhpMyAdmin\\\\Url\\:\\:getCommon\\(\\) expects array\\, mixed given\\.$#" count: 1 @@ -7325,11 +7265,6 @@ parameters: count: 1 path: libraries/classes/Controllers/Table/DeleteConfirmController.php - - - message: "#^Parameter \\#2 \\$table of static method PhpMyAdmin\\\\DbTableExists\\:\\:check\\(\\) expects string, mixed given\\.$#" - count: 1 - path: libraries/classes/Controllers/Table/DeleteConfirmController.php - - message: "#^Argument of an invalid type mixed supplied for foreach, only iterables are supported\\.$#" count: 1 @@ -7550,11 +7485,6 @@ parameters: count: 1 path: libraries/classes/Controllers/Table/FindReplaceController.php - - - message: "#^Parameter \\#1 \\$db of static method PhpMyAdmin\\\\DbTableExists\\:\\:check\\(\\) expects string, mixed given\\.$#" - count: 1 - path: libraries/classes/Controllers/Table/FindReplaceController.php - - message: "#^Parameter \\#1 \\$identifier of static method PhpMyAdmin\\\\Util\\:\\:backquote\\(\\) expects string\\|Stringable\\|null, mixed given\\.$#" count: 22 @@ -7590,11 +7520,6 @@ parameters: count: 1 path: libraries/classes/Controllers/Table/FindReplaceController.php - - - message: "#^Parameter \\#2 \\$table of static method PhpMyAdmin\\\\DbTableExists\\:\\:check\\(\\) expects string, mixed given\\.$#" - count: 1 - path: libraries/classes/Controllers/Table/FindReplaceController.php - - message: "#^Parameter \\#3 \\$replaceWith of method PhpMyAdmin\\\\Controllers\\\\Table\\\\FindReplaceController\\:\\:getReplacePreview\\(\\) expects string, mixed given\\.$#" count: 1 @@ -7785,11 +7710,6 @@ parameters: count: 2 path: libraries/classes/Controllers/Table/ImportController.php - - - message: "#^Parameter \\#1 \\$db of static method PhpMyAdmin\\\\DbTableExists\\:\\:check\\(\\) expects string, mixed given\\.$#" - count: 1 - path: libraries/classes/Controllers/Table/ImportController.php - - message: "#^Parameter \\#1 \\$params of static method PhpMyAdmin\\\\Url\\:\\:getCommon\\(\\) expects array\\, mixed given\\.$#" count: 1 @@ -7805,21 +7725,11 @@ parameters: count: 1 path: libraries/classes/Controllers/Table/ImportController.php - - - message: "#^Parameter \\#2 \\$table of static method PhpMyAdmin\\\\DbTableExists\\:\\:check\\(\\) expects string, mixed given\\.$#" - count: 1 - path: libraries/classes/Controllers/Table/ImportController.php - - message: "#^Cannot access offset 'DefaultTabTable' on mixed\\.$#" count: 1 path: libraries/classes/Controllers/Table/IndexRenameController.php - - - message: "#^Parameter \\#1 \\$db of static method PhpMyAdmin\\\\DbTableExists\\:\\:check\\(\\) expects string, mixed given\\.$#" - count: 1 - path: libraries/classes/Controllers/Table/IndexRenameController.php - - message: "#^Parameter \\#1 \\$dbName of method PhpMyAdmin\\\\DatabaseInterface\\:\\:getTable\\(\\) expects string, mixed given\\.$#" count: 1 @@ -7845,11 +7755,6 @@ parameters: count: 1 path: libraries/classes/Controllers/Table/IndexRenameController.php - - - message: "#^Parameter \\#2 \\$table of static method PhpMyAdmin\\\\DbTableExists\\:\\:check\\(\\) expects string, mixed given\\.$#" - count: 1 - path: libraries/classes/Controllers/Table/IndexRenameController.php - - message: "#^Parameter \\#2 \\$tableName of method PhpMyAdmin\\\\DatabaseInterface\\:\\:getTable\\(\\) expects string, mixed given\\.$#" count: 1 @@ -7890,11 +7795,6 @@ parameters: count: 2 path: libraries/classes/Controllers/Table/IndexesController.php - - - message: "#^Parameter \\#1 \\$db of static method PhpMyAdmin\\\\DbTableExists\\:\\:check\\(\\) expects string, mixed given\\.$#" - count: 1 - path: libraries/classes/Controllers/Table/IndexesController.php - - message: "#^Parameter \\#1 \\$dbName of method PhpMyAdmin\\\\DatabaseInterface\\:\\:getTable\\(\\) expects string, mixed given\\.$#" count: 2 @@ -7930,11 +7830,6 @@ parameters: count: 2 path: libraries/classes/Controllers/Table/IndexesController.php - - - message: "#^Parameter \\#2 \\$table of static method PhpMyAdmin\\\\DbTableExists\\:\\:check\\(\\) expects string, mixed given\\.$#" - count: 1 - path: libraries/classes/Controllers/Table/IndexesController.php - - message: "#^Parameter \\#2 \\$tableName of method PhpMyAdmin\\\\DatabaseInterface\\:\\:getTable\\(\\) expects string, mixed given\\.$#" count: 2 @@ -8050,11 +7945,6 @@ parameters: count: 1 path: libraries/classes/Controllers/Table/OperationsController.php - - - message: "#^Parameter \\#1 \\$db of static method PhpMyAdmin\\\\DbTableExists\\:\\:check\\(\\) expects string, mixed given\\.$#" - count: 1 - path: libraries/classes/Controllers/Table/OperationsController.php - - message: "#^Parameter \\#1 \\$db of static method PhpMyAdmin\\\\Partitioning\\\\Partition\\:\\:getPartitionNames\\(\\) expects string, mixed given\\.$#" count: 1 @@ -8150,11 +8040,6 @@ parameters: count: 1 path: libraries/classes/Controllers/Table/OperationsController.php - - - message: "#^Parameter \\#2 \\$table of static method PhpMyAdmin\\\\DbTableExists\\:\\:check\\(\\) expects string, mixed given\\.$#" - count: 1 - path: libraries/classes/Controllers/Table/OperationsController.php - - message: "#^Parameter \\#2 \\$table of static method PhpMyAdmin\\\\Index\\:\\:getFromTable\\(\\) expects string, mixed given\\.$#" count: 1 @@ -8780,11 +8665,6 @@ parameters: count: 1 path: libraries/classes/Controllers/Table/SearchController.php - - - message: "#^Parameter \\#1 \\$db of static method PhpMyAdmin\\\\DbTableExists\\:\\:check\\(\\) expects string, mixed given\\.$#" - count: 1 - path: libraries/classes/Controllers/Table/SearchController.php - - message: "#^Parameter \\#1 \\$identifier of static method PhpMyAdmin\\\\Util\\:\\:backquote\\(\\) expects string\\|Stringable\\|null, mixed given\\.$#" count: 4 @@ -8850,11 +8730,6 @@ parameters: count: 1 path: libraries/classes/Controllers/Table/SearchController.php - - - message: "#^Parameter \\#2 \\$table of static method PhpMyAdmin\\\\DbTableExists\\:\\:check\\(\\) expects string, mixed given\\.$#" - count: 1 - path: libraries/classes/Controllers/Table/SearchController.php - - message: "#^Parameter \\#3 \\$db of method PhpMyAdmin\\\\Sql\\:\\:executeQueryAndSendQueryResponse\\(\\) expects string, mixed given\\.$#" count: 1 @@ -8885,11 +8760,6 @@ parameters: count: 1 path: libraries/classes/Controllers/Table/SqlController.php - - - message: "#^Parameter \\#1 \\$db of static method PhpMyAdmin\\\\DbTableExists\\:\\:check\\(\\) expects string, mixed given\\.$#" - count: 1 - path: libraries/classes/Controllers/Table/SqlController.php - - message: "#^Parameter \\#1 \\$params of static method PhpMyAdmin\\\\Url\\:\\:getCommon\\(\\) expects array\\, array\\ given\\.$#" count: 1 @@ -8910,11 +8780,6 @@ parameters: count: 1 path: libraries/classes/Controllers/Table/SqlController.php - - - message: "#^Parameter \\#2 \\$table of static method PhpMyAdmin\\\\DbTableExists\\:\\:check\\(\\) expects string, mixed given\\.$#" - count: 1 - path: libraries/classes/Controllers/Table/SqlController.php - - message: "#^Parameter \\#3 \\$query of method PhpMyAdmin\\\\SqlQueryForm\\:\\:getHtml\\(\\) expects bool\\|string, mixed given\\.$#" count: 1 @@ -9210,11 +9075,6 @@ parameters: count: 1 path: libraries/classes/Controllers/Table/Structure/PrimaryController.php - - - message: "#^Parameter \\#1 \\$db of static method PhpMyAdmin\\\\DbTableExists\\:\\:check\\(\\) expects string, mixed given\\.$#" - count: 1 - path: libraries/classes/Controllers/Table/Structure/PrimaryController.php - - message: "#^Parameter \\#1 \\$dbname of method PhpMyAdmin\\\\DatabaseInterface\\:\\:selectDb\\(\\) expects PhpMyAdmin\\\\Identifiers\\\\DatabaseName\\|string, mixed given\\.$#" count: 2 @@ -9235,11 +9095,6 @@ parameters: count: 1 path: libraries/classes/Controllers/Table/Structure/PrimaryController.php - - - message: "#^Parameter \\#2 \\$table of static method PhpMyAdmin\\\\DbTableExists\\:\\:check\\(\\) expects string, mixed given\\.$#" - count: 1 - path: libraries/classes/Controllers/Table/Structure/PrimaryController.php - - message: "#^Argument of an invalid type mixed supplied for foreach, only iterables are supported\\.$#" count: 1 @@ -9625,11 +9480,6 @@ parameters: count: 1 path: libraries/classes/Controllers/Table/StructureController.php - - - message: "#^Parameter \\#1 \\$db of static method PhpMyAdmin\\\\DbTableExists\\:\\:check\\(\\) expects string, mixed given\\.$#" - count: 1 - path: libraries/classes/Controllers/Table/StructureController.php - - message: "#^Parameter \\#1 \\$db of static method PhpMyAdmin\\\\Partitioning\\\\Partition\\:\\:getPartitionNames\\(\\) expects string, mixed given\\.$#" count: 1 @@ -9720,11 +9570,6 @@ parameters: count: 1 path: libraries/classes/Controllers/Table/StructureController.php - - - message: "#^Parameter \\#2 \\$table of static method PhpMyAdmin\\\\DbTableExists\\:\\:check\\(\\) expects string, mixed given\\.$#" - count: 1 - path: libraries/classes/Controllers/Table/StructureController.php - - message: "#^Parameter \\#2 \\$table of static method PhpMyAdmin\\\\Index\\:\\:getFromTable\\(\\) expects string, mixed given\\.$#" count: 1 @@ -9810,11 +9655,6 @@ parameters: count: 1 path: libraries/classes/Controllers/Table/TrackingController.php - - - message: "#^Parameter \\#1 \\$db of static method PhpMyAdmin\\\\DbTableExists\\:\\:check\\(\\) expects string, mixed given\\.$#" - count: 1 - path: libraries/classes/Controllers/Table/TrackingController.php - - message: "#^Parameter \\#1 \\$dbName of method PhpMyAdmin\\\\Tracking\\\\TrackingChecker\\:\\:getTrackedTables\\(\\) expects string, mixed given\\.$#" count: 1 @@ -9865,11 +9705,6 @@ parameters: count: 1 path: libraries/classes/Controllers/Table/TrackingController.php - - - message: "#^Parameter \\#2 \\$table of static method PhpMyAdmin\\\\DbTableExists\\:\\:check\\(\\) expects string, mixed given\\.$#" - count: 1 - path: libraries/classes/Controllers/Table/TrackingController.php - - message: "#^Parameter \\#2 \\$tablename of method PhpMyAdmin\\\\Tracking\\\\Tracking\\:\\:getTrackedData\\(\\) expects string, mixed given\\.$#" count: 3 @@ -10015,11 +9850,6 @@ parameters: count: 1 path: libraries/classes/Controllers/Table/ZoomSearchController.php - - - message: "#^Parameter \\#1 \\$db of static method PhpMyAdmin\\\\DbTableExists\\:\\:check\\(\\) expects string, mixed given\\.$#" - count: 1 - path: libraries/classes/Controllers/Table/ZoomSearchController.php - - message: "#^Parameter \\#1 \\$identifier of static method PhpMyAdmin\\\\Util\\:\\:backquote\\(\\) expects string\\|Stringable\\|null, mixed given\\.$#" count: 2 @@ -10100,11 +9930,6 @@ parameters: count: 1 path: libraries/classes/Controllers/Table/ZoomSearchController.php - - - message: "#^Parameter \\#2 \\$table of static method PhpMyAdmin\\\\DbTableExists\\:\\:check\\(\\) expects string, mixed given\\.$#" - count: 1 - path: libraries/classes/Controllers/Table/ZoomSearchController.php - - message: "#^Parameter \\#3 \\$selectedOperator of method PhpMyAdmin\\\\Types\\:\\:getTypeOperatorsHtml\\(\\) expects string\\|null, mixed given\\.$#" count: 1 @@ -10190,11 +10015,6 @@ parameters: count: 3 path: libraries/classes/Controllers/Triggers/IndexController.php - - - message: "#^Parameter \\#1 \\$db of static method PhpMyAdmin\\\\DbTableExists\\:\\:check\\(\\) expects string, mixed given\\.$#" - count: 1 - path: libraries/classes/Controllers/Triggers/IndexController.php - - message: "#^Parameter \\#1 \\$dbname of method PhpMyAdmin\\\\DatabaseInterface\\:\\:selectDb\\(\\) expects PhpMyAdmin\\\\Identifiers\\\\DatabaseName\\|string, mixed given\\.$#" count: 1 @@ -10255,11 +10075,6 @@ parameters: count: 3 path: libraries/classes/Controllers/Triggers/IndexController.php - - - message: "#^Parameter \\#2 \\$table of static method PhpMyAdmin\\\\DbTableExists\\:\\:check\\(\\) expects string, mixed given\\.$#" - count: 1 - path: libraries/classes/Controllers/Triggers/IndexController.php - - message: "#^Parameter \\#3 \\$name of method PhpMyAdmin\\\\Triggers\\\\Triggers\\:\\:getTriggerByName\\(\\) expects string, mixed given\\.$#" count: 2 @@ -10490,11 +10305,6 @@ parameters: count: 1 path: libraries/classes/Controllers/View/OperationsController.php - - - message: "#^Parameter \\#1 \\$db of static method PhpMyAdmin\\\\DbTableExists\\:\\:check\\(\\) expects string, mixed given\\.$#" - count: 1 - path: libraries/classes/Controllers/View/OperationsController.php - - message: "#^Parameter \\#1 \\$dbName of method PhpMyAdmin\\\\DatabaseInterface\\:\\:getTable\\(\\) expects string, mixed given\\.$#" count: 1 @@ -10515,11 +10325,6 @@ parameters: count: 1 path: libraries/classes/Controllers/View/OperationsController.php - - - message: "#^Parameter \\#2 \\$table of static method PhpMyAdmin\\\\DbTableExists\\:\\:check\\(\\) expects string, mixed given\\.$#" - count: 1 - path: libraries/classes/Controllers/View/OperationsController.php - - message: "#^Parameter \\#2 \\$tableName of method PhpMyAdmin\\\\DatabaseInterface\\:\\:getTable\\(\\) expects string, mixed given\\.$#" count: 1 @@ -12080,46 +11885,6 @@ parameters: count: 1 path: libraries/classes/DatabaseInterface.php - - - message: "#^Cannot call method escapeString\\(\\) on mixed\\.$#" - count: 1 - path: libraries/classes/DbTableExists.php - - - - message: "#^Cannot call method getCache\\(\\) on mixed\\.$#" - count: 1 - path: libraries/classes/DbTableExists.php - - - - message: "#^Cannot call method getCachedTableContent\\(\\) on mixed\\.$#" - count: 1 - path: libraries/classes/DbTableExists.php - - - - message: "#^Cannot call method numRows\\(\\) on mixed\\.$#" - count: 2 - path: libraries/classes/DbTableExists.php - - - - message: "#^Cannot call method selectDb\\(\\) on mixed\\.$#" - count: 1 - path: libraries/classes/DbTableExists.php - - - - message: "#^Cannot call method tryQuery\\(\\) on mixed\\.$#" - count: 2 - path: libraries/classes/DbTableExists.php - - - - message: "#^Construct empty\\(\\) is not allowed\\. Use more strict comparison\\.$#" - count: 3 - path: libraries/classes/DbTableExists.php - - - - message: "#^Parameter \\#1 \\$params of static method PhpMyAdmin\\\\Url\\:\\:getCommonRaw\\(\\) expects array\\, array\\ given\\.$#" - count: 1 - path: libraries/classes/DbTableExists.php - - message: "#^Method PhpMyAdmin\\\\Dbal\\\\DbalInterface\\:\\:fetchSingleRow\\(\\) return type has no value type specified in iterable type array\\.$#" count: 1 @@ -28185,6 +27950,11 @@ parameters: count: 8 path: test/classes/Controllers/Database/StructureControllerTest.php + - + message: "#^Parameter \\#1 \\$dbi of class PhpMyAdmin\\\\DbTableExists constructor expects PhpMyAdmin\\\\DatabaseInterface, mixed given\\.$#" + count: 7 + path: test/classes/Controllers/Database/StructureControllerTest.php + - message: "#^Parameter \\#2 \\$array of method PHPUnit\\\\Framework\\\\Assert\\:\\:assertArrayNotHasKey\\(\\) expects array\\|ArrayAccess, mixed given\\.$#" count: 1 @@ -28940,6 +28710,11 @@ parameters: count: 1 path: test/classes/Controllers/Table/DeleteRowsControllerTest.php + - + message: "#^Parameter \\#1 \\$dbi of class PhpMyAdmin\\\\DbTableExists constructor expects PhpMyAdmin\\\\DatabaseInterface, mixed given\\.$#" + count: 2 + path: test/classes/Controllers/Table/DropColumnConfirmationControllerTest.php + - message: "#^Cannot access offset 'DisableIS' on mixed\\.$#" count: 1 @@ -28980,6 +28755,11 @@ parameters: count: 1 path: test/classes/Controllers/Table/FindReplaceControllerTest.php + - + message: "#^Parameter \\#1 \\$dbi of class PhpMyAdmin\\\\DbTableExists constructor expects PhpMyAdmin\\\\DatabaseInterface, mixed given\\.$#" + count: 2 + path: test/classes/Controllers/Table/FindReplaceControllerTest.php + - message: "#^Parameter \\#3 \\$dbi of class PhpMyAdmin\\\\Controllers\\\\Table\\\\FindReplaceController constructor expects PhpMyAdmin\\\\DatabaseInterface, mixed given\\.$#" count: 2 @@ -29040,6 +28820,11 @@ parameters: count: 1 path: test/classes/Controllers/Table/IndexesControllerTest.php + - + message: "#^Parameter \\#1 \\$dbi of class PhpMyAdmin\\\\DbTableExists constructor expects PhpMyAdmin\\\\DatabaseInterface, mixed given\\.$#" + count: 1 + path: test/classes/Controllers/Table/IndexesControllerTest.php + - message: "#^Parameter \\#3 \\$dbi of class PhpMyAdmin\\\\Controllers\\\\Table\\\\IndexesController constructor expects PhpMyAdmin\\\\DatabaseInterface, mixed given\\.$#" count: 1 @@ -29220,6 +29005,11 @@ parameters: count: 2 path: test/classes/Controllers/Table/SearchControllerTest.php + - + message: "#^Parameter \\#1 \\$dbi of class PhpMyAdmin\\\\DbTableExists constructor expects PhpMyAdmin\\\\DatabaseInterface, mixed given\\.$#" + count: 1 + path: test/classes/Controllers/Table/SearchControllerTest.php + - message: "#^Parameter \\#1 \\$dbi of class PhpMyAdmin\\\\Table\\\\Search constructor expects PhpMyAdmin\\\\DatabaseInterface, mixed given\\.$#" count: 1 diff --git a/psalm-baseline.xml b/psalm-baseline.xml index d40da6611b..2d54066736 100644 --- a/psalm-baseline.xml +++ b/psalm-baseline.xml @@ -846,9 +846,6 @@ - - - $params @@ -3302,9 +3299,6 @@ - - $request - @@ -3444,9 +3438,6 @@ - - $request - @@ -3475,9 +3466,6 @@ - - $request - @@ -3784,9 +3772,6 @@ getColumnProperties - - $request - @@ -4180,9 +4165,6 @@ - - $request - @@ -5426,24 +5408,6 @@ - - - escapeString - - - - - - - - $urlParams - - - - - - - bool diff --git a/test/classes/Controllers/Database/EventsControllerTest.php b/test/classes/Controllers/Database/EventsControllerTest.php index ef1d990126..3e8f2cf2e4 100644 --- a/test/classes/Controllers/Database/EventsControllerTest.php +++ b/test/classes/Controllers/Database/EventsControllerTest.php @@ -6,7 +6,8 @@ namespace PhpMyAdmin\Tests\Controllers\Database; use PhpMyAdmin\Controllers\Database\EventsController; use PhpMyAdmin\Database\Events; -use PhpMyAdmin\Http\ServerRequest; +use PhpMyAdmin\DbTableExists; +use PhpMyAdmin\Http\Factory\ServerRequestFactory; use PhpMyAdmin\Template; use PhpMyAdmin\Tests\AbstractTestCase; use PhpMyAdmin\Tests\Stubs\ResponseRenderer; @@ -50,12 +51,16 @@ final class EventsControllerTest extends AbstractTestCase $response = new ResponseRenderer(); $template = new Template(); + $request = ServerRequestFactory::create()->createServerRequest('GET', 'http://example.com/') + ->withQueryParams(['db' => 'test_db']); + (new EventsController( $response, $template, new Events($dbi), $dbi, - ))($this->createStub(ServerRequest::class)); + new DbTableExists($dbi), + ))($request); $actual = $response->getHTMLResult(); // phpcs:disable Generic.Files.LineLength.TooLong @@ -217,12 +222,16 @@ HTML; $response = new ResponseRenderer(); $template = new Template(); + $request = ServerRequestFactory::create()->createServerRequest('GET', 'http://example.com/') + ->withQueryParams(['db' => 'test_db']); + (new EventsController( $response, $template, new Events($dbi), $dbi, - ))($this->createStub(ServerRequest::class)); + new DbTableExists($dbi), + ))($request); $actual = $response->getHTMLResult(); // phpcs:disable Generic.Files.LineLength.TooLong diff --git a/test/classes/Controllers/Database/RoutinesControllerTest.php b/test/classes/Controllers/Database/RoutinesControllerTest.php index d7caf1304f..5f56c75e10 100644 --- a/test/classes/Controllers/Database/RoutinesControllerTest.php +++ b/test/classes/Controllers/Database/RoutinesControllerTest.php @@ -7,7 +7,8 @@ namespace PhpMyAdmin\Tests\Controllers\Database; use PhpMyAdmin\CheckUserPrivileges; use PhpMyAdmin\Controllers\Database\RoutinesController; use PhpMyAdmin\Database\Routines; -use PhpMyAdmin\Http\ServerRequest; +use PhpMyAdmin\DbTableExists; +use PhpMyAdmin\Http\Factory\ServerRequestFactory; use PhpMyAdmin\Template; use PhpMyAdmin\Tests\AbstractTestCase; use PhpMyAdmin\Tests\Stubs\ResponseRenderer; @@ -98,13 +99,17 @@ final class RoutinesControllerTest extends AbstractTestCase $template = new Template(); $response = new ResponseRenderer(); + $request = ServerRequestFactory::create()->createServerRequest('GET', 'http://example.com/') + ->withQueryParams(['db' => 'test_db']); + (new RoutinesController( $response, $template, new CheckUserPrivileges($dbi), $dbi, new Routines($dbi), - ))($this->createStub(ServerRequest::class)); + new DbTableExists($dbi), + ))($request); $actual = $response->getHTMLResult(); // phpcs:disable Generic.Files.LineLength.TooLong @@ -268,13 +273,17 @@ HTML; $template = new Template(); $response = new ResponseRenderer(); + $request = ServerRequestFactory::create()->createServerRequest('GET', 'http://example.com/') + ->withQueryParams(['db' => 'test_db']); + (new RoutinesController( $response, $template, new CheckUserPrivileges($dbi), $dbi, new Routines($dbi), - ))($this->createStub(ServerRequest::class)); + new DbTableExists($dbi), + ))($request); $actual = $response->getHTMLResult(); // phpcs:disable Generic.Files.LineLength.TooLong diff --git a/test/classes/Controllers/Database/Structure/FavoriteTableControllerTest.php b/test/classes/Controllers/Database/Structure/FavoriteTableControllerTest.php index ce14efcea7..366c86e6b4 100644 --- a/test/classes/Controllers/Database/Structure/FavoriteTableControllerTest.php +++ b/test/classes/Controllers/Database/Structure/FavoriteTableControllerTest.php @@ -7,6 +7,7 @@ namespace PhpMyAdmin\Tests\Controllers\Database\Structure; use PhpMyAdmin\ConfigStorage\Relation; use PhpMyAdmin\Controllers\Database\Structure\FavoriteTableController; use PhpMyAdmin\DatabaseInterface; +use PhpMyAdmin\DbTableExists; use PhpMyAdmin\RecentFavoriteTable; use PhpMyAdmin\Template; use PhpMyAdmin\Tests\AbstractTestCase; @@ -53,6 +54,7 @@ class FavoriteTableControllerTest extends AbstractTestCase new ResponseStub(), new Template(), new Relation($this->dbi), + new DbTableExists($this->dbi), ); // The user hash for test diff --git a/test/classes/Controllers/Database/Structure/RealRowCountControllerTest.php b/test/classes/Controllers/Database/Structure/RealRowCountControllerTest.php index dccd38fab5..066cddb56d 100644 --- a/test/classes/Controllers/Database/Structure/RealRowCountControllerTest.php +++ b/test/classes/Controllers/Database/Structure/RealRowCountControllerTest.php @@ -5,11 +5,10 @@ declare(strict_types=1); namespace PhpMyAdmin\Tests\Controllers\Database\Structure; use PhpMyAdmin\Controllers\Database\Structure\RealRowCountController; -use PhpMyAdmin\DatabaseInterface; -use PhpMyAdmin\Http\ServerRequest; +use PhpMyAdmin\DbTableExists; +use PhpMyAdmin\Http\Factory\ServerRequestFactory; use PhpMyAdmin\Template; use PhpMyAdmin\Tests\AbstractTestCase; -use PhpMyAdmin\Tests\Stubs\DbiDummy; use PhpMyAdmin\Tests\Stubs\ResponseRenderer as ResponseStub; use PHPUnit\Framework\Attributes\CoversClass; @@ -18,41 +17,33 @@ use function json_encode; #[CoversClass(RealRowCountController::class)] class RealRowCountControllerTest extends AbstractTestCase { - protected DatabaseInterface $dbi; - - protected DbiDummy $dummyDbi; - - protected function setUp(): void - { - parent::setUp(); - - $this->dummyDbi = $this->createDbiDummy(); - $this->dbi = $this->createDatabaseInterface($this->dummyDbi); - $GLOBALS['dbi'] = $this->dbi; - } - public function testRealRowCount(): void { $GLOBALS['server'] = 1; $GLOBALS['text_dir'] = 'ltr'; $GLOBALS['cfg']['Server']['DisableIS'] = true; - $GLOBALS['is_db'] = true; $GLOBALS['db'] = 'world'; + $_REQUEST['table'] = 'City'; + + $dbiDummy = $this->createDbiDummy(); + $dbiDummy->addSelectDb('world'); + $dbiDummy->addSelectDb('world'); + $dbi = $this->createDatabaseInterface($dbiDummy); + $GLOBALS['dbi'] = $dbi; $response = new ResponseStub(); - $_REQUEST['table'] = 'City'; - $request = $this->createStub(ServerRequest::class); - $request->method('isAjax')->willReturn(true); + $request = ServerRequestFactory::create()->createServerRequest('GET', 'http://example.com/') + ->withQueryParams(['db' => 'world', 'table' => 'City', 'ajax_request' => '1']); - (new RealRowCountController($response, new Template(), $this->dbi))($request); + (new RealRowCountController($response, new Template(), $dbi, new DbTableExists($dbi)))($request); $json = $response->getJSONResult(); $this->assertEquals('4,079', $json['real_row_count']); $_REQUEST['real_row_count_all'] = 'on'; - (new RealRowCountController($response, new Template(), $this->dbi))($request); + (new RealRowCountController($response, new Template(), $dbi, new DbTableExists($dbi)))($request); $json = $response->getJSONResult(); $expected = [ @@ -61,5 +52,7 @@ class RealRowCountControllerTest extends AbstractTestCase ['table' => 'CountryLanguage', 'row_count' => 984], ]; $this->assertEquals(json_encode($expected), $json['real_row_count_all']); + + $dbiDummy->assertAllSelectsConsumed(); } } diff --git a/test/classes/Controllers/Database/StructureControllerTest.php b/test/classes/Controllers/Database/StructureControllerTest.php index d18490c8ce..89940f6b93 100644 --- a/test/classes/Controllers/Database/StructureControllerTest.php +++ b/test/classes/Controllers/Database/StructureControllerTest.php @@ -8,6 +8,7 @@ use PhpMyAdmin\Config\PageSettings; use PhpMyAdmin\ConfigStorage\Relation; use PhpMyAdmin\Controllers\Database\StructureController; use PhpMyAdmin\DatabaseInterface; +use PhpMyAdmin\DbTableExists; use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\RecentFavoriteTable; use PhpMyAdmin\Replication\Replication; @@ -84,6 +85,7 @@ class StructureControllerTest extends AbstractTestCase $GLOBALS['dbi'], $this->createStub(TrackingChecker::class), $this->createStub(PageSettings::class), + new DbTableExists($GLOBALS['dbi']), ); // Showing statistics $property = $class->getProperty('isShowStats'); @@ -123,6 +125,7 @@ class StructureControllerTest extends AbstractTestCase $GLOBALS['dbi'], $this->createStub(TrackingChecker::class), $this->createStub(PageSettings::class), + new DbTableExists($GLOBALS['dbi']), ); $currentTable['ENGINE'] = 'InnoDB'; @@ -152,6 +155,7 @@ class StructureControllerTest extends AbstractTestCase $GLOBALS['dbi'], $this->createStub(TrackingChecker::class), $this->createStub(PageSettings::class), + new DbTableExists($GLOBALS['dbi']), ); // Showing statistics $property = $class->getProperty('isShowStats'); @@ -183,6 +187,7 @@ class StructureControllerTest extends AbstractTestCase $GLOBALS['dbi'], $this->createStub(TrackingChecker::class), $this->createStub(PageSettings::class), + new DbTableExists($GLOBALS['dbi']), ); [$currentTable, , , , , , $sumSize] = $method->invokeArgs( $controller, @@ -198,6 +203,7 @@ class StructureControllerTest extends AbstractTestCase $GLOBALS['dbi'], $this->createStub(TrackingChecker::class), $this->createStub(PageSettings::class), + new DbTableExists($GLOBALS['dbi']), ); [$currentTable] = $method->invokeArgs( $controller, @@ -222,6 +228,7 @@ class StructureControllerTest extends AbstractTestCase $GLOBALS['dbi'], $this->createStub(TrackingChecker::class), $this->createStub(PageSettings::class), + new DbTableExists($GLOBALS['dbi']), ); // When parameter $db is empty @@ -278,6 +285,7 @@ class StructureControllerTest extends AbstractTestCase $GLOBALS['dbi'], $this->createStub(TrackingChecker::class), $this->createStub(PageSettings::class), + new DbTableExists($GLOBALS['dbi']), ); $recentFavoriteTables = RecentFavoriteTable::getInstance('favorite'); @@ -314,6 +322,7 @@ class StructureControllerTest extends AbstractTestCase $GLOBALS['dbi'], $this->createStub(TrackingChecker::class), $this->createStub(PageSettings::class), + new DbTableExists($GLOBALS['dbi']), ); // Showing statistics $class = new ReflectionClass(StructureController::class); diff --git a/test/classes/Controllers/Table/AddFieldControllerTest.php b/test/classes/Controllers/Table/AddFieldControllerTest.php index 3c82147181..d28822d5da 100644 --- a/test/classes/Controllers/Table/AddFieldControllerTest.php +++ b/test/classes/Controllers/Table/AddFieldControllerTest.php @@ -6,7 +6,8 @@ namespace PhpMyAdmin\Tests\Controllers\Table; use PhpMyAdmin\ConfigStorage\Relation; use PhpMyAdmin\Controllers\Table\AddFieldController; -use PhpMyAdmin\Http\ServerRequest; +use PhpMyAdmin\DbTableExists; +use PhpMyAdmin\Http\Factory\ServerRequestFactory; use PhpMyAdmin\Table\ColumnsDefinition; use PhpMyAdmin\Template; use PhpMyAdmin\Tests\AbstractTestCase; @@ -249,8 +250,9 @@ class AddFieldControllerTest extends AbstractTestCase 'disable_is' => true, ]); - $request = $this->createStub(ServerRequest::class); - $request->method('getParsedBodyParam')->willReturnMap([['num_fields', null, '1']]); + $request = ServerRequestFactory::create()->createServerRequest('POST', 'http://example.com/') + ->withQueryParams(['db' => 'test_db', 'table' => 'test_table']) + ->withParsedBody(['num_fields' => '1']); $transformations = new Transformations(); (new AddFieldController( @@ -260,6 +262,7 @@ class AddFieldControllerTest extends AbstractTestCase $this->createConfig(), $dbi, new ColumnsDefinition($dbi, $relation, $transformations), + new DbTableExists($dbi), ))($request); $this->assertSame($expected, $response->getHTMLResult()); diff --git a/test/classes/Controllers/Table/ChangeControllerTest.php b/test/classes/Controllers/Table/ChangeControllerTest.php index f77df3bfe0..3f8ac70c68 100644 --- a/test/classes/Controllers/Table/ChangeControllerTest.php +++ b/test/classes/Controllers/Table/ChangeControllerTest.php @@ -7,8 +7,9 @@ namespace PhpMyAdmin\Tests\Controllers\Table; use PhpMyAdmin\Config\PageSettings; use PhpMyAdmin\ConfigStorage\Relation; use PhpMyAdmin\Controllers\Table\ChangeController; +use PhpMyAdmin\DbTableExists; use PhpMyAdmin\FileListing; -use PhpMyAdmin\Http\ServerRequest; +use PhpMyAdmin\Http\Factory\ServerRequestFactory; use PhpMyAdmin\InsertEdit; use PhpMyAdmin\Template; use PhpMyAdmin\Tests\AbstractTestCase; @@ -41,7 +42,8 @@ class ChangeControllerTest extends AbstractTestCase $pageSettings = new PageSettings(new UserPreferences($GLOBALS['dbi'])); $pageSettings->init('Edit'); - $request = $this->createStub(ServerRequest::class); + $request = ServerRequestFactory::create()->createServerRequest('GET', 'http://example.com/') + ->withQueryParams(['db' => 'test_db', 'table' => 'test_table']); $relation = new Relation($dbi); $template = new Template(); @@ -51,6 +53,7 @@ class ChangeControllerTest extends AbstractTestCase new InsertEdit($dbi, $relation, new Transformations(), new FileListing(), $template), $relation, $pageSettings, + new DbTableExists($dbi), ))($request); $actual = $response->getHTMLResult(); @@ -95,6 +98,7 @@ class ChangeControllerTest extends AbstractTestCase $this->createStub(InsertEdit::class), $this->createStub(Relation::class), $this->createStub(PageSettings::class), + new DbTableExists($this->createDatabaseInterface()), ); $whereClauseArray = ['foo=1', 'bar=2']; diff --git a/test/classes/Controllers/Table/ChartControllerTest.php b/test/classes/Controllers/Table/ChartControllerTest.php index a99943ee65..14a9229478 100644 --- a/test/classes/Controllers/Table/ChartControllerTest.php +++ b/test/classes/Controllers/Table/ChartControllerTest.php @@ -5,7 +5,8 @@ declare(strict_types=1); namespace PhpMyAdmin\Tests\Controllers\Table; use PhpMyAdmin\Controllers\Table\ChartController; -use PhpMyAdmin\Http\ServerRequest; +use PhpMyAdmin\DbTableExists; +use PhpMyAdmin\Http\Factory\ServerRequestFactory; use PhpMyAdmin\Template; use PhpMyAdmin\Tests\AbstractTestCase; use PhpMyAdmin\Tests\FieldHelper; @@ -92,7 +93,16 @@ class ChartControllerTest extends AbstractTestCase ], ]); - (new ChartController($response, $template, $dbi))($this->createStub(ServerRequest::class)); + $request = ServerRequestFactory::create()->createServerRequest('POST', 'http://example.com/') + ->withQueryParams(['db' => 'test_db', 'table' => 'table_for_chart']) + ->withParsedBody([ + 'printview' => '1', + 'sql_query' => 'SELECT * FROM `test_db`.`table_for_chart`;', + 'single_table' => 'true', + 'unlim_num_rows' => '4', + ]); + + (new ChartController($response, $template, $dbi, new DbTableExists($dbi)))($request); $this->assertSame($expected, $response->getHTMLResult()); } } diff --git a/test/classes/Controllers/Table/DeleteConfirmControllerTest.php b/test/classes/Controllers/Table/DeleteConfirmControllerTest.php index 6b9b10d579..76abb861d3 100644 --- a/test/classes/Controllers/Table/DeleteConfirmControllerTest.php +++ b/test/classes/Controllers/Table/DeleteConfirmControllerTest.php @@ -5,7 +5,8 @@ declare(strict_types=1); namespace PhpMyAdmin\Tests\Controllers\Table; use PhpMyAdmin\Controllers\Table\DeleteConfirmController; -use PhpMyAdmin\Http\ServerRequest; +use PhpMyAdmin\DbTableExists; +use PhpMyAdmin\Http\Factory\ServerRequestFactory; use PhpMyAdmin\Template; use PhpMyAdmin\Tests\AbstractTestCase; use PhpMyAdmin\Tests\Stubs\ResponseRenderer; @@ -42,7 +43,14 @@ class DeleteConfirmControllerTest extends AbstractTestCase 'is_foreign_key_check' => true, ]); - (new DeleteConfirmController($response, $template))($this->createStub(ServerRequest::class)); + $request = ServerRequestFactory::create()->createServerRequest('POST', 'http://example.com/') + ->withQueryParams(['db' => 'test_db', 'table' => 'test_table']) + ->withParsedBody([ + 'rows_to_delete' => ['`test_table`.`id` = 2', '`test_table`.`id` = 3'], + 'sql_query' => 'SELECT * FROM `test_db`.`test_table`', + ]); + + (new DeleteConfirmController($response, $template, new DbTableExists($dbi)))($request); $this->assertSame($expected, $response->getHTMLResult()); } } diff --git a/test/classes/Controllers/Table/DropColumnConfirmationControllerTest.php b/test/classes/Controllers/Table/DropColumnConfirmationControllerTest.php index 99add947d1..9f06afe79f 100644 --- a/test/classes/Controllers/Table/DropColumnConfirmationControllerTest.php +++ b/test/classes/Controllers/Table/DropColumnConfirmationControllerTest.php @@ -5,6 +5,7 @@ declare(strict_types=1); namespace PhpMyAdmin\Tests\Controllers\Table; use PhpMyAdmin\Controllers\Table\DropColumnConfirmationController; +use PhpMyAdmin\DbTableExists; use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\Template; use PhpMyAdmin\Tests\AbstractTestCase; @@ -46,7 +47,7 @@ class DropColumnConfirmationControllerTest extends AbstractTestCase 'fields' => ['name', 'datetimefield'], ]); - (new DropColumnConfirmationController($response, $template))($request); + (new DropColumnConfirmationController($response, $template, new DbTableExists($GLOBALS['dbi'])))($request); $this->assertSame(200, $response->getHttpResponseCode()); $this->assertTrue($response->hasSuccessState()); @@ -66,7 +67,7 @@ class DropColumnConfirmationControllerTest extends AbstractTestCase $response = new ResponseRenderer(); $response->setAjax(true); - (new DropColumnConfirmationController($response, new Template()))($request); + (new DropColumnConfirmationController($response, new Template(), new DbTableExists($GLOBALS['dbi'])))($request); $this->assertSame(400, $response->getHttpResponseCode()); $this->assertFalse($response->hasSuccessState()); @@ -86,7 +87,7 @@ class DropColumnConfirmationControllerTest extends AbstractTestCase $response = new ResponseRenderer(); $response->setAjax(true); - (new DropColumnConfirmationController($response, new Template()))($request); + (new DropColumnConfirmationController($response, new Template(), new DbTableExists($GLOBALS['dbi'])))($request); $this->assertSame(400, $response->getHttpResponseCode()); $this->assertFalse($response->hasSuccessState()); diff --git a/test/classes/Controllers/Table/FindReplaceControllerTest.php b/test/classes/Controllers/Table/FindReplaceControllerTest.php index f751002c4a..0a21698e23 100644 --- a/test/classes/Controllers/Table/FindReplaceControllerTest.php +++ b/test/classes/Controllers/Table/FindReplaceControllerTest.php @@ -6,6 +6,7 @@ namespace PhpMyAdmin\Tests\Controllers\Table; use PhpMyAdmin\Controllers\Table\FindReplaceController; use PhpMyAdmin\DatabaseInterface; +use PhpMyAdmin\DbTableExists; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\Template; use PhpMyAdmin\Tests\AbstractTestCase; @@ -67,6 +68,7 @@ class FindReplaceControllerTest extends AbstractTestCase ResponseRenderer::getInstance(), new Template(), $GLOBALS['dbi'], + new DbTableExists($GLOBALS['dbi']), ); $columnIndex = 0; $find = 'Field'; @@ -84,7 +86,12 @@ class FindReplaceControllerTest extends AbstractTestCase public function testReplaceWithRegex(): void { - $tableSearch = new FindReplaceController(ResponseRenderer::getInstance(), new Template(), $GLOBALS['dbi']); + $tableSearch = new FindReplaceController( + ResponseRenderer::getInstance(), + new Template(), + $GLOBALS['dbi'], + new DbTableExists($GLOBALS['dbi']), + ); $columnIndex = 0; $find = 'Field'; diff --git a/test/classes/Controllers/Table/GisVisualizationControllerTest.php b/test/classes/Controllers/Table/GisVisualizationControllerTest.php index 8e24874f22..9a0981c399 100644 --- a/test/classes/Controllers/Table/GisVisualizationControllerTest.php +++ b/test/classes/Controllers/Table/GisVisualizationControllerTest.php @@ -6,7 +6,8 @@ namespace PhpMyAdmin\Tests\Controllers\Table; use PhpMyAdmin\Controllers\Table\GisVisualizationController; use PhpMyAdmin\Core; -use PhpMyAdmin\Http\ServerRequest; +use PhpMyAdmin\DbTableExists; +use PhpMyAdmin\Http\Factory\ServerRequestFactory; use PhpMyAdmin\Template; use PhpMyAdmin\Tests\AbstractTestCase; use PhpMyAdmin\Tests\FieldHelper; @@ -104,8 +105,11 @@ class GisVisualizationControllerTest extends AbstractTestCase . 'return map;}', ]); + $request = ServerRequestFactory::create()->createServerRequest('POST', 'http://example.com/') + ->withQueryParams(['db' => 'test_db', 'table' => 'test_table']); + $response = new ResponseRenderer(); - (new GisVisualizationController($response, $template, $dbi))($this->createStub(ServerRequest::class)); + (new GisVisualizationController($response, $template, $dbi, new DbTableExists($dbi)))($request); $this->assertSame($expected, $response->getHTMLResult()); } } diff --git a/test/classes/Controllers/Table/ImportControllerTest.php b/test/classes/Controllers/Table/ImportControllerTest.php index edc6c0a4c8..c1a0bbb799 100644 --- a/test/classes/Controllers/Table/ImportControllerTest.php +++ b/test/classes/Controllers/Table/ImportControllerTest.php @@ -7,8 +7,9 @@ namespace PhpMyAdmin\Tests\Controllers\Table; use PhpMyAdmin\Charsets; use PhpMyAdmin\Config\PageSettings; use PhpMyAdmin\Controllers\Table\ImportController; +use PhpMyAdmin\DbTableExists; use PhpMyAdmin\Encoding; -use PhpMyAdmin\Http\ServerRequest; +use PhpMyAdmin\Http\Factory\ServerRequestFactory; use PhpMyAdmin\Plugins; use PhpMyAdmin\Template; use PhpMyAdmin\Tests\AbstractTestCase; @@ -84,8 +85,11 @@ class ImportControllerTest extends AbstractTestCase 'local_files' => '', ]); + $request = ServerRequestFactory::create()->createServerRequest('GET', 'http://example.com/') + ->withQueryParams(['db' => 'test_db', 'table' => 'test_table']); + $response = new ResponseRenderer(); - (new ImportController($response, $template, $dbi, $pageSettings))($this->createStub(ServerRequest::class)); + (new ImportController($response, $template, $dbi, $pageSettings, new DbTableExists($dbi)))($request); $this->assertSame($expected, $response->getHTMLResult()); } } diff --git a/test/classes/Controllers/Table/IndexRenameControllerTest.php b/test/classes/Controllers/Table/IndexRenameControllerTest.php index b88ab743ac..6d7f7a925a 100644 --- a/test/classes/Controllers/Table/IndexRenameControllerTest.php +++ b/test/classes/Controllers/Table/IndexRenameControllerTest.php @@ -5,7 +5,8 @@ declare(strict_types=1); namespace PhpMyAdmin\Tests\Controllers\Table; use PhpMyAdmin\Controllers\Table\IndexRenameController; -use PhpMyAdmin\Http\ServerRequest; +use PhpMyAdmin\DbTableExists; +use PhpMyAdmin\Http\Factory\ServerRequestFactory; use PhpMyAdmin\Index; use PhpMyAdmin\Table\Indexes; use PhpMyAdmin\Template; @@ -37,13 +38,17 @@ class IndexRenameControllerTest extends AbstractTestCase 'form_params' => ['db' => 'test_db', 'table' => 'test_table'], ]); + $request = ServerRequestFactory::create()->createServerRequest('GET', 'http://example.com/') + ->withQueryParams(['db' => 'test_db', 'table' => 'test_table']); + $response = new ResponseRenderer(); (new IndexRenameController( $response, $template, $dbi, new Indexes($response, $template, $dbi), - ))($this->createStub(ServerRequest::class)); + new DbTableExists($dbi), + ))($request); $this->assertSame($expected, $response->getHTMLResult()); } } diff --git a/test/classes/Controllers/Table/IndexesControllerTest.php b/test/classes/Controllers/Table/IndexesControllerTest.php index 3179efda85..9acfbbb785 100644 --- a/test/classes/Controllers/Table/IndexesControllerTest.php +++ b/test/classes/Controllers/Table/IndexesControllerTest.php @@ -6,6 +6,7 @@ namespace PhpMyAdmin\Tests\Controllers\Table; use PhpMyAdmin\Controllers\Table\IndexesController; use PhpMyAdmin\DatabaseInterface; +use PhpMyAdmin\DbTableExists; use PhpMyAdmin\Html\Generator; use PhpMyAdmin\Html\MySQLDocumentation; use PhpMyAdmin\Index; @@ -92,6 +93,7 @@ class IndexesControllerTest extends AbstractTestCase $template, $GLOBALS['dbi'], new Indexes($response, $template, $GLOBALS['dbi']), + new DbTableExists($GLOBALS['dbi']), ); $_POST['create_index'] = true; diff --git a/test/classes/Controllers/Table/OperationsControllerTest.php b/test/classes/Controllers/Table/OperationsControllerTest.php index 2cab611a81..d05dafbfa9 100644 --- a/test/classes/Controllers/Table/OperationsControllerTest.php +++ b/test/classes/Controllers/Table/OperationsControllerTest.php @@ -7,7 +7,7 @@ namespace PhpMyAdmin\Tests\Controllers\Table; use PhpMyAdmin\Charsets; use PhpMyAdmin\Controllers\Table\OperationsController; use PhpMyAdmin\DatabaseInterface; -use PhpMyAdmin\Http\ServerRequest; +use PhpMyAdmin\Http\Factory\ServerRequestFactory; use PhpMyAdmin\StorageEngine; use PhpMyAdmin\Template; use PhpMyAdmin\Tests\AbstractTestCase; @@ -119,9 +119,12 @@ class OperationsControllerTest extends AbstractTestCase 'foreigners' => [], ]); + $request = ServerRequestFactory::create()->createServerRequest('GET', 'http://example.com/') + ->withQueryParams(['db' => 'test_db', 'table' => 'test_table']); + /** @var OperationsController $controller */ $controller = $GLOBALS['containerBuilder']->get(OperationsController::class); - $controller($this->createStub(ServerRequest::class)); + $controller($request); $this->assertEquals($expectedOutput, $this->getResponseHtmlResult()); } diff --git a/test/classes/Controllers/Table/ReplaceControllerTest.php b/test/classes/Controllers/Table/ReplaceControllerTest.php index d2eb8715f5..a1eaccac05 100644 --- a/test/classes/Controllers/Table/ReplaceControllerTest.php +++ b/test/classes/Controllers/Table/ReplaceControllerTest.php @@ -13,7 +13,9 @@ use PhpMyAdmin\Controllers\Sql\SqlController; use PhpMyAdmin\Controllers\Table\ChangeController; use PhpMyAdmin\Controllers\Table\ReplaceController; use PhpMyAdmin\DatabaseInterface; +use PhpMyAdmin\DbTableExists; use PhpMyAdmin\FileListing; +use PhpMyAdmin\Http\Factory\ServerRequestFactory; use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\InsertEdit; use PhpMyAdmin\Operations; @@ -164,14 +166,19 @@ class ReplaceControllerTest extends AbstractTestCase $dbi, ); - $request = $this->createStub(ServerRequest::class); - $request->method('getParsedBodyParam')->willReturnMap([ - ['insert_rows', null, 5], - ['sql_query', '', 'SELECT 1'], - ]); + $request = ServerRequestFactory::create()->createServerRequest('POST', 'http://example.com/') + ->withQueryParams(['db' => 'my_db', 'table' => 'test_tbl']) + ->withParsedBody(['insert_rows' => '5', 'sql_query' => 'SELECT 1']); $pageSettings = $this->createStub(PageSettings::class); - $changeController = new ChangeController($response, $template, $insertEdit, $relation, $pageSettings); + $changeController = new ChangeController( + $response, + $template, + $insertEdit, + $relation, + $pageSettings, + new DbTableExists($dbi), + ); $GLOBALS['containerBuilder'] = $this->createStub(ContainerBuilder::class); $GLOBALS['containerBuilder']->method('get')->willReturn($changeController); diff --git a/test/classes/Controllers/Table/SearchControllerTest.php b/test/classes/Controllers/Table/SearchControllerTest.php index cab3625a54..526ff0b005 100644 --- a/test/classes/Controllers/Table/SearchControllerTest.php +++ b/test/classes/Controllers/Table/SearchControllerTest.php @@ -8,6 +8,7 @@ use PhpMyAdmin\ConfigStorage\Relation; use PhpMyAdmin\Controllers\Table\SearchController; use PhpMyAdmin\Core; use PhpMyAdmin\DatabaseInterface; +use PhpMyAdmin\DbTableExists; use PhpMyAdmin\Table\Search; use PhpMyAdmin\Template; use PhpMyAdmin\Tests\AbstractTestCase; @@ -110,6 +111,7 @@ class SearchControllerTest extends AbstractTestCase new Search($GLOBALS['dbi']), new Relation($GLOBALS['dbi']), $GLOBALS['dbi'], + new DbTableExists($GLOBALS['dbi']), ); $result = $ctrl->getColumnMinMax('column'); diff --git a/test/classes/Controllers/Table/SqlControllerTest.php b/test/classes/Controllers/Table/SqlControllerTest.php index fddc6b3032..9c462ff5f5 100644 --- a/test/classes/Controllers/Table/SqlControllerTest.php +++ b/test/classes/Controllers/Table/SqlControllerTest.php @@ -7,8 +7,9 @@ namespace PhpMyAdmin\Tests\Controllers\Table; use PhpMyAdmin\Config\PageSettings; use PhpMyAdmin\Controllers\Table\SqlController; use PhpMyAdmin\DatabaseInterface; +use PhpMyAdmin\DbTableExists; use PhpMyAdmin\Html\MySQLDocumentation; -use PhpMyAdmin\Http\ServerRequest; +use PhpMyAdmin\Http\Factory\ServerRequestFactory; use PhpMyAdmin\SqlQueryForm; use PhpMyAdmin\Template; use PhpMyAdmin\Tests\AbstractTestCase; @@ -79,12 +80,17 @@ class SqlControllerTest extends AbstractTestCase 'is_foreign_key_check' => true, ]); - $request = $this->createStub(ServerRequest::class); - $request->method('getParsedBodyParam')->willReturnMap([['delimiter', ';', ';']]); - $request->method('getQueryParam')->willReturnMap([['sql_query', true, true]]); + $request = ServerRequestFactory::create()->createServerRequest('GET', 'http://example.com/') + ->withQueryParams(['db' => 'test_db', 'table' => 'test_table']); $response = new ResponseRenderer(); - (new SqlController($response, $template, new SqlQueryForm($template, $this->dbi), $pageSettings))($request); + (new SqlController( + $response, + $template, + new SqlQueryForm($template, $this->dbi), + $pageSettings, + new DbTableExists($this->dbi), + ))($request); $this->assertSame($expected, $response->getHTMLResult()); } } diff --git a/test/classes/Controllers/Table/StructureControllerTest.php b/test/classes/Controllers/Table/StructureControllerTest.php index 7d5059a8ff..5474b7fe19 100644 --- a/test/classes/Controllers/Table/StructureControllerTest.php +++ b/test/classes/Controllers/Table/StructureControllerTest.php @@ -8,7 +8,8 @@ use PhpMyAdmin\Config\PageSettings; use PhpMyAdmin\ConfigStorage\Relation; use PhpMyAdmin\Controllers\Table\StructureController; use PhpMyAdmin\DatabaseInterface; -use PhpMyAdmin\Http\ServerRequest; +use PhpMyAdmin\DbTableExists; +use PhpMyAdmin\Http\Factory\ServerRequestFactory; use PhpMyAdmin\Index; use PhpMyAdmin\Template; use PhpMyAdmin\Tests\AbstractTestCase; @@ -82,8 +83,8 @@ class StructureControllerTest extends AbstractTestCase $pageSettings->init('TableStructure'); $fields = $this->dbi->getColumns($GLOBALS['db'], $GLOBALS['table'], true); - $request = $this->createStub(ServerRequest::class); - $request->method('getRoute')->willReturn('/table/structure'); + $request = ServerRequestFactory::create()->createServerRequest('GET', 'http://example.com/') + ->withQueryParams(['route' => '/table/structure', 'db' => 'test_db', 'table' => 'test_table']); $response = new ResponseRenderer(); $relation = new Relation($this->dbi); @@ -95,6 +96,7 @@ class StructureControllerTest extends AbstractTestCase new Transformations(), $this->dbi, $pageSettings, + new DbTableExists($this->dbi), ))($request); $expected = $pageSettings->getHTML(); diff --git a/test/classes/Controllers/Table/TrackingControllerTest.php b/test/classes/Controllers/Table/TrackingControllerTest.php index 90ababa125..2de9f1a282 100644 --- a/test/classes/Controllers/Table/TrackingControllerTest.php +++ b/test/classes/Controllers/Table/TrackingControllerTest.php @@ -7,7 +7,8 @@ namespace PhpMyAdmin\Tests\Controllers\Table; use PhpMyAdmin\ConfigStorage\Relation; use PhpMyAdmin\Controllers\Table\TrackingController; use PhpMyAdmin\DatabaseInterface; -use PhpMyAdmin\Http\ServerRequest; +use PhpMyAdmin\DbTableExists; +use PhpMyAdmin\Http\Factory\ServerRequestFactory; use PhpMyAdmin\SqlQueryForm; use PhpMyAdmin\Template; use PhpMyAdmin\Tests\AbstractTestCase; @@ -44,6 +45,9 @@ class TrackingControllerTest extends AbstractTestCase $this->dummyDbi->addSelectDb('test_db'); + $request = ServerRequestFactory::create()->createServerRequest('GET', 'http://example.com/') + ->withQueryParams(['db' => 'test_db', 'table' => 'test_table']); + $response = new ResponseRenderer(); $template = new Template(); $trackingChecker = $this->createStub(TrackingChecker::class); @@ -58,7 +62,8 @@ class TrackingControllerTest extends AbstractTestCase $trackingChecker, ), $trackingChecker, - ))($this->createStub(ServerRequest::class)); + new DbTableExists($this->dbi), + ))($request); $main = $template->render('table/tracking/main', [ 'url_params' => [ diff --git a/test/classes/Controllers/Table/ZoomSearchControllerTest.php b/test/classes/Controllers/Table/ZoomSearchControllerTest.php index 82baf22c01..b7542f2264 100644 --- a/test/classes/Controllers/Table/ZoomSearchControllerTest.php +++ b/test/classes/Controllers/Table/ZoomSearchControllerTest.php @@ -7,7 +7,8 @@ namespace PhpMyAdmin\Tests\Controllers\Table; use PhpMyAdmin\ConfigStorage\Relation; use PhpMyAdmin\Controllers\Table\ZoomSearchController; use PhpMyAdmin\DatabaseInterface; -use PhpMyAdmin\Http\ServerRequest; +use PhpMyAdmin\DbTableExists; +use PhpMyAdmin\Http\Factory\ServerRequestFactory; use PhpMyAdmin\Table\Search; use PhpMyAdmin\Template; use PhpMyAdmin\Tests\AbstractTestCase; @@ -42,6 +43,9 @@ class ZoomSearchControllerTest extends AbstractTestCase $this->dummyDbi->addSelectDb('test_db'); $this->dummyDbi->addResult('SHOW TABLES LIKE \'test_table\';', [['test_table']]); + $request = ServerRequestFactory::create()->createServerRequest('GET', 'http://example.com/') + ->withQueryParams(['db' => 'test_db', 'table' => 'test_table']); + $response = new ResponseRenderer(); $template = new Template(); $controller = new ZoomSearchController( @@ -50,8 +54,9 @@ class ZoomSearchControllerTest extends AbstractTestCase new Search($this->dbi), new Relation($this->dbi), $this->dbi, + new DbTableExists($this->dbi), ); - $controller($this->createStub(ServerRequest::class)); + $controller($request); $expected = $template->render('table/zoom_search/index', [ 'db' => $GLOBALS['db'], diff --git a/test/classes/Controllers/Triggers/IndexControllerTest.php b/test/classes/Controllers/Triggers/IndexControllerTest.php index 05800fe6e0..3f63034892 100644 --- a/test/classes/Controllers/Triggers/IndexControllerTest.php +++ b/test/classes/Controllers/Triggers/IndexControllerTest.php @@ -6,6 +6,8 @@ namespace PhpMyAdmin\Tests\Controllers\Triggers; use PhpMyAdmin\Controllers\Triggers\IndexController; use PhpMyAdmin\DatabaseInterface; +use PhpMyAdmin\DbTableExists; +use PhpMyAdmin\Http\Factory\ServerRequestFactory; use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\Template; use PhpMyAdmin\Tests\AbstractTestCase; @@ -48,12 +50,16 @@ final class IndexControllerTest extends AbstractTestCase $template = new Template(); $response = new ResponseRenderer(); + $request = ServerRequestFactory::create()->createServerRequest('GET', 'http://example.com/') + ->withQueryParams(['db' => 'test_db']); + (new IndexController( $response, $template, $dbi, new Triggers($dbi), - ))($this->createStub(ServerRequest::class)); + new DbTableExists($dbi), + ))($request); $actual = $response->getHTMLResult(); // phpcs:disable Generic.Files.LineLength.TooLong @@ -180,12 +186,16 @@ HTML; $template = new Template(); $response = new ResponseRenderer(); + $request = ServerRequestFactory::create()->createServerRequest('GET', 'http://example.com/') + ->withQueryParams(['db' => 'test_db']); + (new IndexController( $response, $template, $dbi, new Triggers($dbi), - ))($this->createStub(ServerRequest::class)); + new DbTableExists($dbi), + ))($request); $actual = $response->getHTMLResult(); // phpcs:disable Generic.Files.LineLength.TooLong @@ -266,6 +276,7 @@ HTML; $template, $dbi, new Triggers($dbi), + new DbTableExists($dbi), ); $request = $this->createStub(ServerRequest::class); diff --git a/test/classes/DbTableExistsTest.php b/test/classes/DbTableExistsTest.php new file mode 100644 index 0000000000..0c5f445537 --- /dev/null +++ b/test/classes/DbTableExistsTest.php @@ -0,0 +1,107 @@ +createDbiDummy(); + $dbiDummy->removeDefaultResults(); + $dbiDummy->addSelectDb('test_db'); + $dbi = $this->createDatabaseInterface($dbiDummy); + $dbTableExists = new DbTableExists($dbi); + $this->assertTrue($dbTableExists->hasDatabase(DatabaseName::from('test_db'))); + // cached result + $this->assertTrue($dbTableExists->hasDatabase(DatabaseName::from('test_db'))); + $dbiDummy->assertAllSelectsConsumed(); + } + + public function testHasDatabaseWithOutOfSyncError(): void + { + $db = DatabaseName::from('test_db'); + $dbi = $this->createMock(DatabaseInterface::class); + $dbi->expects($this->once())->method('selectDb')->with($db)->willReturn(false); + $dbi->expects($this->once())->method('getError')->willReturn('#2014 - Commands out of sync'); + $dbTableExists = new DbTableExists($dbi); + $this->assertTrue($dbTableExists->hasDatabase($db)); + // cached result + $this->assertTrue($dbTableExists->hasDatabase(DatabaseName::from('test_db'))); + } + + public function testHasDatabaseWithNoDatabase(): void + { + $db = DatabaseName::from('test_db'); + $dbi = $this->createMock(DatabaseInterface::class); + $dbi->expects($this->once())->method('selectDb')->with($db)->willReturn(false); + $dbi->expects($this->once())->method('getError')->willReturn('#1049 - Unknown database \'test_db\''); + $dbTableExists = new DbTableExists($dbi); + $this->assertFalse($dbTableExists->hasDatabase($db)); + } + + public function testHasTable(): void + { + $dbiDummy = $this->createDbiDummy(); + $dbiDummy->removeDefaultResults(); + $dbiDummy->addResult('SHOW TABLES LIKE \'test_table\';', [['test_table']], ['Tables_in_test_db (test_table)']); + $dbi = $this->createDatabaseInterface($dbiDummy); + $dbi->getCache()->clearTableCache(); + $dbTableExists = new DbTableExists($dbi); + $this->assertTrue($dbTableExists->hasTable(DatabaseName::from('test_db'), TableName::from('test_table'))); + $dbi->getCache()->clearTableCache(); + // cached result + $this->assertTrue($dbTableExists->hasTable(DatabaseName::from('test_db'), TableName::from('test_table'))); + $dbiDummy->assertAllQueriesConsumed(); + } + + public function testHasTableWithTempTable(): void + { + $dbiDummy = $this->createDbiDummy(); + $dbiDummy->removeDefaultResults(); + $dbiDummy->addResult('SHOW TABLES LIKE \'test_table\';', [], ['Tables_in_test_db (test_table)']); + $dbiDummy->addResult('SELECT 1 FROM `test_table` LIMIT 1;', [['1']], ['1']); + $dbi = $this->createDatabaseInterface($dbiDummy); + $dbi->getCache()->clearTableCache(); + $dbTableExists = new DbTableExists($dbi); + $this->assertTrue($dbTableExists->hasTable(DatabaseName::from('test_db'), TableName::from('test_table'))); + $dbi->getCache()->clearTableCache(); + // cached result + $this->assertTrue($dbTableExists->hasTable(DatabaseName::from('test_db'), TableName::from('test_table'))); + $dbiDummy->assertAllQueriesConsumed(); + } + + public function testHasTableWithDbiCache(): void + { + $dbiDummy = $this->createDbiDummy(); + $dbiDummy->removeDefaultResults(); + $dbi = $this->createDatabaseInterface($dbiDummy); + $dbi->getCache()->cacheTableContent(['test_db', 'test_table'], ['test_table']); + $dbTableExists = new DbTableExists($dbi); + $this->assertTrue($dbTableExists->hasTable(DatabaseName::from('test_db'), TableName::from('test_table'))); + $dbi->getCache()->clearTableCache(); + // cached result + $this->assertTrue($dbTableExists->hasTable(DatabaseName::from('test_db'), TableName::from('test_table'))); + } + + public function testHasTableWithNoTable(): void + { + $dbiDummy = $this->createDbiDummy(); + $dbiDummy->removeDefaultResults(); + $dbiDummy->addResult('SHOW TABLES LIKE \'test_table\';', false); + $dbiDummy->addResult('SELECT 1 FROM `test_table` LIMIT 1;', false); + $dbi = $this->createDatabaseInterface($dbiDummy); + $dbi->getCache()->clearTableCache(); + $dbTableExists = new DbTableExists($dbi); + $this->assertFalse($dbTableExists->hasTable(DatabaseName::from('test_db'), TableName::from('test_table'))); + $dbiDummy->assertAllQueriesConsumed(); + } +} diff --git a/test/classes/Plugins/Auth/AuthenticationHttpTest.php b/test/classes/Plugins/Auth/AuthenticationHttpTest.php index 00c0cc6a28..3168e3d541 100644 --- a/test/classes/Plugins/Auth/AuthenticationHttpTest.php +++ b/test/classes/Plugins/Auth/AuthenticationHttpTest.php @@ -192,8 +192,8 @@ class AuthenticationHttpTest extends AbstractNetworkTestCase $this->assertEquals($expectedPass, $this->object->password); - $_SERVER[$userIndex] = null; - $_SERVER[$passIndex] = null; + unset($_SERVER[$userIndex]); + unset($_SERVER[$passIndex]); } /**