diff --git a/libraries/classes/Controllers/AbstractController.php b/libraries/classes/Controllers/AbstractController.php index 8b3cf5818975..85ee1c014031 100644 --- a/libraries/classes/Controllers/AbstractController.php +++ b/libraries/classes/Controllers/AbstractController.php @@ -5,12 +5,14 @@ namespace PhpMyAdmin\Controllers; use PhpMyAdmin\Core; +use PhpMyAdmin\Html\MySQLDocumentation; use PhpMyAdmin\Message; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\Template; use PhpMyAdmin\Url; use function __; +use function basename; use function defined; use function strlen; @@ -101,4 +103,44 @@ protected function redirect(string $route, array $params = []): void $uri = './index.php?route=' . $route . Url::getCommonRaw($params, '&'); Core::sendHeaderLocation($uri); } + + /** + * Function added to avoid path disclosures. + * Called by each script that needs parameters, it displays + * an error message and, by default, stops the execution. + * + * @param bool $request Check parameters in request + * @psalm-param non-empty-list $params The names of the parameters needed by the calling script + */ + protected function checkParameters(array $params, bool $request = false): void + { + $reportedScriptName = basename($GLOBALS['PMA_PHP_SELF']); + $foundError = false; + $errorMessage = ''; + if ($request) { + $array = $_REQUEST; + } else { + $array = $GLOBALS; + } + + foreach ($params as $param) { + if (isset($array[$param]) && $array[$param] !== '') { + continue; + } + + $errorMessage .= $reportedScriptName + . ': ' . __('Missing parameter:') . ' ' + . $param + . MySQLDocumentation::showDocumentation('faq', 'faqmissingparameters', true) + . '[br]'; + $foundError = true; + } + + if (! $foundError) { + return; + } + + $this->response->setHttpResponseCode(400); + Core::fatalError($errorMessage); + } } diff --git a/libraries/classes/Controllers/Database/DataDictionaryController.php b/libraries/classes/Controllers/Database/DataDictionaryController.php index 8eb1aa0f8503..aaf7cd4cdeb2 100644 --- a/libraries/classes/Controllers/Database/DataDictionaryController.php +++ b/libraries/classes/Controllers/Database/DataDictionaryController.php @@ -42,7 +42,7 @@ public function __construct( public function __invoke(): void { - Util::checkParameters(['db'], true); + $this->checkParameters(['db'], true); $relationParameters = $this->relation->getRelationParameters(); diff --git a/libraries/classes/Controllers/Database/DesignerController.php b/libraries/classes/Controllers/Database/DesignerController.php index 7d7688d9f7b9..36184123a814 100644 --- a/libraries/classes/Controllers/Database/DesignerController.php +++ b/libraries/classes/Controllers/Database/DesignerController.php @@ -140,7 +140,7 @@ public function __invoke(): void return; } - Util::checkParameters(['db']); + $this->checkParameters(['db']); $GLOBALS['errorUrl'] = Util::getScriptNameForOption($GLOBALS['cfg']['DefaultTabDatabase'], 'database'); $GLOBALS['errorUrl'] .= Url::getCommon(['db' => $GLOBALS['db']], '&'); diff --git a/libraries/classes/Controllers/Database/EventsController.php b/libraries/classes/Controllers/Database/EventsController.php index 1ed8da239b05..2af8ac426497 100644 --- a/libraries/classes/Controllers/Database/EventsController.php +++ b/libraries/classes/Controllers/Database/EventsController.php @@ -38,7 +38,7 @@ public function __invoke(): void $this->addScriptFiles(['database/events.js']); if (! $this->response->isAjax()) { - Util::checkParameters(['db']); + $this->checkParameters(['db']); $GLOBALS['errorUrl'] = Util::getScriptNameForOption($GLOBALS['cfg']['DefaultTabDatabase'], 'database'); $GLOBALS['errorUrl'] .= Url::getCommon(['db' => $GLOBALS['db']], '&'); diff --git a/libraries/classes/Controllers/Database/ExportController.php b/libraries/classes/Controllers/Database/ExportController.php index f9fbe56224f1..2d8ee819f664 100644 --- a/libraries/classes/Controllers/Database/ExportController.php +++ b/libraries/classes/Controllers/Database/ExportController.php @@ -50,7 +50,7 @@ public function __invoke(): void // /database/export, in which case we don't obey $cfg['MaxTableList'] $GLOBALS['sub_part'] = '_export'; - Util::checkParameters(['db']); + $this->checkParameters(['db']); $GLOBALS['errorUrl'] = Util::getScriptNameForOption($GLOBALS['cfg']['DefaultTabDatabase'], 'database'); $GLOBALS['errorUrl'] .= Url::getCommon(['db' => $GLOBALS['db']], '&'); diff --git a/libraries/classes/Controllers/Database/ImportController.php b/libraries/classes/Controllers/Database/ImportController.php index 5e6da2daa130..7eabeeb28bee 100644 --- a/libraries/classes/Controllers/Database/ImportController.php +++ b/libraries/classes/Controllers/Database/ImportController.php @@ -42,7 +42,7 @@ public function __invoke(): void $this->addScriptFiles(['import.js']); - Util::checkParameters(['db']); + $this->checkParameters(['db']); $GLOBALS['errorUrl'] = Util::getScriptNameForOption($GLOBALS['cfg']['DefaultTabDatabase'], 'database'); $GLOBALS['errorUrl'] .= Url::getCommon(['db' => $GLOBALS['db']], '&'); diff --git a/libraries/classes/Controllers/Database/Operations/CollationController.php b/libraries/classes/Controllers/Database/Operations/CollationController.php index 07a8335546d2..7a033bd67097 100644 --- a/libraries/classes/Controllers/Database/Operations/CollationController.php +++ b/libraries/classes/Controllers/Database/Operations/CollationController.php @@ -47,7 +47,7 @@ public function __invoke(): void return; } - Util::checkParameters(['db']); + $this->checkParameters(['db']); $GLOBALS['errorUrl'] = Util::getScriptNameForOption($GLOBALS['cfg']['DefaultTabDatabase'], 'database'); $GLOBALS['errorUrl'] .= Url::getCommon(['db' => $GLOBALS['db']], '&'); diff --git a/libraries/classes/Controllers/Database/OperationsController.php b/libraries/classes/Controllers/Database/OperationsController.php index acb123b0cfb4..ae73086c3bd6 100644 --- a/libraries/classes/Controllers/Database/OperationsController.php +++ b/libraries/classes/Controllers/Database/OperationsController.php @@ -237,7 +237,7 @@ public function __invoke(): void $this->relation->setDbComment($GLOBALS['db'], $_POST['comment']); } - Util::checkParameters(['db']); + $this->checkParameters(['db']); $GLOBALS['errorUrl'] = Util::getScriptNameForOption($GLOBALS['cfg']['DefaultTabDatabase'], 'database'); $GLOBALS['errorUrl'] .= Url::getCommon(['db' => $GLOBALS['db']], '&'); diff --git a/libraries/classes/Controllers/Database/QueryByExampleController.php b/libraries/classes/Controllers/Database/QueryByExampleController.php index 9757b490b08b..75e5ae7e1395 100644 --- a/libraries/classes/Controllers/Database/QueryByExampleController.php +++ b/libraries/classes/Controllers/Database/QueryByExampleController.php @@ -132,7 +132,7 @@ public function __invoke(): void $GLOBALS['sub_part'] = '_qbe'; - Util::checkParameters(['db']); + $this->checkParameters(['db']); $GLOBALS['errorUrl'] = Util::getScriptNameForOption($GLOBALS['cfg']['DefaultTabDatabase'], 'database'); $GLOBALS['errorUrl'] .= Url::getCommon(['db' => $GLOBALS['db']], '&'); diff --git a/libraries/classes/Controllers/Database/RoutinesController.php b/libraries/classes/Controllers/Database/RoutinesController.php index 1f862fca14f6..7e5bb50cf0b0 100644 --- a/libraries/classes/Controllers/Database/RoutinesController.php +++ b/libraries/classes/Controllers/Database/RoutinesController.php @@ -52,7 +52,7 @@ public function __invoke(): void * Displays the header and tabs */ if (! empty($GLOBALS['table']) && in_array($GLOBALS['table'], $this->dbi->getTables($GLOBALS['db']))) { - Util::checkParameters(['db', 'table']); + $this->checkParameters(['db', 'table']); $GLOBALS['urlParams'] = ['db' => $GLOBALS['db'], 'table' => $GLOBALS['table']]; $GLOBALS['errorUrl'] = Util::getScriptNameForOption($GLOBALS['cfg']['DefaultTabTable'], 'table'); @@ -62,7 +62,7 @@ public function __invoke(): void } else { $GLOBALS['table'] = ''; - Util::checkParameters(['db']); + $this->checkParameters(['db']); $GLOBALS['errorUrl'] = Util::getScriptNameForOption($GLOBALS['cfg']['DefaultTabDatabase'], 'database'); $GLOBALS['errorUrl'] .= Url::getCommon(['db' => $GLOBALS['db']], '&'); diff --git a/libraries/classes/Controllers/Database/SearchController.php b/libraries/classes/Controllers/Database/SearchController.php index 42b94e08e1ea..383f436629ea 100644 --- a/libraries/classes/Controllers/Database/SearchController.php +++ b/libraries/classes/Controllers/Database/SearchController.php @@ -35,7 +35,7 @@ public function __invoke(): void 'makegrid.js', ]); - Util::checkParameters(['db']); + $this->checkParameters(['db']); $GLOBALS['errorUrl'] = Util::getScriptNameForOption($GLOBALS['cfg']['DefaultTabDatabase'], 'database'); $GLOBALS['errorUrl'] .= Url::getCommon(['db' => $GLOBALS['db']], '&'); diff --git a/libraries/classes/Controllers/Database/SqlController.php b/libraries/classes/Controllers/Database/SqlController.php index 15a47b805fe5..2d70d946730f 100644 --- a/libraries/classes/Controllers/Database/SqlController.php +++ b/libraries/classes/Controllers/Database/SqlController.php @@ -41,7 +41,7 @@ public function __invoke(): void $this->response->addHTML($pageSettings->getErrorHTML()); $this->response->addHTML($pageSettings->getHTML()); - Util::checkParameters(['db']); + $this->checkParameters(['db']); $GLOBALS['errorUrl'] = Util::getScriptNameForOption($GLOBALS['cfg']['DefaultTabDatabase'], 'database'); $GLOBALS['errorUrl'] .= Url::getCommon(['db' => $GLOBALS['db']], '&'); diff --git a/libraries/classes/Controllers/Database/Structure/FavoriteTableController.php b/libraries/classes/Controllers/Database/Structure/FavoriteTableController.php index 040d0eb00558..95d4caeced26 100644 --- a/libraries/classes/Controllers/Database/Structure/FavoriteTableController.php +++ b/libraries/classes/Controllers/Database/Structure/FavoriteTableController.php @@ -38,7 +38,7 @@ public function __invoke(): void 'sync_favorite_tables' => $_REQUEST['sync_favorite_tables'] ?? null, ]; - Util::checkParameters(['db']); + $this->checkParameters(['db']); $GLOBALS['errorUrl'] = Util::getScriptNameForOption($GLOBALS['cfg']['DefaultTabDatabase'], 'database'); $GLOBALS['errorUrl'] .= Url::getCommon(['db' => $GLOBALS['db']], '&'); diff --git a/libraries/classes/Controllers/Database/Structure/RealRowCountController.php b/libraries/classes/Controllers/Database/Structure/RealRowCountController.php index 40c0a876e4d5..19be7f2199bd 100644 --- a/libraries/classes/Controllers/Database/Structure/RealRowCountController.php +++ b/libraries/classes/Controllers/Database/Structure/RealRowCountController.php @@ -34,7 +34,7 @@ public function __invoke(): void 'table' => $_REQUEST['table'] ?? null, ]; - Util::checkParameters(['db']); + $this->checkParameters(['db']); $GLOBALS['errorUrl'] = Util::getScriptNameForOption($GLOBALS['cfg']['DefaultTabDatabase'], 'database'); $GLOBALS['errorUrl'] .= Url::getCommon(['db' => $GLOBALS['db']], '&'); diff --git a/libraries/classes/Controllers/Database/StructureController.php b/libraries/classes/Controllers/Database/StructureController.php index 76188b64f1df..f9742e358496 100644 --- a/libraries/classes/Controllers/Database/StructureController.php +++ b/libraries/classes/Controllers/Database/StructureController.php @@ -140,7 +140,7 @@ public function __invoke(): void 'sort_order' => $_REQUEST['sort_order'] ?? null, ]; - Util::checkParameters(['db']); + $this->checkParameters(['db']); $GLOBALS['errorUrl'] = Util::getScriptNameForOption($GLOBALS['cfg']['DefaultTabDatabase'], 'database'); $GLOBALS['errorUrl'] .= Url::getCommon(['db' => $GLOBALS['db']], '&'); diff --git a/libraries/classes/Controllers/Database/TrackingController.php b/libraries/classes/Controllers/Database/TrackingController.php index e4e6e6fe8c4b..9e0dec958f3e 100644 --- a/libraries/classes/Controllers/Database/TrackingController.php +++ b/libraries/classes/Controllers/Database/TrackingController.php @@ -47,7 +47,7 @@ public function __invoke(): void { $this->addScriptFiles(['vendor/jquery/jquery.tablesorter.js', 'database/tracking.js']); - Util::checkParameters(['db']); + $this->checkParameters(['db']); $GLOBALS['errorUrl'] = Util::getScriptNameForOption($GLOBALS['cfg']['DefaultTabDatabase'], 'database'); $GLOBALS['errorUrl'] .= Url::getCommon(['db' => $GLOBALS['db']], '&'); diff --git a/libraries/classes/Controllers/Database/TriggersController.php b/libraries/classes/Controllers/Database/TriggersController.php index fce9c863338f..434aa6f56317 100644 --- a/libraries/classes/Controllers/Database/TriggersController.php +++ b/libraries/classes/Controllers/Database/TriggersController.php @@ -39,7 +39,7 @@ public function __invoke(): void * Displays the header and tabs */ if (! empty($GLOBALS['table']) && in_array($GLOBALS['table'], $this->dbi->getTables($GLOBALS['db']))) { - Util::checkParameters(['db', 'table']); + $this->checkParameters(['db', 'table']); $GLOBALS['urlParams'] = ['db' => $GLOBALS['db'], 'table' => $GLOBALS['table']]; $GLOBALS['errorUrl'] = Util::getScriptNameForOption($GLOBALS['cfg']['DefaultTabTable'], 'table'); @@ -49,7 +49,7 @@ public function __invoke(): void } else { $GLOBALS['table'] = ''; - Util::checkParameters(['db']); + $this->checkParameters(['db']); $GLOBALS['errorUrl'] = Util::getScriptNameForOption($GLOBALS['cfg']['DefaultTabDatabase'], 'database'); $GLOBALS['errorUrl'] .= Url::getCommon(['db' => $GLOBALS['db']], '&'); diff --git a/libraries/classes/Controllers/Export/ExportController.php b/libraries/classes/Controllers/Export/ExportController.php index 8b99b1fa6175..269102d27acd 100644 --- a/libraries/classes/Controllers/Export/ExportController.php +++ b/libraries/classes/Controllers/Export/ExportController.php @@ -212,7 +212,7 @@ public function __invoke(ServerRequest $request): void $GLOBALS[$param] = $postParams[$param]; } - Util::checkParameters(['what', 'export_type']); + $this->checkParameters(['what', 'export_type']); // sanitize this parameter which will be used below in a file inclusion $GLOBALS['what'] = Core::securePath($whatParam); diff --git a/libraries/classes/Controllers/Import/ImportController.php b/libraries/classes/Controllers/Import/ImportController.php index 1e2fe4753ef8..e0cec17b5ff6 100644 --- a/libraries/classes/Controllers/Import/ImportController.php +++ b/libraries/classes/Controllers/Import/ImportController.php @@ -255,8 +255,7 @@ public function __invoke(): void Core::setPostAsGlobal($post_patterns); - // Check needed parameters - Util::checkParameters(['import_type', 'format']); + $this->checkParameters(['import_type', 'format']); // We don't want anything special in format $GLOBALS['format'] = Core::securePath($GLOBALS['format']); diff --git a/libraries/classes/Controllers/SchemaExportController.php b/libraries/classes/Controllers/SchemaExportController.php index f06306a95089..52c181cc3712 100644 --- a/libraries/classes/Controllers/SchemaExportController.php +++ b/libraries/classes/Controllers/SchemaExportController.php @@ -4,8 +4,11 @@ namespace PhpMyAdmin\Controllers; +use PhpMyAdmin\Core; use PhpMyAdmin\Export; -use PhpMyAdmin\Util; +use PhpMyAdmin\Html\MySQLDocumentation; + +use function __; /** * Schema export handler @@ -23,7 +26,12 @@ public function __construct(Export $export) public function __invoke(): void { if (! isset($_POST['export_type'])) { - Util::checkParameters(['export_type']); + $errorMessage = __('Missing parameter:') . ' export_type' + . MySQLDocumentation::showDocumentation('faq', 'faqmissingparameters', true) + . '[br]'; + Core::fatalError($errorMessage); + + return; } /** diff --git a/libraries/classes/Controllers/Sql/SqlController.php b/libraries/classes/Controllers/Sql/SqlController.php index 9826d86fe7b0..233383afbc8c 100644 --- a/libraries/classes/Controllers/Sql/SqlController.php +++ b/libraries/classes/Controllers/Sql/SqlController.php @@ -124,8 +124,7 @@ public function __invoke(): void // set $goto to what will be displayed if query returns 0 rows $GLOBALS['goto'] = ''; } else { - // Now we can check the parameters - Util::checkParameters(['sql_query']); + $this->checkParameters(['sql_query']); } /** diff --git a/libraries/classes/Controllers/Table/AddFieldController.php b/libraries/classes/Controllers/Table/AddFieldController.php index 1cd41d31ca1d..7007a800bdf9 100644 --- a/libraries/classes/Controllers/Table/AddFieldController.php +++ b/libraries/classes/Controllers/Table/AddFieldController.php @@ -61,8 +61,7 @@ public function __invoke(): void { $this->addScriptFiles(['table/structure.js']); - // Check parameters - Util::checkParameters(['db', 'table']); + $this->checkParameters(['db', 'table']); $cfg = $this->config->settings; @@ -178,6 +177,8 @@ public function __invoke(): void $this->addScriptFiles(['vendor/jquery/jquery.uitablefilter.js', 'indexes.js']); + $this->checkParameters(['server', 'db', 'table', 'num_fields']); + $templateData = $this->columnsDefinition->displayForm( '/table/add-field', $GLOBALS['num_fields'], diff --git a/libraries/classes/Controllers/Table/ChartController.php b/libraries/classes/Controllers/Table/ChartController.php index 90a73e447eaf..d5aa5bcb58b8 100644 --- a/libraries/classes/Controllers/Table/ChartController.php +++ b/libraries/classes/Controllers/Table/ChartController.php @@ -81,7 +81,7 @@ public function __invoke(): void * Runs common work */ if (strlen($GLOBALS['table']) > 0) { - Util::checkParameters(['db', 'table']); + $this->checkParameters(['db', 'table']); $url_params = ['db' => $GLOBALS['db'], 'table' => $GLOBALS['table']]; $GLOBALS['errorUrl'] = Util::getScriptNameForOption($GLOBALS['cfg']['DefaultTabTable'], 'table'); @@ -96,7 +96,7 @@ public function __invoke(): void $url_params['goto'] = Util::getScriptNameForOption($GLOBALS['cfg']['DefaultTabDatabase'], 'database'); $url_params['back'] = Url::getFromRoute('/sql'); - Util::checkParameters(['db']); + $this->checkParameters(['db']); $GLOBALS['errorUrl'] = Util::getScriptNameForOption($GLOBALS['cfg']['DefaultTabDatabase'], 'database'); $GLOBALS['errorUrl'] .= Url::getCommon(['db' => $GLOBALS['db']], '&'); @@ -168,7 +168,7 @@ public function __invoke(): void public function ajax(): void { if (strlen($GLOBALS['table']) > 0 && strlen($GLOBALS['db']) > 0) { - Util::checkParameters(['db', 'table']); + $this->checkParameters(['db', 'table']); $GLOBALS['urlParams'] = ['db' => $GLOBALS['db'], 'table' => $GLOBALS['table']]; $GLOBALS['errorUrl'] = Util::getScriptNameForOption($GLOBALS['cfg']['DefaultTabTable'], 'table'); diff --git a/libraries/classes/Controllers/Table/CreateController.php b/libraries/classes/Controllers/Table/CreateController.php index 0ccf154b061f..709874a8540a 100644 --- a/libraries/classes/Controllers/Table/CreateController.php +++ b/libraries/classes/Controllers/Table/CreateController.php @@ -15,7 +15,6 @@ use PhpMyAdmin\Template; use PhpMyAdmin\Transformations; use PhpMyAdmin\Url; -use PhpMyAdmin\Util; use function __; use function htmlspecialchars; @@ -58,7 +57,7 @@ public function __construct( public function __invoke(): void { - Util::checkParameters(['db']); + $this->checkParameters(['db']); $cfg = $this->config->settings; @@ -156,6 +155,8 @@ public function __invoke(): void $this->addScriptFiles(['vendor/jquery/jquery.uitablefilter.js', 'indexes.js']); + $this->checkParameters(['server', 'db', 'table', 'num_fields']); + $templateData = $this->columnsDefinition->displayForm('/table/create', $GLOBALS['num_fields']); $this->render('columns_definitions/column_definitions_form', $templateData); diff --git a/libraries/classes/Controllers/Table/DeleteConfirmController.php b/libraries/classes/Controllers/Table/DeleteConfirmController.php index da751966b492..c5ee9cfe5db3 100644 --- a/libraries/classes/Controllers/Table/DeleteConfirmController.php +++ b/libraries/classes/Controllers/Table/DeleteConfirmController.php @@ -26,7 +26,7 @@ public function __invoke(): void return; } - Util::checkParameters(['db', 'table']); + $this->checkParameters(['db', 'table']); $GLOBALS['urlParams'] = ['db' => $GLOBALS['db'], 'table' => $GLOBALS['table']]; $GLOBALS['errorUrl'] = Util::getScriptNameForOption($GLOBALS['cfg']['DefaultTabTable'], 'table'); diff --git a/libraries/classes/Controllers/Table/DropColumnConfirmationController.php b/libraries/classes/Controllers/Table/DropColumnConfirmationController.php index 8309fa71df58..e2c795e8ebee 100644 --- a/libraries/classes/Controllers/Table/DropColumnConfirmationController.php +++ b/libraries/classes/Controllers/Table/DropColumnConfirmationController.php @@ -24,7 +24,7 @@ public function __invoke(): void return; } - Util::checkParameters(['db', 'table']); + $this->checkParameters(['db', 'table']); $GLOBALS['urlParams'] = ['db' => $GLOBALS['db'], 'table' => $GLOBALS['table']]; $GLOBALS['errorUrl'] = Util::getScriptNameForOption($GLOBALS['cfg']['DefaultTabTable'], 'table'); diff --git a/libraries/classes/Controllers/Table/ExportController.php b/libraries/classes/Controllers/Table/ExportController.php index 81cb1224b185..8ab6d99bb5c0 100644 --- a/libraries/classes/Controllers/Table/ExportController.php +++ b/libraries/classes/Controllers/Table/ExportController.php @@ -44,7 +44,7 @@ public function __invoke(): void $this->addScriptFiles(['export.js']); - Util::checkParameters(['db', 'table']); + $this->checkParameters(['db', 'table']); $GLOBALS['urlParams'] = ['db' => $GLOBALS['db'], 'table' => $GLOBALS['table']]; $GLOBALS['errorUrl'] = Util::getScriptNameForOption($GLOBALS['cfg']['DefaultTabTable'], 'table'); diff --git a/libraries/classes/Controllers/Table/FindReplaceController.php b/libraries/classes/Controllers/Table/FindReplaceController.php index c49e9087106b..3029f235bce0 100644 --- a/libraries/classes/Controllers/Table/FindReplaceController.php +++ b/libraries/classes/Controllers/Table/FindReplaceController.php @@ -60,7 +60,7 @@ public function __construct( public function __invoke(): void { - Util::checkParameters(['db', 'table']); + $this->checkParameters(['db', 'table']); $GLOBALS['urlParams'] = ['db' => $GLOBALS['db'], 'table' => $GLOBALS['table']]; $GLOBALS['errorUrl'] = Util::getScriptNameForOption($GLOBALS['cfg']['DefaultTabTable'], 'table'); diff --git a/libraries/classes/Controllers/Table/GetFieldController.php b/libraries/classes/Controllers/Table/GetFieldController.php index c033e18f5248..a481bf03cd56 100644 --- a/libraries/classes/Controllers/Table/GetFieldController.php +++ b/libraries/classes/Controllers/Table/GetFieldController.php @@ -40,11 +40,7 @@ public function __invoke(): void { $this->response->disable(); - /* Check parameters */ - Util::checkParameters([ - 'db', - 'table', - ]); + $this->checkParameters(['db', 'table']); /* Select database */ if (! $this->dbi->selectDb($GLOBALS['db'])) { diff --git a/libraries/classes/Controllers/Table/GisVisualizationController.php b/libraries/classes/Controllers/Table/GisVisualizationController.php index 82ea0679464a..cfd37f3d40f7 100644 --- a/libraries/classes/Controllers/Table/GisVisualizationController.php +++ b/libraries/classes/Controllers/Table/GisVisualizationController.php @@ -41,7 +41,7 @@ public function __construct( public function __invoke(): void { - Util::checkParameters(['db']); + $this->checkParameters(['db']); $GLOBALS['errorUrl'] = Util::getScriptNameForOption($GLOBALS['cfg']['DefaultTabDatabase'], 'database'); $GLOBALS['errorUrl'] .= Url::getCommon(['db' => $GLOBALS['db']], '&'); diff --git a/libraries/classes/Controllers/Table/ImportController.php b/libraries/classes/Controllers/Table/ImportController.php index e156b3052eb9..4a2098eab3ea 100644 --- a/libraries/classes/Controllers/Table/ImportController.php +++ b/libraries/classes/Controllers/Table/ImportController.php @@ -46,7 +46,7 @@ public function __invoke(): void $this->addScriptFiles(['import.js']); - Util::checkParameters(['db', 'table']); + $this->checkParameters(['db', 'table']); $GLOBALS['urlParams'] = ['db' => $GLOBALS['db'], 'table' => $GLOBALS['table']]; $GLOBALS['errorUrl'] = Util::getScriptNameForOption($GLOBALS['cfg']['DefaultTabTable'], 'table'); diff --git a/libraries/classes/Controllers/Table/IndexRenameController.php b/libraries/classes/Controllers/Table/IndexRenameController.php index 8965ef6a56cb..38a74d96f057 100644 --- a/libraries/classes/Controllers/Table/IndexRenameController.php +++ b/libraries/classes/Controllers/Table/IndexRenameController.php @@ -38,7 +38,7 @@ public function __construct( public function __invoke(): void { if (! isset($_POST['create_edit_table'])) { - Util::checkParameters(['db', 'table']); + $this->checkParameters(['db', 'table']); $GLOBALS['urlParams'] = ['db' => $GLOBALS['db'], 'table' => $GLOBALS['table']]; $GLOBALS['errorUrl'] = Util::getScriptNameForOption($GLOBALS['cfg']['DefaultTabTable'], 'table'); diff --git a/libraries/classes/Controllers/Table/IndexesController.php b/libraries/classes/Controllers/Table/IndexesController.php index c2dd4f23962e..1ae9e531f3c0 100644 --- a/libraries/classes/Controllers/Table/IndexesController.php +++ b/libraries/classes/Controllers/Table/IndexesController.php @@ -45,7 +45,7 @@ public function __construct( public function __invoke(): void { if (! isset($_POST['create_edit_table'])) { - Util::checkParameters(['db', 'table']); + $this->checkParameters(['db', 'table']); $GLOBALS['urlParams'] = ['db' => $GLOBALS['db'], 'table' => $GLOBALS['table']]; $GLOBALS['errorUrl'] = Util::getScriptNameForOption($GLOBALS['cfg']['DefaultTabTable'], 'table'); diff --git a/libraries/classes/Controllers/Table/OperationsController.php b/libraries/classes/Controllers/Table/OperationsController.php index 509be58036af..cf2539e5023a 100644 --- a/libraries/classes/Controllers/Table/OperationsController.php +++ b/libraries/classes/Controllers/Table/OperationsController.php @@ -77,7 +77,7 @@ public function __invoke(): void $this->addScriptFiles(['table/operations.js']); - Util::checkParameters(['db', 'table']); + $this->checkParameters(['db', 'table']); $isSystemSchema = Utilities::isSystemSchema($GLOBALS['db']); $GLOBALS['urlParams'] = ['db' => $GLOBALS['db'], 'table' => $GLOBALS['table']]; diff --git a/libraries/classes/Controllers/Table/ReplaceController.php b/libraries/classes/Controllers/Table/ReplaceController.php index 07f0fed2023b..0f252fa80468 100644 --- a/libraries/classes/Controllers/Table/ReplaceController.php +++ b/libraries/classes/Controllers/Table/ReplaceController.php @@ -69,7 +69,7 @@ public function __construct( public function __invoke(): void { - Util::checkParameters(['db', 'table', 'goto']); + $this->checkParameters(['db', 'table', 'goto']); $this->dbi->selectDb($GLOBALS['db']); diff --git a/libraries/classes/Controllers/Table/SearchController.php b/libraries/classes/Controllers/Table/SearchController.php index 78c2600072be..3687b1756f33 100644 --- a/libraries/classes/Controllers/Table/SearchController.php +++ b/libraries/classes/Controllers/Table/SearchController.php @@ -171,7 +171,7 @@ private function loadTableInfo(): void */ public function __invoke(): void { - Util::checkParameters(['db', 'table']); + $this->checkParameters(['db', 'table']); $GLOBALS['urlParams'] = ['db' => $GLOBALS['db'], 'table' => $GLOBALS['table']]; $GLOBALS['errorUrl'] = Util::getScriptNameForOption($GLOBALS['cfg']['DefaultTabTable'], 'table'); diff --git a/libraries/classes/Controllers/Table/SqlController.php b/libraries/classes/Controllers/Table/SqlController.php index 6affce977721..8f6b98f031ed 100644 --- a/libraries/classes/Controllers/Table/SqlController.php +++ b/libraries/classes/Controllers/Table/SqlController.php @@ -45,7 +45,7 @@ public function __invoke(): void $this->response->addHTML($pageSettings->getErrorHTML()); $this->response->addHTML($pageSettings->getHTML()); - Util::checkParameters(['db', 'table']); + $this->checkParameters(['db', 'table']); $url_params = ['db' => $GLOBALS['db'], 'table' => $GLOBALS['table']]; $GLOBALS['errorUrl'] = Util::getScriptNameForOption($GLOBALS['cfg']['DefaultTabTable'], 'table'); diff --git a/libraries/classes/Controllers/Table/Structure/ChangeController.php b/libraries/classes/Controllers/Table/Structure/ChangeController.php index 5dfc76566abe..c70a2e523512 100644 --- a/libraries/classes/Controllers/Table/Structure/ChangeController.php +++ b/libraries/classes/Controllers/Table/Structure/ChangeController.php @@ -95,6 +95,8 @@ private function displayHtmlForColumnChange(?array $selected): void $this->addScriptFiles(['vendor/jquery/jquery.uitablefilter.js', 'indexes.js']); + $this->checkParameters(['server', 'db', 'table', 'num_fields']); + $templateData = $this->columnsDefinition->displayForm( '/table/structure/save', $GLOBALS['num_fields'], diff --git a/libraries/classes/Controllers/Table/Structure/PrimaryController.php b/libraries/classes/Controllers/Table/Structure/PrimaryController.php index a7a6fa5051e9..7ce9333069bc 100644 --- a/libraries/classes/Controllers/Table/Structure/PrimaryController.php +++ b/libraries/classes/Controllers/Table/Structure/PrimaryController.php @@ -58,7 +58,7 @@ public function __invoke(): void $mult_btn = $_POST['mult_btn'] ?? $mult_btn ?? ''; if (! empty($selected_fld) && ! empty($primary)) { - Util::checkParameters(['db', 'table']); + $this->checkParameters(['db', 'table']); $GLOBALS['urlParams'] = ['db' => $GLOBALS['db'], 'table' => $GLOBALS['table']]; $GLOBALS['errorUrl'] = Util::getScriptNameForOption($GLOBALS['cfg']['DefaultTabTable'], 'table'); diff --git a/libraries/classes/Controllers/Table/StructureController.php b/libraries/classes/Controllers/Table/StructureController.php index fd99cb9fadca..6fe98a43fb36 100644 --- a/libraries/classes/Controllers/Table/StructureController.php +++ b/libraries/classes/Controllers/Table/StructureController.php @@ -117,7 +117,7 @@ public function __invoke(): void $relationParameters = $this->relation->getRelationParameters(); - Util::checkParameters(['db', 'table']); + $this->checkParameters(['db', 'table']); $isSystemSchema = Utilities::isSystemSchema($GLOBALS['db']); $url_params = ['db' => $GLOBALS['db'], 'table' => $GLOBALS['table']]; diff --git a/libraries/classes/Controllers/Table/TrackingController.php b/libraries/classes/Controllers/Table/TrackingController.php index 62ce85815bde..b972bb26de18 100644 --- a/libraries/classes/Controllers/Table/TrackingController.php +++ b/libraries/classes/Controllers/Table/TrackingController.php @@ -42,7 +42,7 @@ public function __invoke(): void define('TABLE_MAY_BE_ABSENT', true); - Util::checkParameters(['db', 'table']); + $this->checkParameters(['db', 'table']); $GLOBALS['urlParams'] = ['db' => $GLOBALS['db'], 'table' => $GLOBALS['table']]; $GLOBALS['errorUrl'] = Util::getScriptNameForOption($GLOBALS['cfg']['DefaultTabTable'], 'table'); diff --git a/libraries/classes/Controllers/Table/TriggersController.php b/libraries/classes/Controllers/Table/TriggersController.php index 2a8e859281e3..773c1aad6397 100644 --- a/libraries/classes/Controllers/Table/TriggersController.php +++ b/libraries/classes/Controllers/Table/TriggersController.php @@ -42,7 +42,7 @@ public function __invoke(): void * Displays the header and tabs */ if (! empty($GLOBALS['table']) && in_array($GLOBALS['table'], $this->dbi->getTables($GLOBALS['db']))) { - Util::checkParameters(['db', 'table']); + $this->checkParameters(['db', 'table']); $GLOBALS['urlParams'] = ['db' => $GLOBALS['db'], 'table' => $GLOBALS['table']]; $GLOBALS['errorUrl'] = Util::getScriptNameForOption($GLOBALS['cfg']['DefaultTabTable'], 'table'); @@ -52,7 +52,7 @@ public function __invoke(): void } else { $GLOBALS['table'] = ''; - Util::checkParameters(['db']); + $this->checkParameters(['db']); $GLOBALS['errorUrl'] = Util::getScriptNameForOption($GLOBALS['cfg']['DefaultTabDatabase'], 'database'); $GLOBALS['errorUrl'] .= Url::getCommon(['db' => $GLOBALS['db']], '&'); diff --git a/libraries/classes/Controllers/Table/ZoomSearchController.php b/libraries/classes/Controllers/Table/ZoomSearchController.php index a5601a993580..d56216756288 100644 --- a/libraries/classes/Controllers/Table/ZoomSearchController.php +++ b/libraries/classes/Controllers/Table/ZoomSearchController.php @@ -94,7 +94,7 @@ public function __construct( public function __invoke(): void { - Util::checkParameters(['db', 'table']); + $this->checkParameters(['db', 'table']); $GLOBALS['urlParams'] = ['db' => $GLOBALS['db'], 'table' => $GLOBALS['table']]; $GLOBALS['errorUrl'] = Util::getScriptNameForOption($GLOBALS['cfg']['DefaultTabTable'], 'table'); diff --git a/libraries/classes/Controllers/View/CreateController.php b/libraries/classes/Controllers/View/CreateController.php index 023a5840eb75..b7a755a758e7 100644 --- a/libraries/classes/Controllers/View/CreateController.php +++ b/libraries/classes/Controllers/View/CreateController.php @@ -44,7 +44,7 @@ public function __construct(ResponseRenderer $response, Template $template, Data public function __invoke(): void { - Util::checkParameters(['db']); + $this->checkParameters(['db']); $GLOBALS['errorUrl'] = Util::getScriptNameForOption($GLOBALS['cfg']['DefaultTabDatabase'], 'database'); $GLOBALS['errorUrl'] .= Url::getCommon(['db' => $GLOBALS['db']], '&'); diff --git a/libraries/classes/Controllers/View/OperationsController.php b/libraries/classes/Controllers/View/OperationsController.php index e80eb24d7998..644cf89478b8 100644 --- a/libraries/classes/Controllers/View/OperationsController.php +++ b/libraries/classes/Controllers/View/OperationsController.php @@ -45,7 +45,7 @@ public function __invoke(): void $this->addScriptFiles(['table/operations.js']); - Util::checkParameters(['db', 'table']); + $this->checkParameters(['db', 'table']); $GLOBALS['urlParams'] = ['db' => $GLOBALS['db'], 'table' => $GLOBALS['table']]; $GLOBALS['errorUrl'] = Util::getScriptNameForOption($GLOBALS['cfg']['DefaultTabTable'], 'table'); diff --git a/libraries/classes/Table/ColumnsDefinition.php b/libraries/classes/Table/ColumnsDefinition.php index ca9002fd899e..535af8a89433 100644 --- a/libraries/classes/Table/ColumnsDefinition.php +++ b/libraries/classes/Table/ColumnsDefinition.php @@ -68,13 +68,6 @@ public function displayForm( ?array $selected = null, $fields_meta = null ): array { - Util::checkParameters([ - 'server', - 'db', - 'table', - 'num_fields', - ]); - $length_values_input_size = 8; $content_cells = []; $form_params = ['db' => $GLOBALS['db']]; diff --git a/libraries/classes/Util.php b/libraries/classes/Util.php index 12f84ca740c1..dbca164a0750 100644 --- a/libraries/classes/Util.php +++ b/libraries/classes/Util.php @@ -6,7 +6,6 @@ use PhpMyAdmin\Dbal\ResultInterface; use PhpMyAdmin\Html\Generator; -use PhpMyAdmin\Html\MySQLDocumentation; use PhpMyAdmin\Query\Utilities; use PhpMyAdmin\SqlParser\Components\Expression; use PhpMyAdmin\SqlParser\Context; @@ -22,7 +21,6 @@ use function array_merge; use function array_shift; use function array_unique; -use function basename; use function bin2hex; use function chr; use function count; @@ -800,46 +798,6 @@ public static function timespanFormat($seconds): string ); } - /** - * Function added to avoid path disclosures. - * Called by each script that needs parameters, it displays - * an error message and, by default, stops the execution. - * - * @param string[] $params The names of the parameters needed by the calling - * script - * @param bool $request Check parameters in request - */ - public static function checkParameters($params, $request = false): void - { - $reportedScriptName = basename($GLOBALS['PMA_PHP_SELF']); - $foundError = false; - $errorMessage = ''; - if ($request) { - $array = $_REQUEST; - } else { - $array = $GLOBALS; - } - - foreach ($params as $param) { - if (isset($array[$param])) { - continue; - } - - $errorMessage .= $reportedScriptName - . ': ' . __('Missing parameter:') . ' ' - . $param - . MySQLDocumentation::showDocumentation('faq', 'faqmissingparameters', true) - . '[br]'; - $foundError = true; - } - - if (! $foundError) { - return; - } - - Core::fatalError($errorMessage); - } - /** * Build a condition and with a value * diff --git a/test/classes/Controllers/AbstractControllerTest.php b/test/classes/Controllers/AbstractControllerTest.php new file mode 100644 index 000000000000..b56b9822bbd9 --- /dev/null +++ b/test/classes/Controllers/AbstractControllerTest.php @@ -0,0 +1,83 @@ + $params + */ + public function testCheckParameters(array $params): void + { + parent::checkParameters($params); + } + }; + + \PhpMyAdmin\ResponseRenderer::getInstance()->setAjax(false); + + $GLOBALS['param1'] = 'param1'; + $GLOBALS['param2'] = null; + + $message = 'index.php: Missing parameter: param2'; + $message .= MySQLDocumentation::showDocumentation('faq', 'faqmissingparameters', true); + $message .= '[br]'; + $expected = $template->render('error/generic', [ + 'lang' => 'en', + 'dir' => 'ltr', + 'error_message' => Sanitize::sanitizeMessage($message), + ]); + + $this->expectOutputString($expected); + + $controller->testCheckParameters(['param1', 'param2']); + + $this->assertSame(400, $response->getHttpResponseCode()); + } + + public function testCheckParametersWithAllParameters(): void + { + $_REQUEST = []; + + $response = new ResponseRenderer(); + $template = new Template(); + $controller = new class ($response, $template) extends AbstractController { + /** + * @psalm-param non-empty-list $params + */ + public function testCheckParameters(array $params): void + { + parent::checkParameters($params); + } + }; + + \PhpMyAdmin\ResponseRenderer::getInstance()->setAjax(false); + + $GLOBALS['param1'] = 'param1'; + $GLOBALS['param2'] = 'param2'; + + $this->expectOutputString(''); + + $controller->testCheckParameters(['param1', 'param2']); + + $this->assertSame(200, $response->getHttpResponseCode()); + } +} diff --git a/test/classes/UtilTest.php b/test/classes/UtilTest.php index beedb613e6b3..7ca5bb9d0b1a 100644 --- a/test/classes/UtilTest.php +++ b/test/classes/UtilTest.php @@ -4,11 +4,9 @@ namespace PhpMyAdmin\Tests; -use PhpMyAdmin\Core; use PhpMyAdmin\DatabaseInterface; use PhpMyAdmin\FieldMetadata; use PhpMyAdmin\MoTranslator\Loader; -use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\SqlParser\Context; use PhpMyAdmin\SqlParser\Token; use PhpMyAdmin\Util; @@ -334,52 +332,6 @@ public function testClearUserCache(): void $this->assertArrayNotHasKey('is_superuser', $_SESSION['cache']['server_server']); } - public function testCheckParameterMissing(): void - { - parent::setGlobalConfig(); - $_REQUEST = []; - $GLOBALS['text_dir'] = 'ltr'; - $GLOBALS['PMA_PHP_SELF'] = Core::getenv('PHP_SELF'); - $GLOBALS['db'] = 'db'; - $GLOBALS['table'] = 'table'; - $GLOBALS['server'] = 1; - $GLOBALS['cfg']['ServerDefault'] = 1; - $GLOBALS['cfg']['AllowThirdPartyFraming'] = false; - ResponseRenderer::getInstance()->setAjax(false); - - $this->expectOutputRegex('/Missing parameter: field/'); - - Util::checkParameters( - [ - 'db', - 'table', - 'field', - ] - ); - } - - public function testCheckParameter(): void - { - parent::setGlobalConfig(); - $GLOBALS['cfg'] = ['ServerDefault' => 1]; - $GLOBALS['text_dir'] = 'ltr'; - $GLOBALS['PMA_PHP_SELF'] = Core::getenv('PHP_SELF'); - $GLOBALS['db'] = 'dbDatabase'; - $GLOBALS['table'] = 'tblTable'; - $GLOBALS['field'] = 'test_field'; - $GLOBALS['sql_query'] = 'SELECT * FROM tblTable;'; - - $this->expectOutputString(''); - Util::checkParameters( - [ - 'db', - 'table', - 'field', - 'sql_query', - ] - ); - } - /** * Test for Util::convertBitDefaultValue *