diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 8afed57932..08bbde4493 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -8275,9 +8275,14 @@ parameters: count: 5 path: src/Html/Generator.php + - + message: "#^Cannot cast mixed to string\\.$#" + count: 2 + path: src/Html/Generator.php + - message: "#^Construct empty\\(\\) is not allowed\\. Use more strict comparison\\.$#" - count: 16 + count: 14 path: src/Html/Generator.php - @@ -8310,46 +8315,16 @@ parameters: count: 2 path: src/Html/Generator.php - - - message: "#^Parameter \\#1 \\$sqlQuery of static method PhpMyAdmin\\\\Html\\\\Generator\\:\\:formatSql\\(\\) expects string, mixed given\\.$#" - count: 1 - path: src/Html/Generator.php - - - - message: "#^Parameter \\#1 \\$string of function addslashes expects string, mixed given\\.$#" - count: 1 - path: src/Html/Generator.php - - message: "#^Parameter \\#1 \\$string of function htmlspecialchars expects string, \\(int\\|string\\) given\\.$#" count: 1 path: src/Html/Generator.php - - - message: "#^Parameter \\#1 \\$string of function htmlspecialchars expects string, mixed given\\.$#" - count: 1 - path: src/Html/Generator.php - - - - message: "#^Parameter \\#1 \\$string of function mb_strlen expects string, mixed given\\.$#" - count: 1 - path: src/Html/Generator.php - - - - message: "#^Parameter \\#1 \\$string of function mb_substr expects string, mixed given\\.$#" - count: 2 - path: src/Html/Generator.php - - message: "#^Parameter \\#1 \\$string of function trim expects string, mixed given\\.$#" count: 1 path: src/Html/Generator.php - - - message: "#^Parameter \\#2 \\$subject of function preg_match expects string, mixed given\\.$#" - count: 3 - path: src/Html/Generator.php - - message: "#^Parameter \\#2 \\.\\.\\.\\$values of function sprintf expects bool\\|float\\|int\\|string\\|null, mixed given\\.$#" count: 1 @@ -8540,11 +8515,6 @@ parameters: count: 1 path: src/Import/Import.php - - - message: "#^Only booleans are allowed in an if condition, string\\|false given\\.$#" - count: 1 - path: src/Import/Import.php - - message: "#^Parameter \\#1 \\$precision of static method PhpMyAdmin\\\\Import\\\\DecimalSize\\:\\:fromPrecisionAndScale\\(\\) expects int, int\\|PhpMyAdmin\\\\Import\\\\DecimalSize given\\.$#" count: 1 diff --git a/psalm-baseline.xml b/psalm-baseline.xml index bc9108fd4d..e62dc975c4 100644 --- a/psalm-baseline.xml +++ b/psalm-baseline.xml @@ -6598,6 +6598,10 @@ + + + + @@ -6608,7 +6612,6 @@ - @@ -6727,7 +6730,6 @@ - diff --git a/psalm.xml b/psalm.xml index 992652ebab..a1b5ac3433 100644 --- a/psalm.xml +++ b/psalm.xml @@ -111,7 +111,6 @@ tbl_storage_engine: string, token_mismatch: bool, token_provided: bool, - unparsed_sql?: string, urlParams: array, username: string, xml_export_triggers: bool, diff --git a/src/Controllers/Import/ImportController.php b/src/Controllers/Import/ImportController.php index c68169b181..80cbd73c90 100644 --- a/src/Controllers/Import/ImportController.php +++ b/src/Controllers/Import/ImportController.php @@ -679,6 +679,13 @@ final class ImportController implements InvocableController return null; } + if ($request->hasBodyParam('rollback_query')) { + // We rollback because there might be other queries that need to be executed after this, + // e.g. creation of a bookmark. + $this->dbi->query('ROLLBACK'); + ImportSettings::$message .= __('[ROLLBACK occurred.]'); + } + if ($GLOBALS['result']) { // Save a Bookmark with more than one queries (if Bookmark label given). if (! empty($request->getParsedBodyParam('bkm_label')) && ! empty($GLOBALS['import_text'])) { @@ -708,13 +715,6 @@ final class ImportController implements InvocableController include ROOT_PATH . $GLOBALS['goto']; } - // If there is request for ROLLBACK in the end. - if (! $request->hasBodyParam('rollback_query')) { - return null; - } - - $this->dbi->query('ROLLBACK'); - return null; } } diff --git a/src/Html/Generator.php b/src/Html/Generator.php index 75b81a8fda..01f8f8997c 100644 --- a/src/Html/Generator.php +++ b/src/Html/Generator.php @@ -407,18 +407,16 @@ class Generator if ($sqlQuery === null) { if (! empty($GLOBALS['display_query'])) { - $sqlQuery = $GLOBALS['display_query']; - } elseif (! empty($GLOBALS['unparsed_sql'])) { - $sqlQuery = $GLOBALS['unparsed_sql']; + $sqlQuery = (string) $GLOBALS['display_query']; } elseif (! empty($GLOBALS['sql_query'])) { - $sqlQuery = $GLOBALS['sql_query']; + $sqlQuery = (string) $GLOBALS['sql_query']; } else { $sqlQuery = ''; } } $config = Config::getInstance(); - $renderSql = $config->settings['ShowSQL'] == true && ! empty($sqlQuery) && $sqlQuery !== ';'; + $renderSql = $config->settings['ShowSQL'] == true && $sqlQuery !== '' && $sqlQuery !== ';'; if (isset($GLOBALS['using_bookmark_message'])) { $retval .= $GLOBALS['using_bookmark_message']->getDisplay(); @@ -455,34 +453,19 @@ class Generator $retval .= ' ' . $message->getMessage() . "\n"; $retval .= '' . "\n"; - $queryTooBig = false; - - $queryLength = mb_strlen($sqlQuery); - if ($queryLength > $config->settings['MaxCharactersInDisplayedSQL']) { - // when the query is large (for example an INSERT of binary - // data), the parser chokes; so avoid parsing the query - $queryTooBig = true; - $queryBase = mb_substr($sqlQuery, 0, $config->settings['MaxCharactersInDisplayedSQL']) . '[...]'; - } else { - $queryBase = $sqlQuery; - } - // Html format the query to be displayed // If we want to show some sql code it is easiest to create it here /* SQL-Parser-Analyzer */ if (! empty($GLOBALS['show_as_php'])) { $newLine = '\\n"
' . "\n" . '    . "'; - $queryBase = htmlspecialchars(addslashes($queryBase)); + $queryBase = htmlspecialchars(addslashes($sqlQuery)); $queryBase = preg_replace('/((\015\012)|(\015)|(\012))/', $newLine, $queryBase); $queryBase = '
' . "\n"
                 . '$sql = "' . $queryBase . '";' . "\n"
                 . '
'; - } elseif ($queryTooBig) { - $queryBase = '
' . "\n"
-                . htmlspecialchars($queryBase, ENT_COMPAT) . '
'; } else { - $queryBase = self::formatSql($queryBase); + $queryBase = self::formatSql($sqlQuery, true); } // Prepares links that may be displayed to edit/explain the query @@ -507,6 +490,7 @@ class Generator // but only explain a SELECT (that has not been explained) /* SQL-Parser-Analyzer */ $explainLink = ''; + $queryTooBig = mb_strlen($sqlQuery) > $config->settings['MaxCharactersInDisplayedSQL']; $isSelect = preg_match('@^SELECT[[:space:]]+@i', $sqlQuery); if (! empty($config->settings['SQLQuery']['Explain']) && ! $queryTooBig) { $explainParams = $urlParams; @@ -1085,8 +1069,6 @@ class Generator * @param bool $truncate truncate the query if it is too long * * @return string the formatted sql - * - * @global array $cfg the configuration array */ public static function formatSql(string $sqlQuery, bool $truncate = false): string { diff --git a/src/Import/Import.php b/src/Import/Import.php index 19a20a8d2b..dfef41c653 100644 --- a/src/Import/Import.php +++ b/src/Import/Import.php @@ -240,13 +240,6 @@ class Import // Do we have something to push into buffer? $this->importRunBuffer = $sql !== '' ? $sql . ';' : null; - - // In case of ROLLBACK, notify the user. - if (! isset($_POST['rollback_query'])) { - return; - } - - ImportSettings::$message .= __('[ROLLBACK occurred.]'); } /** @@ -928,20 +921,10 @@ class Import ImportSettings::$importNotice = $message; } - /** - * Handles request for ROLLBACK. - * - * @param string $sqlQuery SQL query(s) - */ public function handleRollbackRequest(string $sqlQuery): void { $sqlDelimiter = $_POST['sql_delimiter']; $queries = explode($sqlDelimiter, $sqlQuery); - $error = false; - $errorMsg = __( - 'Only INSERT, UPDATE, DELETE and REPLACE ' - . 'SQL queries containing transactional engine tables can be rolled back.', - ); $dbi = DatabaseInterface::getInstance(); foreach ($queries as $sqlQuery) { if ($sqlQuery === '') { @@ -953,17 +936,14 @@ class Import continue; } - $globalError = $dbi->getError(); - $error = $globalError !== '' ? $globalError : $errorMsg; + $sqlError = $dbi->getError(); + $error = $sqlError !== '' ? $sqlError : __( + 'Only INSERT, UPDATE, DELETE and REPLACE ' + . 'SQL queries containing transactional engine tables can be rolled back.', + ); - break; - } - - if ($error) { - unset($_POST['rollback_query']); $response = ResponseRenderer::getInstance(); - $message = Message::rawError($error); - $response->addJSON('message', $message); + $response->addJSON('message', Message::rawError($error)); $response->callExit(); } diff --git a/src/ParseAnalyze.php b/src/ParseAnalyze.php index 948d4a8d35..61e88e3b65 100644 --- a/src/ParseAnalyze.php +++ b/src/ParseAnalyze.php @@ -26,9 +26,6 @@ class ParseAnalyze */ public static function sqlQuery(string $sqlQuery, string $db): array { - // @todo: move to returned results (also in all the calling chain) - $GLOBALS['unparsed_sql'] = $sqlQuery; - $info = Query::getAll($sqlQuery); $table = ''; diff --git a/tests/unit/Html/GeneratorTest.php b/tests/unit/Html/GeneratorTest.php index 97badffb91..390deba9b4 100644 --- a/tests/unit/Html/GeneratorTest.php +++ b/tests/unit/Html/GeneratorTest.php @@ -476,7 +476,6 @@ class GeneratorTest extends AbstractTestCase { Config::getInstance()->settings['ShowSQL'] = true; $GLOBALS['display_query'] = null; - $GLOBALS['unparsed_sql'] = null; $GLOBALS['sql_query'] = 'SELECT 1;'; $usingBookmarkMessage = Message::notice('Bookmark message'); $GLOBALS['using_bookmark_message'] = $usingBookmarkMessage; @@ -533,7 +532,6 @@ HTML; $config->settings['SQLQuery']['Edit'] = false; $config->settings['SQLQuery']['Refresh'] = true; $GLOBALS['display_query'] = 'EXPLAIN SELECT 1;'; - $GLOBALS['unparsed_sql'] = null; $GLOBALS['sql_query'] = null; DatabaseInterface::$instance = $this->createDatabaseInterface(); Current::$database = 'test_db'; diff --git a/tests/unit/ParseAnalyzeTest.php b/tests/unit/ParseAnalyzeTest.php index 0de673be2d..8019facfdb 100644 --- a/tests/unit/ParseAnalyzeTest.php +++ b/tests/unit/ParseAnalyzeTest.php @@ -24,12 +24,8 @@ class ParseAnalyzeTest extends AbstractTestCase $GLOBALS['lang'] = 'en'; ResponseRenderer::getInstance()->setAjax(false); - $GLOBALS['unparsed_sql'] = ''; - $actual = ParseAnalyze::sqlQuery('SELECT * FROM `sakila`.`actor`', 'sakila_test'); - /** @psalm-suppress TypeDoesNotContainType */ - self::assertSame('SELECT * FROM `sakila`.`actor`', $GLOBALS['unparsed_sql']); self::assertSame('sakila', $actual[1]); self::assertSame('actor', $actual[2]); self::assertTrue($actual[0]->flags->reload); @@ -44,12 +40,8 @@ class ParseAnalyzeTest extends AbstractTestCase $GLOBALS['lang'] = 'en'; ResponseRenderer::getInstance()->setAjax(false); - $GLOBALS['unparsed_sql'] = ''; - $actual = ParseAnalyze::sqlQuery('SELECT `first_name`, `title` FROM `actor`, `film`', 'sakila'); - /** @psalm-suppress TypeDoesNotContainType */ - self::assertSame('SELECT `first_name`, `title` FROM `actor`, `film`', $GLOBALS['unparsed_sql']); self::assertSame('sakila', $actual[1]); self::assertSame('', $actual[2]); self::assertFalse($actual[0]->flags->reload);