From ad2908a775519c3f24e956a30576cceca31e24a9 Mon Sep 17 00:00:00 2001 From: khushal_b_patel Date: Mon, 12 Jan 2026 11:51:38 +0530 Subject: [PATCH 01/52] fix: reset stale grid edit state after AJAX refresh Signed-off-by: Khushal Patel --- js/src/makegrid.js | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/js/src/makegrid.js b/js/src/makegrid.js index 4fb677d676..4f10bcc07d 100644 --- a/js/src/makegrid.js +++ b/js/src/makegrid.js @@ -280,6 +280,20 @@ var makeGrid = function (t, enableResize, enableReorder, enableVisib, enableGrid $(g.cRsz).css('height', $(g.t).height()); }, + /** + * Clears the current cell edit state, internal flags, + * and any pending save request. + */ + resetGridEditState: function () { + g.isCellEditActive = false; + g.isEditCellTextEditable = false; + g.currentEditCell = null; + g.wasEditedCellNull = false; + g.isCellEdited = false; + g.isSaving = false; + g.lastXHR = null; + }, + /** * Shift column from index oldn to newn. * @@ -2305,6 +2319,11 @@ var makeGrid = function (t, enableResize, enableReorder, enableVisib, enableGrid // some adjustment $(t).removeClass('data'); $(g.gDiv).addClass('data'); + + /* Store the grid controller instance on the table element so it can be accessed later by other modules + (e.g. during AJAX teardown) without exposing the grid object as a global variable.*/ + $(t).data('pmaGrid', g); + }; /** From b8db145e4bbf5a138d3706d08263302f5123347d Mon Sep 17 00:00:00 2001 From: khushal_b_patel Date: Mon, 12 Jan 2026 11:53:23 +0530 Subject: [PATCH 02/52] fix: clear grid edit state during table teardown Signed-off-by: Khushal Patel --- js/src/table/change.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/js/src/table/change.js b/js/src/table/change.js index a44b02140d..91b6631e49 100644 --- a/js/src/table/change.js +++ b/js/src/table/change.js @@ -450,6 +450,14 @@ AJAX.registerTeardown('table/change.js', function () { $(document).off('click', 'input.checkbox_null'); $('select[name="submit_type"]').off('change'); $(document).off('change', '#insert_rows'); + + // Reset grid edit state + $('table').each(function () { + var grid = $(this).data('pmaGrid'); + if (grid && typeof grid.resetGridEditState === 'function') { + grid.resetGridEditState(); + } + }); }); /** From c8a226e71c12efc9d77e0f24c63c9ff38d050fe6 Mon Sep 17 00:00:00 2001 From: Khushal Patel Date: Mon, 12 Jan 2026 20:50:37 +0530 Subject: [PATCH 03/52] style: removed trailing spaces Signed-off-by: Khushal Patel --- js/src/makegrid.js | 4 +--- js/src/table/change.js | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/js/src/makegrid.js b/js/src/makegrid.js index 4f10bcc07d..a071843d9d 100644 --- a/js/src/makegrid.js +++ b/js/src/makegrid.js @@ -2319,11 +2319,9 @@ var makeGrid = function (t, enableResize, enableReorder, enableVisib, enableGrid // some adjustment $(t).removeClass('data'); $(g.gDiv).addClass('data'); - - /* Store the grid controller instance on the table element so it can be accessed later by other modules + /* Store the grid controller instance on the table element so it can be accessed later by other modules (e.g. during AJAX teardown) without exposing the grid object as a global variable.*/ $(t).data('pmaGrid', g); - }; /** diff --git a/js/src/table/change.js b/js/src/table/change.js index 91b6631e49..79ca0f982a 100644 --- a/js/src/table/change.js +++ b/js/src/table/change.js @@ -450,7 +450,7 @@ AJAX.registerTeardown('table/change.js', function () { $(document).off('click', 'input.checkbox_null'); $('select[name="submit_type"]').off('change'); $(document).off('change', '#insert_rows'); - + // Reset grid edit state $('table').each(function () { var grid = $(this).data('pmaGrid'); From 768396625c844fe05b6a992f7800539afadd9598 Mon Sep 17 00:00:00 2001 From: Liviu-Mihail Concioiu Date: Sat, 7 Feb 2026 21:39:03 +0100 Subject: [PATCH 04/52] Add Refresh button for EXPLAIN queries Signed-off-by: Liviu-Mihail Concioiu --- libraries/classes/Html/Generator.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/classes/Html/Generator.php b/libraries/classes/Html/Generator.php index 85908aebbc..15cdb678f7 100644 --- a/libraries/classes/Html/Generator.php +++ b/libraries/classes/Html/Generator.php @@ -655,7 +655,7 @@ class Generator if ( ! empty($cfg['SQLQuery']['Refresh']) && ! isset($GLOBALS['show_as_php']) // 'Submit query' does the same - && preg_match('@^(SELECT|SHOW)[[:space:]]+@i', $sqlQuery) + && preg_match('@^(EXPLAIN|SELECT|SHOW)[[:space:]]+@i', $sqlQuery) ) { $refreshLink = Url::getFromRoute('/sql', $urlParams); $refreshLink = ' [ ' From 0b5cb47dae8b01d7a2688ad6d0448a89ecc08dbf Mon Sep 17 00:00:00 2001 From: Liviu-Mihail Concioiu Date: Sat, 7 Feb 2026 22:19:07 +0100 Subject: [PATCH 05/52] Add Refresh button for ANALYZE queries Signed-off-by: Liviu-Mihail Concioiu --- libraries/classes/Html/Generator.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/classes/Html/Generator.php b/libraries/classes/Html/Generator.php index 15cdb678f7..1d6630396f 100644 --- a/libraries/classes/Html/Generator.php +++ b/libraries/classes/Html/Generator.php @@ -655,7 +655,7 @@ class Generator if ( ! empty($cfg['SQLQuery']['Refresh']) && ! isset($GLOBALS['show_as_php']) // 'Submit query' does the same - && preg_match('@^(EXPLAIN|SELECT|SHOW)[[:space:]]+@i', $sqlQuery) + && preg_match('@^(ANALYZE|EXPLAIN|SELECT|SHOW)[[:space:]]+@i', $sqlQuery) ) { $refreshLink = Url::getFromRoute('/sql', $urlParams); $refreshLink = ' [ ' From 46bc8725aec5bfff4c8511251e9fde066952b002 Mon Sep 17 00:00:00 2001 From: Liviu-Mihail Concioiu Date: Sun, 8 Feb 2026 19:48:11 +0100 Subject: [PATCH 06/52] Make POST requests for encrypted queries Signed-off-by: Liviu-Mihail Concioiu --- libraries/classes/Html/Generator.php | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/classes/Html/Generator.php b/libraries/classes/Html/Generator.php index 85908aebbc..56b2f05234 100644 --- a/libraries/classes/Html/Generator.php +++ b/libraries/classes/Html/Generator.php @@ -1068,6 +1068,7 @@ class Generator str_contains($url, 'sql_query=') && ! str_contains($url, 'sql_signature=') ) + || $GLOBALS['cfg']['URLQueryEncryption'] || str_contains($url, 'view[as]='); if ($respectUrlLengthLimit && $isDataPostFormatSupported) { $parts = explode('?', $url, 2); From cfd5c741252e9c008c0d14e25246890d7a9ab9bd Mon Sep 17 00:00:00 2001 From: Liviu-Mihail Concioiu Date: Sun, 8 Feb 2026 20:08:01 +0100 Subject: [PATCH 07/52] Fix linting errors Signed-off-by: Liviu-Mihail Concioiu --- phpstan-baseline.neon | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index c23c8177ce..d7e883349a 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -19980,6 +19980,11 @@ parameters: count: 1 path: libraries/classes/Html/Generator.php + - + message: "#^Cannot access offset 'URLQueryEncryption' on mixed\\.$#" + count: 1 + path: libraries/classes/Html/Generator.php + - message: "#^Cannot access offset 'first_timestamp' on mixed\\.$#" count: 1 @@ -20817,7 +20822,7 @@ parameters: - message: "#^Cannot access offset mixed on mixed\\.$#" - count: 3 + count: 4 path: libraries/classes/Index.php - @@ -35382,7 +35387,7 @@ parameters: - message: "#^Only booleans are allowed in a negated boolean, int\\|null given\\.$#" - count: 2 + count: 1 path: libraries/classes/Table.php - @@ -35395,6 +35400,11 @@ parameters: count: 3 path: libraries/classes/Table.php + - + message: "#^Only booleans are allowed in a negated boolean, string\\|null given\\.$#" + count: 1 + path: libraries/classes/Table.php + - message: "#^Only booleans are allowed in an elseif condition, int\\|false given\\.$#" count: 1 @@ -35410,6 +35420,11 @@ parameters: count: 2 path: libraries/classes/Table.php + - + message: "#^Only booleans are allowed in an if condition, int\\|null given\\.$#" + count: 1 + path: libraries/classes/Table.php + - message: "#^Only booleans are allowed in an if condition, mixed given\\.$#" count: 1 From 354f5364b54a1dba7db765330163c1f13b98f9a8 Mon Sep 17 00:00:00 2001 From: Liviu-Mihail Concioiu Date: Sun, 8 Feb 2026 20:19:15 +0100 Subject: [PATCH 08/52] Fix linting errors Signed-off-by: Liviu-Mihail Concioiu --- psalm-baseline.xml | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/psalm-baseline.xml b/psalm-baseline.xml index 232362d17b..c29ad6e430 100644 --- a/psalm-baseline.xml +++ b/psalm-baseline.xml @@ -7651,7 +7651,8 @@ $urlParams $urlParams - + + $GLOBALS['cfg']['URLQueryEncryption'] $server['ssl'] $server['ssl_verify'] @@ -7921,13 +7922,15 @@ self::$registry[$schema][$table] self::$registry[$schema][$table] - + + $columns['collations'][$key] $columns['sub_parts'][$key] self::$registry[$schema][$table][$keyName] self::$registry[$schema][$table][$keyName] self::$registry[$schema][$table][$keyName] - + + $collation $column $column $data['columns'][] From fe50147755c7699bab098dcf391c1e90f3d1da79 Mon Sep 17 00:00:00 2001 From: Liviu-Mihail Concioiu Date: Sun, 8 Feb 2026 21:30:03 +0100 Subject: [PATCH 09/52] Add warning message if URLQueryEncryptionSecretKey is not valid Signed-off-by: Liviu-Mihail Concioiu --- .../classes/Controllers/HomeController.php | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/libraries/classes/Controllers/HomeController.php b/libraries/classes/Controllers/HomeController.php index 78192f4e46..bbda118bfa 100644 --- a/libraries/classes/Controllers/HomeController.php +++ b/libraries/classes/Controllers/HomeController.php @@ -347,6 +347,40 @@ class HomeController extends AbstractController } } + /** + * Check if user does not have defined query encryption key and it is being used. + */ + if ($cfg['URLQueryEncryption']) { + $encryptionKeyLength = 0; + // This can happen if the user did use getenv() to set URLQueryEncryptionSecretKey + if (is_string($cfg['URLQueryEncryptionSecretKey'])) { + $encryptionKeyLength = mb_strlen($cfg['URLQueryEncryptionSecretKey'], '8bit'); + } + + if ($encryptionKeyLength < SODIUM_CRYPTO_SECRETBOX_KEYBYTES) { + $this->errors[] = [ + 'message' => __( + 'The configuration file needs a valid key for query encryption.' + . ' A temporary key was automatically generated for you.' + . ' Please refer to the [doc@cfg_URLQueryEncryptionSecretKey]documentation[/doc].' + ), + 'severity' => 'warning', + ]; + } elseif ($encryptionKeyLength > SODIUM_CRYPTO_SECRETBOX_KEYBYTES) { + $this->errors[] = [ + 'message' => sprintf( + __( + 'The query encryption key in the configuration file is longer than necessary.' + . ' It should only be %d bytes long.' + . ' Please refer to the [doc@cfg_URLQueryEncryptionSecretKey]documentation[/doc].' + ), + SODIUM_CRYPTO_SECRETBOX_KEYBYTES + ), + 'severity' => 'warning', + ]; + } + } + /** * Check for existence of config directory which should not exist in * production environment. From 4a6bccb1548a5404f111acb8b12b05e3d64f6883 Mon Sep 17 00:00:00 2001 From: Liviu-Mihail Concioiu Date: Sun, 8 Feb 2026 21:40:08 +0100 Subject: [PATCH 10/52] Fix linting errors Signed-off-by: Liviu-Mihail Concioiu --- phpstan-baseline.neon | 10 ++++++++++ psalm-baseline.xml | 4 ++++ 2 files changed, 14 insertions(+) diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index c23c8177ce..91f01daa6e 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -6105,6 +6105,16 @@ parameters: count: 1 path: libraries/classes/Controllers/HomeController.php + - + message: "#^Cannot access offset 'URLQueryEncryption' on mixed\\.$#" + count: 1 + path: libraries/classes/Controllers/HomeController.php + + - + message: "#^Cannot access offset 'URLQueryEncryptionS…' on mixed\\.$#" + count: 1 + path: libraries/classes/Controllers/HomeController.php + - message: "#^Cannot access offset 'VersionCheck' on mixed\\.$#" count: 1 diff --git a/psalm-baseline.xml b/psalm-baseline.xml index 232362d17b..36ab128756 100644 --- a/psalm-baseline.xml +++ b/psalm-baseline.xml @@ -2091,6 +2091,10 @@ + + $cfg['URLQueryEncryption'] + $cfg['URLQueryEncryptionSecretKey'] + $message $this->config->get('ShowGitRevision') ?? true From 8f2395a05934d64f7a1e76f235533043dfb616cd Mon Sep 17 00:00:00 2001 From: Liviu-Mihail Concioiu Date: Tue, 17 Feb 2026 14:30:26 +0100 Subject: [PATCH 11/52] Check also for WebKit Signed-off-by: Liviu-Mihail Concioiu --- js/src/designer/move.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/js/src/designer/move.js b/js/src/designer/move.js index 990896dc0d..53c0ae7e56 100644 --- a/js/src/designer/move.js +++ b/js/src/designer/move.js @@ -556,7 +556,9 @@ DesignerMove.toggleFullscreen = function () { var $content = $('#page_content'); const pageContent = document.getElementById('page_content'); - if (! document.fullscreenEnabled) { + var fullscreenEnabled = document.fullscreenEnabled || document.webkitFullscreenEnabled; + + if (! fullscreenEnabled) { Functions.ajaxShowMessage(Messages.strFullscreenRequestDenied, null, 'error'); return; From 3c268c1b94ce479d40893e5fd67fe7ccd67eac83 Mon Sep 17 00:00:00 2001 From: Liviu-Mihail Concioiu Date: Tue, 17 Feb 2026 14:41:53 +0100 Subject: [PATCH 12/52] Please compat Signed-off-by: Liviu-Mihail Concioiu --- js/src/designer/move.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/js/src/designer/move.js b/js/src/designer/move.js index 53c0ae7e56..335792adfa 100644 --- a/js/src/designer/move.js +++ b/js/src/designer/move.js @@ -556,7 +556,11 @@ DesignerMove.toggleFullscreen = function () { var $content = $('#page_content'); const pageContent = document.getElementById('page_content'); - var fullscreenEnabled = document.fullscreenEnabled || document.webkitFullscreenEnabled; + var fullscreenEnabled = + document.fullscreenEnabled || + document.webkitFullscreenEnabled || + document.mozFullScreenEnabled || + document.msFullscreenEnabled; if (! fullscreenEnabled) { Functions.ajaxShowMessage(Messages.strFullscreenRequestDenied, null, 'error'); From e016e7a6ba52cd5dd8ec73fa82523becc1d721a4 Mon Sep 17 00:00:00 2001 From: Liviu-Mihail Concioiu Date: Tue, 17 Feb 2026 15:27:17 +0100 Subject: [PATCH 13/52] Support older Firefox versions Signed-off-by: Liviu-Mihail Concioiu --- js/src/designer/move.js | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/js/src/designer/move.js b/js/src/designer/move.js index 335792adfa..aeaba2179f 100644 --- a/js/src/designer/move.js +++ b/js/src/designer/move.js @@ -549,6 +549,18 @@ DesignerMove.rect = function (x1, y1, w, h, color) { }; // --------------------------- FULLSCREEN ------------------------------------- +DesignerMove.requestFullscreen = function (e) { + if (e.requestFullscreen) { + return e.requestFullscreen(); + } else if (e.webkitRequestFullscreen) { + return e.webkitRequestFullscreen(); + } else if (e.mozRequestFullScreen) { + return e.mozRequestFullScreen(); + } else if (e.msRequestFullscreen) { + return e.msRequestFullscreen(); + } +} + DesignerMove.toggleFullscreen = function () { var valueSent = ''; var $img = $('#toggleFullscreen').find('img'); @@ -559,7 +571,7 @@ DesignerMove.toggleFullscreen = function () { var fullscreenEnabled = document.fullscreenEnabled || document.webkitFullscreenEnabled || - document.mozFullScreenEnabled || + document.mozFullscreenEnabled || document.msFullscreenEnabled; if (! fullscreenEnabled) { @@ -578,7 +590,7 @@ DesignerMove.toggleFullscreen = function () { $('#osn_tab').css({ 'width': screen.width + 'px', 'height': screen.height }); valueSent = 'on'; - pageContent.requestFullscreen(); + DesignerMove.requestFullscreen(pageContent); } else { $img.attr('src', $img.data('enter')) .attr('title', $span.data('enter')); From a786530ba675c070de459a6d679aa04e80a9737a Mon Sep 17 00:00:00 2001 From: Liviu-Mihail Concioiu Date: Tue, 17 Feb 2026 15:32:01 +0100 Subject: [PATCH 14/52] It should be capital S Signed-off-by: Liviu-Mihail Concioiu --- js/src/designer/move.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/src/designer/move.js b/js/src/designer/move.js index aeaba2179f..8e9fad32a0 100644 --- a/js/src/designer/move.js +++ b/js/src/designer/move.js @@ -571,7 +571,7 @@ DesignerMove.toggleFullscreen = function () { var fullscreenEnabled = document.fullscreenEnabled || document.webkitFullscreenEnabled || - document.mozFullscreenEnabled || + document.mozFullScreenEnabled || document.msFullscreenEnabled; if (! fullscreenEnabled) { From 4987197fb09121c5fb2a7297d223fbbf10d8c5ee Mon Sep 17 00:00:00 2001 From: Liviu-Mihail Concioiu Date: Tue, 17 Feb 2026 15:35:59 +0100 Subject: [PATCH 15/52] Fix Signed-off-by: Liviu-Mihail Concioiu --- js/src/designer/move.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/js/src/designer/move.js b/js/src/designer/move.js index 8e9fad32a0..3b0c7435b0 100644 --- a/js/src/designer/move.js +++ b/js/src/designer/move.js @@ -559,7 +559,7 @@ DesignerMove.requestFullscreen = function (e) { } else if (e.msRequestFullscreen) { return e.msRequestFullscreen(); } -} +}; DesignerMove.toggleFullscreen = function () { var valueSent = ''; @@ -569,10 +569,10 @@ DesignerMove.toggleFullscreen = function () { const pageContent = document.getElementById('page_content'); var fullscreenEnabled = - document.fullscreenEnabled || document.webkitFullscreenEnabled || document.mozFullScreenEnabled || - document.msFullscreenEnabled; + document.msFullscreenEnabled || + document.fullscreenEnabled; if (! fullscreenEnabled) { Functions.ajaxShowMessage(Messages.strFullscreenRequestDenied, null, 'error'); From c338fdbbe19dfab6a86aacb07174c59e30033650 Mon Sep 17 00:00:00 2001 From: Liviu-Mihail Concioiu Date: Tue, 17 Feb 2026 15:45:45 +0100 Subject: [PATCH 16/52] Disable eslint Signed-off-by: Liviu-Mihail Concioiu --- js/src/designer/move.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/js/src/designer/move.js b/js/src/designer/move.js index 3b0c7435b0..8a149c63e6 100644 --- a/js/src/designer/move.js +++ b/js/src/designer/move.js @@ -568,11 +568,12 @@ DesignerMove.toggleFullscreen = function () { var $content = $('#page_content'); const pageContent = document.getElementById('page_content'); + // eslint-disable-next-line compat/compat var fullscreenEnabled = + document.fullscreenEnabled || document.webkitFullscreenEnabled || document.mozFullScreenEnabled || - document.msFullscreenEnabled || - document.fullscreenEnabled; + document.msFullscreenEnabled; if (! fullscreenEnabled) { Functions.ajaxShowMessage(Messages.strFullscreenRequestDenied, null, 'error'); From 3d07f562147ee1c436d6e06f8f6c0db8784d6fa4 Mon Sep 17 00:00:00 2001 From: Liviu-Mihail Concioiu Date: Tue, 17 Feb 2026 15:52:31 +0100 Subject: [PATCH 17/52] Fix Signed-off-by: Liviu-Mihail Concioiu --- js/src/designer/move.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/src/designer/move.js b/js/src/designer/move.js index 8a149c63e6..360a88b634 100644 --- a/js/src/designer/move.js +++ b/js/src/designer/move.js @@ -568,8 +568,8 @@ DesignerMove.toggleFullscreen = function () { var $content = $('#page_content'); const pageContent = document.getElementById('page_content'); - // eslint-disable-next-line compat/compat var fullscreenEnabled = + // eslint-disable-next-line compat/compat document.fullscreenEnabled || document.webkitFullscreenEnabled || document.mozFullScreenEnabled || From 46c16452f98d41061d31f84eb33bd1e16fb3ebd6 Mon Sep 17 00:00:00 2001 From: Liviu-Mihail Concioiu Date: Wed, 18 Feb 2026 14:39:31 +0100 Subject: [PATCH 18/52] Move fullscreenEnabled to function Signed-off-by: Liviu-Mihail Concioiu --- js/src/designer/move.js | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/js/src/designer/move.js b/js/src/designer/move.js index 360a88b634..89c00279b6 100644 --- a/js/src/designer/move.js +++ b/js/src/designer/move.js @@ -561,6 +561,14 @@ DesignerMove.requestFullscreen = function (e) { } }; +DesignerMove.fullscreenEnabled = function () { + // eslint-disable-next-line compat/compat + return document.fullscreenEnabled || + document.webkitFullscreenEnabled || + document.mozFullScreenEnabled || + document.msFullscreenEnabled; +}; + DesignerMove.toggleFullscreen = function () { var valueSent = ''; var $img = $('#toggleFullscreen').find('img'); @@ -568,14 +576,7 @@ DesignerMove.toggleFullscreen = function () { var $content = $('#page_content'); const pageContent = document.getElementById('page_content'); - var fullscreenEnabled = - // eslint-disable-next-line compat/compat - document.fullscreenEnabled || - document.webkitFullscreenEnabled || - document.mozFullScreenEnabled || - document.msFullscreenEnabled; - - if (! fullscreenEnabled) { + if (! DesignerMove.fullscreenEnabled()) { Functions.ajaxShowMessage(Messages.strFullscreenRequestDenied, null, 'error'); return; From c0e99fcaa0831f7043623f6cc513b47000199a3b Mon Sep 17 00:00:00 2001 From: Liviu-Mihail Concioiu Date: Wed, 18 Feb 2026 15:17:10 +0100 Subject: [PATCH 19/52] Improve message Signed-off-by: Liviu-Mihail Concioiu --- .../classes/Controllers/JavaScriptMessagesController.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/libraries/classes/Controllers/JavaScriptMessagesController.php b/libraries/classes/Controllers/JavaScriptMessagesController.php index 31ced988e8..f92737784d 100644 --- a/libraries/classes/Controllers/JavaScriptMessagesController.php +++ b/libraries/classes/Controllers/JavaScriptMessagesController.php @@ -710,7 +710,9 @@ final class JavaScriptMessagesController 'strHide' => __('Hide'), 'strShow' => __('Show'), 'strStructure' => __('Structure'), - 'strFullscreenRequestDenied' => __('The fullscreen request was denied.'), + 'strFullscreenRequestDenied' => __( + 'Request for fullscreen was denied because Fullscreen API is disabled by user preference.' + ), ]; } } From bcd217f6454f63c1ea8357c6d1d535f0e5b7e387 Mon Sep 17 00:00:00 2001 From: Liviu-Mihail Concioiu Date: Wed, 18 Feb 2026 23:34:48 +0100 Subject: [PATCH 20/52] Do not quote geometry values Signed-off-by: Liviu-Mihail Concioiu --- libraries/classes/Import.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libraries/classes/Import.php b/libraries/classes/Import.php index d401defe02..6ad8d092e4 100644 --- a/libraries/classes/Import.php +++ b/libraries/classes/Import.php @@ -1169,7 +1169,8 @@ class Import if ($analyses != null) { $isVarchar = ($analyses[$i][self::TYPES][$colCount] === self::VARCHAR); } else { - $isVarchar = ! is_numeric($tables[$i][self::ROWS][$j][$k]); + $isVarchar = ! is_numeric($tables[$i][self::ROWS][$j][$k]) + && ! preg_match('/^0x[0-9a-f]+$/', $tables[$i][self::ROWS][$j][$k]); } /* Don't put quotes around NULL fields */ From e5e1c9122abbfef197ac964370d65cca392dc09f Mon Sep 17 00:00:00 2001 From: Khushal Patel Date: Thu, 19 Feb 2026 07:04:00 +0530 Subject: [PATCH 21/52] fix: select results table instead of iterating through each table in DOM Signed-off-by: Khushal Patel --- js/src/table/change.js | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/js/src/table/change.js b/js/src/table/change.js index 79ca0f982a..33c6c1cef1 100644 --- a/js/src/table/change.js +++ b/js/src/table/change.js @@ -452,12 +452,11 @@ AJAX.registerTeardown('table/change.js', function () { $(document).off('change', '#insert_rows'); // Reset grid edit state - $('table').each(function () { - var grid = $(this).data('pmaGrid'); - if (grid && typeof grid.resetGridEditState === 'function') { - grid.resetGridEditState(); - } - }); + var grid = $('table.table_results').data('pmaGrid'); + + if (grid && typeof grid.resetGridEditState === 'function') { + grid.resetGridEditState(); + } }); /** From 4341d2c45ef137865b273f8221f22fcb1fc98433 Mon Sep 17 00:00:00 2001 From: Liviu-Mihail Concioiu Date: Thu, 19 Feb 2026 03:14:48 +0100 Subject: [PATCH 22/52] XML - Allow export of geometry and binary fields Signed-off-by: Liviu-Mihail Concioiu --- libraries/classes/Plugins/Export/ExportXml.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/libraries/classes/Plugins/Export/ExportXml.php b/libraries/classes/Plugins/Export/ExportXml.php index f8dc1034c4..6895578a4b 100644 --- a/libraries/classes/Plugins/Export/ExportXml.php +++ b/libraries/classes/Plugins/Export/ExportXml.php @@ -5,6 +5,7 @@ declare(strict_types=1); namespace PhpMyAdmin\Plugins\Export; use PhpMyAdmin\DatabaseInterface; +use PhpMyAdmin\FieldMetadata; use PhpMyAdmin\Plugins\ExportPlugin; use PhpMyAdmin\Properties\Options\Groups\OptionsPropertyMainGroup; use PhpMyAdmin\Properties\Options\Groups\OptionsPropertyRootGroup; @@ -15,6 +16,7 @@ use PhpMyAdmin\Util; use PhpMyAdmin\Version; use function __; +use function bin2hex; use function count; use function htmlspecialchars; use function is_array; @@ -463,6 +465,8 @@ class ExportXml extends ExportPlugin $result = $dbi->query($sqlQuery, DatabaseInterface::CONNECT_USER, DatabaseInterface::QUERY_UNBUFFERED); $columns_cnt = $result->numFields(); + /** @var FieldMetadata[] $fieldsMeta */ + $fieldsMeta = $dbi->getFieldsMeta($result); $columns = []; foreach ($result->getFieldNames() as $column) { $columns[] = stripslashes($column); @@ -487,6 +491,8 @@ class ExportXml extends ExportPlugin // the XML structure if (! isset($record[$i])) { $record[$i] = 'NULL'; + } elseif ($fieldsMeta[$i]->isMappedTypeGeometry || $fieldsMeta[$i]->isBinary) { + $record[$i] = '0x' . bin2hex($record[$i]); } $buffer .= ' Date: Thu, 19 Feb 2026 03:17:58 +0100 Subject: [PATCH 27/52] PDF - Show [GEOMETRY] and [BLOB] Signed-off-by: Liviu-Mihail Concioiu --- libraries/classes/Plugins/Export/Helpers/Pdf.php | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/libraries/classes/Plugins/Export/Helpers/Pdf.php b/libraries/classes/Plugins/Export/Helpers/Pdf.php index 8bac35c212..0e60cae7e7 100644 --- a/libraries/classes/Plugins/Export/Helpers/Pdf.php +++ b/libraries/classes/Plugins/Export/Helpers/Pdf.php @@ -267,6 +267,16 @@ class Pdf extends PdfLib $this->page = $currpage; $this->setXY($l, $h); if ($this->tablewidths[$col] > 0) { + if ($txt !== null) { + if ($this->fields[$col]->isType(FieldMetadata::TYPE_GEOMETRY)) { + $txt = '[GEOMETRY]'; + } + + if ($this->fields[$col]->isType(FieldMetadata::TYPE_BLOB) || $this->fields[$col]->isBinary()) { + $txt = '[BLOB]'; + } + } + $this->MultiCell($this->tablewidths[$col], $lineheight, $txt ?? 'NULL', 0, $this->colAlign[$col]); $l += $this->tablewidths[$col]; } @@ -770,7 +780,7 @@ class Pdf extends PdfLib } /** - * @todo do not deactivate completely the display + * do not deactivate completely the display * but show the field's name and [BLOB] */ if ($this->fields[$i]->isBinary()) { From 2570d01743f0e388333e3fa4df4a75612b71957a Mon Sep 17 00:00:00 2001 From: Liviu-Mihail Concioiu Date: Thu, 19 Feb 2026 03:20:43 +0100 Subject: [PATCH 28/52] YAML - Allow export of geometry and binary fields Signed-off-by: Liviu-Mihail Concioiu --- libraries/classes/Plugins/Export/ExportYaml.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/libraries/classes/Plugins/Export/ExportYaml.php b/libraries/classes/Plugins/Export/ExportYaml.php index e7b5b8065b..7edceb2270 100644 --- a/libraries/classes/Plugins/Export/ExportYaml.php +++ b/libraries/classes/Plugins/Export/ExportYaml.php @@ -17,6 +17,7 @@ use PhpMyAdmin\Properties\Plugins\ExportPluginProperties; use function __; use function array_key_exists; +use function bin2hex; use function is_numeric; use function str_replace; use function stripslashes; @@ -141,6 +142,7 @@ class ExportYaml extends ExportPlugin $result = $dbi->query($sqlQuery, DatabaseInterface::CONNECT_USER, DatabaseInterface::QUERY_UNBUFFERED); $columns_cnt = $result->numFields(); + /** @var FieldMetadata[] $fieldsMeta */ $fieldsMeta = $dbi->getFieldsMeta($result); $columns = []; @@ -181,6 +183,10 @@ class ExportYaml extends ExportPlugin continue; } + if ($fieldsMeta[$i]->isMappedTypeGeometry || $fieldsMeta[$i]->isBinary) { + $record[$i] = '0x' . bin2hex($record[$i]); + } + $record[$i] = str_replace( [ '\\', From cf64bbf57a26c2dd0c8caa2339cc5588b779aec4 Mon Sep 17 00:00:00 2001 From: Liviu-Mihail Concioiu Date: Thu, 19 Feb 2026 03:21:24 +0100 Subject: [PATCH 29/52] LaTeX - Allow export of geometry and binary fields Signed-off-by: Liviu-Mihail Concioiu --- libraries/classes/Plugins/Export/ExportLatex.php | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/libraries/classes/Plugins/Export/ExportLatex.php b/libraries/classes/Plugins/Export/ExportLatex.php index 86167d7893..582696c88d 100644 --- a/libraries/classes/Plugins/Export/ExportLatex.php +++ b/libraries/classes/Plugins/Export/ExportLatex.php @@ -8,6 +8,7 @@ declare(strict_types=1); namespace PhpMyAdmin\Plugins\Export; use PhpMyAdmin\DatabaseInterface; +use PhpMyAdmin\FieldMetadata; use PhpMyAdmin\Plugins\ExportPlugin; use PhpMyAdmin\Properties\Options\Groups\OptionsPropertyMainGroup; use PhpMyAdmin\Properties\Options\Groups\OptionsPropertyRootGroup; @@ -19,6 +20,7 @@ use PhpMyAdmin\Util; use PhpMyAdmin\Version; use function __; +use function bin2hex; use function count; use function in_array; use function mb_strpos; @@ -298,6 +300,8 @@ class ExportLatex extends ExportPlugin $result = $dbi->tryQuery($sqlQuery, DatabaseInterface::CONNECT_USER, DatabaseInterface::QUERY_UNBUFFERED); $columns_cnt = $result->numFields(); + /** @var FieldMetadata[] $fieldsMeta */ + $fieldsMeta = $dbi->getFieldsMeta($result); $columns = []; $columns_alias = []; foreach ($result->getFieldNames() as $i => $col_as) { @@ -398,9 +402,15 @@ class ExportLatex extends ExportPlugin // print each row for ($i = 0; $i < $columns_cnt; $i++) { if ($record[$columns[$i]] !== null && isset($record[$columns[$i]])) { - $column_value = self::texEscape( - stripslashes($record[$columns[$i]]) - ); + if ($fieldsMeta[$i]->isMappedTypeGeometry || $fieldsMeta[$i]->isBinary) { + $column_value = self::texEscape( + '0x' . bin2hex($record[$columns[$i]]) + ); + } else { + $column_value = self::texEscape( + stripslashes($record[$columns[$i]]) + ); + } } else { $column_value = $GLOBALS['latex_null']; } From 0a947b96b5ce0e6d4f42cdf8480f80508612e00f Mon Sep 17 00:00:00 2001 From: Liviu-Mihail Concioiu Date: Thu, 19 Feb 2026 04:08:37 +0100 Subject: [PATCH 30/52] Fix baselines Signed-off-by: Liviu-Mihail Concioiu --- .../classes/Plugins/Export/ExportCsv.php | 1 - .../classes/Plugins/Export/ExportLatex.php | 1 - .../Plugins/Export/ExportMediawiki.php | 1 - .../classes/Plugins/Export/ExportPhparray.php | 1 - .../classes/Plugins/Export/ExportTexytext.php | 1 - .../classes/Plugins/Export/ExportXml.php | 1 - .../classes/Plugins/Export/ExportYaml.php | 1 - phpstan-baseline.neon | 166 +++++++++++++++++- psalm-baseline.xml | 6 +- 9 files changed, 163 insertions(+), 16 deletions(-) diff --git a/libraries/classes/Plugins/Export/ExportCsv.php b/libraries/classes/Plugins/Export/ExportCsv.php index 67f36701c3..de1a5a6f07 100644 --- a/libraries/classes/Plugins/Export/ExportCsv.php +++ b/libraries/classes/Plugins/Export/ExportCsv.php @@ -222,7 +222,6 @@ class ExportCsv extends ExportPlugin // Gets the data from the database $result = $dbi->query($sqlQuery, DatabaseInterface::CONNECT_USER, DatabaseInterface::QUERY_UNBUFFERED); $fields_cnt = $result->numFields(); - /** @var FieldMetadata[] $fieldsMeta */ $fieldsMeta = $dbi->getFieldsMeta($result); // If required, get fields name at the first line diff --git a/libraries/classes/Plugins/Export/ExportLatex.php b/libraries/classes/Plugins/Export/ExportLatex.php index 582696c88d..66e643fff2 100644 --- a/libraries/classes/Plugins/Export/ExportLatex.php +++ b/libraries/classes/Plugins/Export/ExportLatex.php @@ -300,7 +300,6 @@ class ExportLatex extends ExportPlugin $result = $dbi->tryQuery($sqlQuery, DatabaseInterface::CONNECT_USER, DatabaseInterface::QUERY_UNBUFFERED); $columns_cnt = $result->numFields(); - /** @var FieldMetadata[] $fieldsMeta */ $fieldsMeta = $dbi->getFieldsMeta($result); $columns = []; $columns_alias = []; diff --git a/libraries/classes/Plugins/Export/ExportMediawiki.php b/libraries/classes/Plugins/Export/ExportMediawiki.php index f18b7a351b..7626f4de89 100644 --- a/libraries/classes/Plugins/Export/ExportMediawiki.php +++ b/libraries/classes/Plugins/Export/ExportMediawiki.php @@ -319,7 +319,6 @@ class ExportMediawiki extends ExportPlugin // Get the table data from the database $result = $dbi->query($sqlQuery, DatabaseInterface::CONNECT_USER, DatabaseInterface::QUERY_UNBUFFERED); $fields_cnt = $result->numFields(); - /** @var FieldMetadata[] $fieldsMeta */ $fieldsMeta = $dbi->getFieldsMeta($result); while ($row = $result->fetchRow()) { diff --git a/libraries/classes/Plugins/Export/ExportPhparray.php b/libraries/classes/Plugins/Export/ExportPhparray.php index 25097c2753..881f7c12b8 100644 --- a/libraries/classes/Plugins/Export/ExportPhparray.php +++ b/libraries/classes/Plugins/Export/ExportPhparray.php @@ -171,7 +171,6 @@ class ExportPhparray extends ExportPlugin $result = $dbi->query($sqlQuery, DatabaseInterface::CONNECT_USER, DatabaseInterface::QUERY_UNBUFFERED); $columns_cnt = $result->numFields(); - /** @var FieldMetadata[] $fieldsMeta */ $fieldsMeta = $dbi->getFieldsMeta($result); $columns = []; foreach ($result->getFieldNames() as $i => $col_as) { diff --git a/libraries/classes/Plugins/Export/ExportTexytext.php b/libraries/classes/Plugins/Export/ExportTexytext.php index 8927485491..adf972181a 100644 --- a/libraries/classes/Plugins/Export/ExportTexytext.php +++ b/libraries/classes/Plugins/Export/ExportTexytext.php @@ -187,7 +187,6 @@ class ExportTexytext extends ExportPlugin // Gets the data from the database $result = $dbi->query($sqlQuery, DatabaseInterface::CONNECT_USER, DatabaseInterface::QUERY_UNBUFFERED); $fields_cnt = $result->numFields(); - /** @var FieldMetadata[] $fieldsMeta */ $fieldsMeta = $dbi->getFieldsMeta($result); // If required, get fields name at the first line diff --git a/libraries/classes/Plugins/Export/ExportXml.php b/libraries/classes/Plugins/Export/ExportXml.php index 6895578a4b..36b73cae11 100644 --- a/libraries/classes/Plugins/Export/ExportXml.php +++ b/libraries/classes/Plugins/Export/ExportXml.php @@ -465,7 +465,6 @@ class ExportXml extends ExportPlugin $result = $dbi->query($sqlQuery, DatabaseInterface::CONNECT_USER, DatabaseInterface::QUERY_UNBUFFERED); $columns_cnt = $result->numFields(); - /** @var FieldMetadata[] $fieldsMeta */ $fieldsMeta = $dbi->getFieldsMeta($result); $columns = []; foreach ($result->getFieldNames() as $column) { diff --git a/libraries/classes/Plugins/Export/ExportYaml.php b/libraries/classes/Plugins/Export/ExportYaml.php index 7edceb2270..9df20345ab 100644 --- a/libraries/classes/Plugins/Export/ExportYaml.php +++ b/libraries/classes/Plugins/Export/ExportYaml.php @@ -142,7 +142,6 @@ class ExportYaml extends ExportPlugin $result = $dbi->query($sqlQuery, DatabaseInterface::CONNECT_USER, DatabaseInterface::QUERY_UNBUFFERED); $columns_cnt = $result->numFields(); - /** @var FieldMetadata[] $fieldsMeta */ $fieldsMeta = $dbi->getFieldsMeta($result); $columns = []; diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 6680a7a261..6b411fad4b 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -20772,7 +20772,7 @@ parameters: - message: "#^Cannot access offset mixed on mixed\\.$#" - count: 3 + count: 4 path: libraries/classes/Index.php - @@ -25577,7 +25577,7 @@ parameters: - message: "#^Cannot access offset int\\<0, max\\> on mixed\\.$#" - count: 1 + count: 3 path: libraries/classes/Plugins/Export/ExportCsv.php - @@ -25590,6 +25590,16 @@ parameters: count: 1 path: libraries/classes/Plugins/Export/ExportCsv.php + - + message: "#^Cannot access property \\$isBinary on mixed\\.$#" + count: 1 + path: libraries/classes/Plugins/Export/ExportCsv.php + + - + message: "#^Cannot access property \\$isMappedTypeGeometry on mixed\\.$#" + count: 1 + path: libraries/classes/Plugins/Export/ExportCsv.php + - message: "#^Cannot call method fetchRow\\(\\) on mixed\\.$#" count: 1 @@ -25600,6 +25610,11 @@ parameters: count: 1 path: libraries/classes/Plugins/Export/ExportCsv.php + - + message: "#^Cannot call method getFieldsMeta\\(\\) on mixed\\.$#" + count: 1 + path: libraries/classes/Plugins/Export/ExportCsv.php + - message: "#^Cannot call method numFields\\(\\) on mixed\\.$#" count: 1 @@ -25625,6 +25640,11 @@ parameters: count: 1 path: libraries/classes/Plugins/Export/ExportCsv.php + - + message: "#^Parameter \\#1 \\$data of function bin2hex expects string, mixed given\\.$#" + count: 1 + path: libraries/classes/Plugins/Export/ExportCsv.php + - message: "#^Parameter \\#1 \\$search of function str_replace expects array\\|string, mixed given\\.$#" count: 4 @@ -25960,6 +25980,11 @@ parameters: count: 2 path: libraries/classes/Plugins/Export/ExportLatex.php + - + message: "#^Cannot access offset int\\<0, max\\> on mixed\\.$#" + count: 2 + path: libraries/classes/Plugins/Export/ExportLatex.php + - message: "#^Cannot access offset mixed on mixed\\.$#" count: 3 @@ -25970,6 +25995,16 @@ parameters: count: 2 path: libraries/classes/Plugins/Export/ExportLatex.php + - + message: "#^Cannot access property \\$isBinary on mixed\\.$#" + count: 1 + path: libraries/classes/Plugins/Export/ExportLatex.php + + - + message: "#^Cannot access property \\$isMappedTypeGeometry on mixed\\.$#" + count: 1 + path: libraries/classes/Plugins/Export/ExportLatex.php + - message: "#^Cannot call method fetchAssoc\\(\\) on mixed\\.$#" count: 1 @@ -25985,6 +26020,11 @@ parameters: count: 1 path: libraries/classes/Plugins/Export/ExportLatex.php + - + message: "#^Cannot call method getFieldsMeta\\(\\) on mixed\\.$#" + count: 1 + path: libraries/classes/Plugins/Export/ExportLatex.php + - message: "#^Cannot call method getTableIndexes\\(\\) on mixed\\.$#" count: 1 @@ -26030,6 +26070,11 @@ parameters: count: 1 path: libraries/classes/Plugins/Export/ExportLatex.php + - + message: "#^Parameter \\#1 \\$data of function bin2hex expects string, mixed given\\.$#" + count: 1 + path: libraries/classes/Plugins/Export/ExportLatex.php + - message: "#^Parameter \\#1 \\$str of function stripslashes expects string, mixed given\\.$#" count: 2 @@ -26092,7 +26137,7 @@ parameters: - message: "#^Cannot access offset int\\<0, max\\> on mixed\\.$#" - count: 1 + count: 4 path: libraries/classes/Plugins/Export/ExportMediawiki.php - @@ -26105,6 +26150,16 @@ parameters: count: 2 path: libraries/classes/Plugins/Export/ExportMediawiki.php + - + message: "#^Cannot access property \\$isBinary on mixed\\.$#" + count: 1 + path: libraries/classes/Plugins/Export/ExportMediawiki.php + + - + message: "#^Cannot access property \\$isMappedTypeGeometry on mixed\\.$#" + count: 1 + path: libraries/classes/Plugins/Export/ExportMediawiki.php + - message: "#^Cannot call method fetchRow\\(\\) on mixed\\.$#" count: 1 @@ -26120,6 +26175,11 @@ parameters: count: 1 path: libraries/classes/Plugins/Export/ExportMediawiki.php + - + message: "#^Cannot call method getFieldsMeta\\(\\) on mixed\\.$#" + count: 1 + path: libraries/classes/Plugins/Export/ExportMediawiki.php + - message: "#^Cannot call method numFields\\(\\) on mixed\\.$#" count: 1 @@ -26150,6 +26210,11 @@ parameters: count: 1 path: libraries/classes/Plugins/Export/ExportMediawiki.php + - + message: "#^Parameter \\#1 \\$data of function bin2hex expects string, mixed given\\.$#" + count: 1 + path: libraries/classes/Plugins/Export/ExportMediawiki.php + - message: "#^Parameter \\#1 \\$identifier of static method PhpMyAdmin\\\\Util\\:\\:backquote\\(\\) expects string\\|Stringable\\|null, mixed given\\.$#" count: 2 @@ -26492,7 +26557,7 @@ parameters: - message: "#^Cannot access offset int\\<0, max\\> on mixed\\.$#" - count: 1 + count: 4 path: libraries/classes/Plugins/Export/ExportPhparray.php - @@ -26505,6 +26570,16 @@ parameters: count: 1 path: libraries/classes/Plugins/Export/ExportPhparray.php + - + message: "#^Cannot access property \\$isBinary on mixed\\.$#" + count: 1 + path: libraries/classes/Plugins/Export/ExportPhparray.php + + - + message: "#^Cannot access property \\$isMappedTypeGeometry on mixed\\.$#" + count: 1 + path: libraries/classes/Plugins/Export/ExportPhparray.php + - message: "#^Cannot call method fetchRow\\(\\) on mixed\\.$#" count: 1 @@ -26515,6 +26590,11 @@ parameters: count: 1 path: libraries/classes/Plugins/Export/ExportPhparray.php + - + message: "#^Cannot call method getFieldsMeta\\(\\) on mixed\\.$#" + count: 1 + path: libraries/classes/Plugins/Export/ExportPhparray.php + - message: "#^Cannot call method numFields\\(\\) on mixed\\.$#" count: 1 @@ -26545,6 +26625,11 @@ parameters: count: 1 path: libraries/classes/Plugins/Export/ExportPhparray.php + - + message: "#^Parameter \\#1 \\$data of function bin2hex expects string, mixed given\\.$#" + count: 1 + path: libraries/classes/Plugins/Export/ExportPhparray.php + - message: "#^Parameter \\#1 \\$identifier of static method PhpMyAdmin\\\\Util\\:\\:backquote\\(\\) expects string\\|Stringable\\|null, mixed given\\.$#" count: 2 @@ -27287,7 +27372,7 @@ parameters: - message: "#^Cannot access offset int\\<0, max\\> on mixed\\.$#" - count: 1 + count: 3 path: libraries/classes/Plugins/Export/ExportTexytext.php - @@ -27300,6 +27385,16 @@ parameters: count: 3 path: libraries/classes/Plugins/Export/ExportTexytext.php + - + message: "#^Cannot access property \\$isBinary on mixed\\.$#" + count: 1 + path: libraries/classes/Plugins/Export/ExportTexytext.php + + - + message: "#^Cannot access property \\$isMappedTypeGeometry on mixed\\.$#" + count: 1 + path: libraries/classes/Plugins/Export/ExportTexytext.php + - message: "#^Cannot call method fetchRow\\(\\) on mixed\\.$#" count: 1 @@ -27315,6 +27410,11 @@ parameters: count: 1 path: libraries/classes/Plugins/Export/ExportTexytext.php + - + message: "#^Cannot call method getFieldsMeta\\(\\) on mixed\\.$#" + count: 1 + path: libraries/classes/Plugins/Export/ExportTexytext.php + - message: "#^Cannot call method getTableIndexes\\(\\) on mixed\\.$#" count: 2 @@ -27385,6 +27485,11 @@ parameters: count: 1 path: libraries/classes/Plugins/Export/ExportTexytext.php + - + message: "#^Parameter \\#1 \\$data of function bin2hex expects string, mixed given\\.$#" + count: 1 + path: libraries/classes/Plugins/Export/ExportTexytext.php + - message: "#^Parameter \\#1 \\$str of function stripslashes expects string, mixed given\\.$#" count: 1 @@ -27477,7 +27582,7 @@ parameters: - message: "#^Cannot access offset int\\<0, max\\> on mixed\\.$#" - count: 2 + count: 4 path: libraries/classes/Plugins/Export/ExportXml.php - @@ -27490,6 +27595,16 @@ parameters: count: 2 path: libraries/classes/Plugins/Export/ExportXml.php + - + message: "#^Cannot access property \\$isBinary on mixed\\.$#" + count: 1 + path: libraries/classes/Plugins/Export/ExportXml.php + + - + message: "#^Cannot access property \\$isMappedTypeGeometry on mixed\\.$#" + count: 1 + path: libraries/classes/Plugins/Export/ExportXml.php + - message: "#^Cannot call method escapeString\\(\\) on mixed\\.$#" count: 2 @@ -27515,6 +27630,11 @@ parameters: count: 1 path: libraries/classes/Plugins/Export/ExportXml.php + - + message: "#^Cannot call method getFieldsMeta\\(\\) on mixed\\.$#" + count: 1 + path: libraries/classes/Plugins/Export/ExportXml.php + - message: "#^Cannot call method getProceduresOrFunctions\\(\\) on mixed\\.$#" count: 1 @@ -27595,6 +27715,11 @@ parameters: count: 1 path: libraries/classes/Plugins/Export/ExportXml.php + - + message: "#^Parameter \\#1 \\$data of function bin2hex expects string, mixed given\\.$#" + count: 1 + path: libraries/classes/Plugins/Export/ExportXml.php + - message: "#^Parameter \\#1 \\$db of method PhpMyAdmin\\\\Plugins\\\\Export\\\\ExportXml\\:\\:exportDefinitions\\(\\) expects string, mixed given\\.$#" count: 1 @@ -27662,7 +27787,7 @@ parameters: - message: "#^Cannot access offset int\\<0, max\\> on mixed\\.$#" - count: 1 + count: 3 path: libraries/classes/Plugins/Export/ExportYaml.php - @@ -27675,6 +27800,16 @@ parameters: count: 1 path: libraries/classes/Plugins/Export/ExportYaml.php + - + message: "#^Cannot access property \\$isBinary on mixed\\.$#" + count: 1 + path: libraries/classes/Plugins/Export/ExportYaml.php + + - + message: "#^Cannot access property \\$isMappedTypeGeometry on mixed\\.$#" + count: 1 + path: libraries/classes/Plugins/Export/ExportYaml.php + - message: "#^Cannot access property \\$name on mixed\\.$#" count: 1 @@ -27720,6 +27855,11 @@ parameters: count: 1 path: libraries/classes/Plugins/Export/ExportYaml.php + - + message: "#^Parameter \\#1 \\$data of function bin2hex expects string, mixed given\\.$#" + count: 1 + path: libraries/classes/Plugins/Export/ExportYaml.php + - message: "#^Parameter \\#1 \\$str of function stripslashes expects string, mixed given\\.$#" count: 1 @@ -35327,7 +35467,7 @@ parameters: - message: "#^Only booleans are allowed in a negated boolean, int\\|null given\\.$#" - count: 2 + count: 1 path: libraries/classes/Table.php - @@ -35340,6 +35480,11 @@ parameters: count: 3 path: libraries/classes/Table.php + - + message: "#^Only booleans are allowed in a negated boolean, string\\|null given\\.$#" + count: 1 + path: libraries/classes/Table.php + - message: "#^Only booleans are allowed in an elseif condition, int\\|false given\\.$#" count: 1 @@ -35355,6 +35500,11 @@ parameters: count: 2 path: libraries/classes/Table.php + - + message: "#^Only booleans are allowed in an if condition, int\\|null given\\.$#" + count: 1 + path: libraries/classes/Table.php + - message: "#^Only booleans are allowed in an if condition, mixed given\\.$#" count: 1 diff --git a/psalm-baseline.xml b/psalm-baseline.xml index 01239a7a1f..2f809e6623 100644 --- a/psalm-baseline.xml +++ b/psalm-baseline.xml @@ -9640,7 +9640,8 @@ numFields - + + $record[$columns[$i]] $record[$columns[$i]] @@ -10134,6 +10135,9 @@ $col_as + + $record[$i] + From 42fdb08180051c46c7a2d559db563c10b60b2cb2 Mon Sep 17 00:00:00 2001 From: Liviu-Mihail Concioiu Date: Thu, 19 Feb 2026 04:17:13 +0100 Subject: [PATCH 31/52] Fix baselines Signed-off-by: Liviu-Mihail Concioiu --- libraries/classes/Plugins/Export/ExportCsv.php | 1 - libraries/classes/Plugins/Export/ExportLatex.php | 1 - libraries/classes/Plugins/Export/ExportMediawiki.php | 1 - libraries/classes/Plugins/Export/ExportPhparray.php | 1 - libraries/classes/Plugins/Export/ExportTexytext.php | 1 - libraries/classes/Plugins/Export/ExportXml.php | 1 - psalm-baseline.xml | 6 ++++-- 7 files changed, 4 insertions(+), 8 deletions(-) diff --git a/libraries/classes/Plugins/Export/ExportCsv.php b/libraries/classes/Plugins/Export/ExportCsv.php index de1a5a6f07..ae1ef4c09b 100644 --- a/libraries/classes/Plugins/Export/ExportCsv.php +++ b/libraries/classes/Plugins/Export/ExportCsv.php @@ -8,7 +8,6 @@ declare(strict_types=1); namespace PhpMyAdmin\Plugins\Export; use PhpMyAdmin\DatabaseInterface; -use PhpMyAdmin\FieldMetadata; use PhpMyAdmin\Plugins\ExportPlugin; use PhpMyAdmin\Properties\Options\Groups\OptionsPropertyMainGroup; use PhpMyAdmin\Properties\Options\Groups\OptionsPropertyRootGroup; diff --git a/libraries/classes/Plugins/Export/ExportLatex.php b/libraries/classes/Plugins/Export/ExportLatex.php index 66e643fff2..60c49adfd6 100644 --- a/libraries/classes/Plugins/Export/ExportLatex.php +++ b/libraries/classes/Plugins/Export/ExportLatex.php @@ -8,7 +8,6 @@ declare(strict_types=1); namespace PhpMyAdmin\Plugins\Export; use PhpMyAdmin\DatabaseInterface; -use PhpMyAdmin\FieldMetadata; use PhpMyAdmin\Plugins\ExportPlugin; use PhpMyAdmin\Properties\Options\Groups\OptionsPropertyMainGroup; use PhpMyAdmin\Properties\Options\Groups\OptionsPropertyRootGroup; diff --git a/libraries/classes/Plugins/Export/ExportMediawiki.php b/libraries/classes/Plugins/Export/ExportMediawiki.php index 7626f4de89..a7a726254c 100644 --- a/libraries/classes/Plugins/Export/ExportMediawiki.php +++ b/libraries/classes/Plugins/Export/ExportMediawiki.php @@ -8,7 +8,6 @@ declare(strict_types=1); namespace PhpMyAdmin\Plugins\Export; use PhpMyAdmin\DatabaseInterface; -use PhpMyAdmin\FieldMetadata; use PhpMyAdmin\Plugins\ExportPlugin; use PhpMyAdmin\Properties\Options\Groups\OptionsPropertyMainGroup; use PhpMyAdmin\Properties\Options\Groups\OptionsPropertyRootGroup; diff --git a/libraries/classes/Plugins/Export/ExportPhparray.php b/libraries/classes/Plugins/Export/ExportPhparray.php index 881f7c12b8..caf6efb11f 100644 --- a/libraries/classes/Plugins/Export/ExportPhparray.php +++ b/libraries/classes/Plugins/Export/ExportPhparray.php @@ -8,7 +8,6 @@ declare(strict_types=1); namespace PhpMyAdmin\Plugins\Export; use PhpMyAdmin\DatabaseInterface; -use PhpMyAdmin\FieldMetadata; use PhpMyAdmin\Plugins\ExportPlugin; use PhpMyAdmin\Properties\Options\Groups\OptionsPropertyMainGroup; use PhpMyAdmin\Properties\Options\Groups\OptionsPropertyRootGroup; diff --git a/libraries/classes/Plugins/Export/ExportTexytext.php b/libraries/classes/Plugins/Export/ExportTexytext.php index adf972181a..31c4c3772d 100644 --- a/libraries/classes/Plugins/Export/ExportTexytext.php +++ b/libraries/classes/Plugins/Export/ExportTexytext.php @@ -8,7 +8,6 @@ declare(strict_types=1); namespace PhpMyAdmin\Plugins\Export; use PhpMyAdmin\DatabaseInterface; -use PhpMyAdmin\FieldMetadata; use PhpMyAdmin\Plugins\ExportPlugin; use PhpMyAdmin\Properties\Options\Groups\OptionsPropertyMainGroup; use PhpMyAdmin\Properties\Options\Groups\OptionsPropertyRootGroup; diff --git a/libraries/classes/Plugins/Export/ExportXml.php b/libraries/classes/Plugins/Export/ExportXml.php index 36b73cae11..74a33185ef 100644 --- a/libraries/classes/Plugins/Export/ExportXml.php +++ b/libraries/classes/Plugins/Export/ExportXml.php @@ -5,7 +5,6 @@ declare(strict_types=1); namespace PhpMyAdmin\Plugins\Export; use PhpMyAdmin\DatabaseInterface; -use PhpMyAdmin\FieldMetadata; use PhpMyAdmin\Plugins\ExportPlugin; use PhpMyAdmin\Properties\Options\Groups\OptionsPropertyMainGroup; use PhpMyAdmin\Properties\Options\Groups\OptionsPropertyRootGroup; diff --git a/psalm-baseline.xml b/psalm-baseline.xml index 2f809e6623..1b9d6a2786 100644 --- a/psalm-baseline.xml +++ b/psalm-baseline.xml @@ -7894,13 +7894,15 @@ self::$registry[$schema][$table] self::$registry[$schema][$table] - + + $columns['collations'][$key] $columns['sub_parts'][$key] self::$registry[$schema][$table][$keyName] self::$registry[$schema][$table][$keyName] self::$registry[$schema][$table][$keyName] - + + $collation $column $column $data['columns'][] From b47bbde6cbb1d72327a9a96faa121772a993ee4c Mon Sep 17 00:00:00 2001 From: Liviu-Mihail Concioiu Date: Thu, 19 Feb 2026 04:47:18 +0100 Subject: [PATCH 32/52] Fix baselines Signed-off-by: Liviu-Mihail Concioiu --- libraries/classes/Import.php | 2 +- phpstan-baseline.neon | 22 ++++++++++++++++------ psalm-baseline.xml | 9 ++++++--- 3 files changed, 23 insertions(+), 10 deletions(-) diff --git a/libraries/classes/Import.php b/libraries/classes/Import.php index 6ad8d092e4..143a9906d5 100644 --- a/libraries/classes/Import.php +++ b/libraries/classes/Import.php @@ -1170,7 +1170,7 @@ class Import $isVarchar = ($analyses[$i][self::TYPES][$colCount] === self::VARCHAR); } else { $isVarchar = ! is_numeric($tables[$i][self::ROWS][$j][$k]) - && ! preg_match('/^0x[0-9a-f]+$/', $tables[$i][self::ROWS][$j][$k]); + && ! preg_match('/^0x[0-9a-f]+$/', (string) $tables[$i][self::ROWS][$j][$k]); } /* Don't put quotes around NULL fields */ diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 6680a7a261..0e03a36e3c 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -20392,12 +20392,12 @@ parameters: - message: "#^Cannot access offset 2 on mixed\\.$#" - count: 8 + count: 9 path: libraries/classes/Import.php - message: "#^Cannot access offset int\\<0, max\\> on mixed\\.$#" - count: 21 + count: 22 path: libraries/classes/Import.php - @@ -20447,7 +20447,7 @@ parameters: - message: "#^Cannot cast mixed to string\\.$#" - count: 7 + count: 8 path: libraries/classes/Import.php - @@ -20557,7 +20557,7 @@ parameters: - message: "#^Only booleans are allowed in a negated boolean, int\\|false given\\.$#" - count: 1 + count: 2 path: libraries/classes/Import.php - @@ -20772,7 +20772,7 @@ parameters: - message: "#^Cannot access offset mixed on mixed\\.$#" - count: 3 + count: 4 path: libraries/classes/Index.php - @@ -35327,7 +35327,7 @@ parameters: - message: "#^Only booleans are allowed in a negated boolean, int\\|null given\\.$#" - count: 2 + count: 1 path: libraries/classes/Table.php - @@ -35340,6 +35340,11 @@ parameters: count: 3 path: libraries/classes/Table.php + - + message: "#^Only booleans are allowed in a negated boolean, string\\|null given\\.$#" + count: 1 + path: libraries/classes/Table.php + - message: "#^Only booleans are allowed in an elseif condition, int\\|false given\\.$#" count: 1 @@ -35355,6 +35360,11 @@ parameters: count: 2 path: libraries/classes/Table.php + - + message: "#^Only booleans are allowed in an if condition, int\\|null given\\.$#" + count: 1 + path: libraries/classes/Table.php + - message: "#^Only booleans are allowed in an if condition, mixed given\\.$#" count: 1 diff --git a/psalm-baseline.xml b/psalm-baseline.xml index 01239a7a1f..47f06c519e 100644 --- a/psalm-baseline.xml +++ b/psalm-baseline.xml @@ -7750,7 +7750,7 @@ $tables[$i][self::TBL_NAME] $tables[$n][self::TBL_NAME] - + $analyses[$i][self::FORMATTEDSQL][$colCount] $analyses[$i][self::SIZES] $analyses[$i][self::TYPES] @@ -7775,6 +7775,7 @@ $tables[$i][self::ROWS] $tables[$i][self::ROWS] $tables[$i][self::ROWS] + $tables[$i][self::ROWS] $tables[$i][self::TBL_NAME] $tables[$i][self::TBL_NAME] $tables[$n][self::TBL_NAME] @@ -7894,13 +7895,15 @@ self::$registry[$schema][$table] self::$registry[$schema][$table] - + + $columns['collations'][$key] $columns['sub_parts'][$key] self::$registry[$schema][$table][$keyName] self::$registry[$schema][$table][$keyName] self::$registry[$schema][$table][$keyName] - + + $collation $column $column $data['columns'][] From a0f61544f0e59ff791a62c77f58e9957bb418d25 Mon Sep 17 00:00:00 2001 From: Liviu-Mihail Concioiu Date: Thu, 19 Feb 2026 19:19:38 +0100 Subject: [PATCH 33/52] Add test case Signed-off-by: Liviu-Mihail Concioiu --- test/classes/Plugins/Import/ImportXmlTest.php | 33 +++++++ test/test_data/test.xml | 85 +++++++++++++++++++ 2 files changed, 118 insertions(+) create mode 100644 test/test_data/test.xml diff --git a/test/classes/Plugins/Import/ImportXmlTest.php b/test/classes/Plugins/Import/ImportXmlTest.php index 65f261f283..3cd5265a8f 100644 --- a/test/classes/Plugins/Import/ImportXmlTest.php +++ b/test/classes/Plugins/Import/ImportXmlTest.php @@ -117,4 +117,37 @@ class ImportXmlTest extends AbstractTestCase self::assertStringContainsString('Edit settings for `pma_bookmarktest`', $import_notice); self::assertTrue($GLOBALS['finished']); } + + /** + * Test for doImport using second dataset + * + * @group medium + * @requires extension simplexml + */ + public function testDoImportDataset2(): void + { + global $import_notice; + + $dbi = $this->getMockBuilder(DatabaseInterface::class) + ->disableOriginalConstructor() + ->getMock(); + $GLOBALS['dbi'] = $dbi; + + $GLOBALS['import_file'] = 'test/test_data/test.xml'; + + $importHandle = new File($GLOBALS['import_file']); + $importHandle->open(); + + $this->object->doImport($importHandle); + + self::assertStringContainsString( + 'The following structures have either been created or altered.', + $import_notice + ); + self::assertStringContainsString('Go to database: `test`', $import_notice); + self::assertStringContainsString('Edit settings for `test`', $import_notice); + self::assertStringContainsString('Go to table: `test`', $import_notice); + self::assertStringContainsString('Edit settings for `test`', $import_notice); + self::assertTrue($GLOBALS['finished']); + } } diff --git a/test/test_data/test.xml b/test/test_data/test.xml new file mode 100644 index 0000000000..6bdd8ed22b --- /dev/null +++ b/test/test_data/test.xml @@ -0,0 +1,85 @@ + + + + + + + + + CREATE TABLE `test` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `binary` binary(16) NOT NULL, + `name` varchar(20) NOT NULL, + `shape` geometry DEFAULT NULL, + PRIMARY KEY (`id`) + ) ENGINE=MyISAM AUTO_INCREMENT=9 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; + + + + + + + + + 1 + 0x10000000000000000000000000000000 + POLYGON + 0x00000000010300000001000000040000000000000000405f40000000000000000000000000008063400000000000006940000000000040664000000000004057400000000000405f400000000000000000 +
+ + 2 + 0x20000000000000000000000000000000 + MULTIPOLYGON + 0x00000000010600000002000000010300000001000000040000000000000000006140000000000000444000000000006062400000000000c0544000000000004064400000000000c0524000000000000061400000000000004440010300000001000000040000000000000000405a4000000000000000000000000000004c400000000000006940000000000080534000000000004057400000000000405a400000000000000000 +
+ + 3 + 0x30000000000000000000000000000000 + MULTIPOINT + 0x0000000001040000000400000001010000000000000000405f400000000000004940010100000000000000008063400000000000406f40010100000000000000004066400000000000e0614001010000000000000000e065400000000000005440 +
+ + 4 + 0x40000000000000000000000000000000 + MULTILINESTRING + 0x000000000105000000020000000102000000030000000000000000004240000000000080614000000000008047400000000000206d400000000000004f400000000000c052400102000000030000000000000000004240000000000000594000000000000031400000000000206d4000000000004066400000000000405740 +
+ + 5 + 0x50000000000000000000000000000000 + POINT + 0x00000000010100000000000000000059400000000000406f40 +
+ + 6 + 0x60000000000000000000000000000000 + LINESTRING + 0x0000000001020000000400000000000000008063400000000000003840000000000040664000000000000058400000000000606d4000000000000069400000000000a063400000000000c06140 +
+ + 7 + 0x70000000000000000000000000000000 + GEOMETRYCOLLECTION + 0x000000000107000000030000000101000000000000000000594000000000000059400102000000050000000000000000000000000000000000000000000000000059400000000000005940000000000000694000000000000069400000000000c072400000000000c07240000000000000794000000000000079400103000000020000000500000000000000008041400000000000002440000000000000244000000000000034400000000000002e40000000000000444000000000008046400000000000804640000000000080414000000000000024400400000000000000000034400000000000003e40000000000080414000000000008041400000000000003e40000000000000344000000000000034400000000000003e40 +
+ + 8 + 0x80000000000000000000000000000000 + TEST + NULL +
+
+
From f9d5c506535bf8481ca9b8d9cb1ff0b757552bc3 Mon Sep 17 00:00:00 2001 From: Liviu-Mihail Concioiu Date: Thu, 19 Feb 2026 19:39:24 +0100 Subject: [PATCH 34/52] Update baselines Signed-off-by: Liviu-Mihail Concioiu --- phpstan-baseline.neon | 2 +- psalm-baseline.xml | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 0e03a36e3c..d73ed35131 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -46932,7 +46932,7 @@ parameters: - message: "#^Parameter \\#2 \\$haystack of static method PHPUnit\\\\Framework\\\\Assert\\:\\:assertStringContainsString\\(\\) expects string, mixed given\\.$#" - count: 5 + count: 10 path: test/classes/Plugins/Import/ImportXmlTest.php - diff --git a/psalm-baseline.xml b/psalm-baseline.xml index 47f06c519e..9915269832 100644 --- a/psalm-baseline.xml +++ b/psalm-baseline.xml @@ -15995,7 +15995,8 @@
- + + $import_notice $import_notice From d3ecb785ee821b99e7372a454596420055ea38a5 Mon Sep 17 00:00:00 2001 From: Liviu-Mihail Concioiu Date: Thu, 19 Feb 2026 19:49:00 +0100 Subject: [PATCH 35/52] Revert "Update baselines" This reverts commit f9d5c506535bf8481ca9b8d9cb1ff0b757552bc3. --- phpstan-baseline.neon | 2 +- psalm-baseline.xml | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index d73ed35131..0e03a36e3c 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -46932,7 +46932,7 @@ parameters: - message: "#^Parameter \\#2 \\$haystack of static method PHPUnit\\\\Framework\\\\Assert\\:\\:assertStringContainsString\\(\\) expects string, mixed given\\.$#" - count: 10 + count: 5 path: test/classes/Plugins/Import/ImportXmlTest.php - diff --git a/psalm-baseline.xml b/psalm-baseline.xml index 9915269832..47f06c519e 100644 --- a/psalm-baseline.xml +++ b/psalm-baseline.xml @@ -15995,8 +15995,7 @@ - - $import_notice + $import_notice From 9e096535634c66834bdbcacb3181cfff80aca9f1 Mon Sep 17 00:00:00 2001 From: Liviu-Mihail Concioiu Date: Thu, 19 Feb 2026 19:50:18 +0100 Subject: [PATCH 36/52] Update baselines Signed-off-by: Liviu-Mihail Concioiu --- phpstan-baseline.neon | 2 +- psalm-baseline.xml | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 0e03a36e3c..d73ed35131 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -46932,7 +46932,7 @@ parameters: - message: "#^Parameter \\#2 \\$haystack of static method PHPUnit\\\\Framework\\\\Assert\\:\\:assertStringContainsString\\(\\) expects string, mixed given\\.$#" - count: 5 + count: 10 path: test/classes/Plugins/Import/ImportXmlTest.php - diff --git a/psalm-baseline.xml b/psalm-baseline.xml index 47f06c519e..9915269832 100644 --- a/psalm-baseline.xml +++ b/psalm-baseline.xml @@ -15995,7 +15995,8 @@ - + + $import_notice $import_notice From 45968657cb3d1f19a0dab3fc2bd8e23447c3d3ec Mon Sep 17 00:00:00 2001 From: Liviu-Mihail Concioiu Date: Sat, 21 Feb 2026 03:00:15 +0100 Subject: [PATCH 37/52] Show sql-highlight div only if CodeMirror is enabled Signed-off-by: Liviu-Mihail Concioiu --- js/src/functions.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/js/src/functions.js b/js/src/functions.js index ce9532f20c..d617e484e2 100644 --- a/js/src/functions.js +++ b/js/src/functions.js @@ -1718,9 +1718,9 @@ Functions.highlightSql = function ($base) { var $pre = $sql.find('pre'); /* We only care about visible elements to avoid double processing */ if ($pre.is(':visible')) { - var $highlight = $('
'); - $sql.append($highlight); if (typeof CodeMirror !== 'undefined') { + var $highlight = $('
'); + $sql.append($highlight); CodeMirror.runMode($sql.text(), 'text/x-mysql', $highlight[0]); $pre.hide(); $highlight.find('.cm-keyword').each(Functions.documentationKeyword); From df8beb464c3d1d4a4ad267537af6ab6d737b69af Mon Sep 17 00:00:00 2001 From: Liviu-Mihail Concioiu Date: Sun, 22 Feb 2026 17:21:20 +0100 Subject: [PATCH 38/52] Set user-agent to null if not defined Signed-off-by: Liviu-Mihail Concioiu --- libraries/classes/ErrorReport.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/classes/ErrorReport.php b/libraries/classes/ErrorReport.php index 9f6a305a69..65cab944a1 100644 --- a/libraries/classes/ErrorReport.php +++ b/libraries/classes/ErrorReport.php @@ -86,7 +86,7 @@ class ErrorReport 'browser_version' => $this->config->get('PMA_USR_BROWSER_VER'), 'user_os' => $this->config->get('PMA_USR_OS'), 'server_software' => $_SERVER['SERVER_SOFTWARE'] ?? null, - 'user_agent_string' => $_SERVER['HTTP_USER_AGENT'], + 'user_agent_string' => $_SERVER['HTTP_USER_AGENT'] ?? null, 'locale' => $this->config->getCookie('pma_lang'), 'configuration_storage' => $relationParameters->db === null ? 'disabled' : 'enabled', 'php_version' => PHP_VERSION, From 56822a6b58646495a4a382f2ac533ccdfc8a5ad8 Mon Sep 17 00:00:00 2001 From: Liviu-Mihail Concioiu Date: Sun, 22 Feb 2026 20:10:47 +0100 Subject: [PATCH 39/52] Fix Uncaught ReferenceError: CodeMirror is not defined Signed-off-by: Liviu-Mihail Concioiu --- libraries/classes/Header.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libraries/classes/Header.php b/libraries/classes/Header.php index 7916094469..558ad289c1 100644 --- a/libraries/classes/Header.php +++ b/libraries/classes/Header.php @@ -334,7 +334,8 @@ class Header // The user preferences have been merged at this point // so we can conditionally add CodeMirror, other scripts and settings - if ($GLOBALS['cfg']['CodemirrorEnable']) { + // See #20159, why we need to check for HTTP_USER_AGENT here + if ($GLOBALS['cfg']['CodemirrorEnable'] && isset($_SERVER['HTTP_USER_AGENT'])) { $this->scripts->addFile('vendor/codemirror/lib/codemirror.js'); $this->scripts->addFile('vendor/codemirror/mode/sql/sql.js'); $this->scripts->addFile('vendor/codemirror/addon/runmode/runmode.js'); From 9ce6792f2b36e0b320e64ce214d76e07d35f687b Mon Sep 17 00:00:00 2001 From: Liviu-Mihail Concioiu Date: Sun, 22 Feb 2026 21:11:13 +0100 Subject: [PATCH 40/52] Implement userAgent function Signed-off-by: Liviu-Mihail Concioiu --- js/src/functions.js | 13 ++++++++++++- js/src/makegrid.js | 10 +++++----- 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/js/src/functions.js b/js/src/functions.js index ce9532f20c..3f308169a3 100644 --- a/js/src/functions.js +++ b/js/src/functions.js @@ -103,6 +103,17 @@ $.ajaxPrefilter(function (options, originalOptions) { } }); +/** + * Get an empty string for user-agent, if undefined + */ +Functions.userAgent = function () { + try { + return navigator.userAgent; + } catch { + return ''; + } +}; + /** * Adds a date/time picker to an element * @@ -1095,7 +1106,7 @@ AJAX.registerOnload('functions.js', function () { /** * Add attribute to text boxes for iOS devices (based on bugID: 3508912) */ - if (navigator.userAgent.match(/(iphone|ipod|ipad)/i)) { + if (Functions.userAgent().match(/(iphone|ipod|ipad)/i)) { $('input[type=text]').attr('autocapitalize', 'off').attr('autocorrect', 'off'); } }); diff --git a/js/src/makegrid.js b/js/src/makegrid.js index 54bef74551..74dd32680a 100644 --- a/js/src/makegrid.js +++ b/js/src/makegrid.js @@ -260,7 +260,7 @@ var makeGrid = function (t, enableResize, enableReorder, enableVisib, enableGrid for (var n = 0, l = $firstRowCols.length; n < l; n++) { var $col = $($firstRowCols[n]); var colWidth; - if (navigator.userAgent.toLowerCase().indexOf('safari') !== -1) { + if (Functions.userAgent().toLowerCase().indexOf('safari') !== -1) { colWidth = $col.outerWidth(); } else { colWidth = $col.outerWidth(true); @@ -2317,10 +2317,10 @@ var makeGrid = function (t, enableResize, enableReorder, enableVisib, enableGrid $.fn.noSelect = function (p) { // no select plugin by Paulo P.Marinas var prevent = (p === null) ? true : p; /* eslint-disable compat/compat */ - var isMsie = navigator.userAgent.indexOf('MSIE') > -1 || !!window.navigator.userAgent.match(/Trident.*rv:11\./); - var isFirefox = navigator.userAgent.indexOf('Firefox') > -1; - var isSafari = navigator.userAgent.indexOf('Safari') > -1; - var isOpera = navigator.userAgent.indexOf('Presto') > -1; + var isMsie = Functions.userAgent().indexOf('MSIE') > -1 || !!Functions.userAgent().match(/Trident.*rv:11\./); + var isFirefox = Functions.userAgent().indexOf('Firefox') > -1; + var isSafari = Functions.userAgent().indexOf('Safari') > -1; + var isOpera = Functions.userAgent().indexOf('Presto') > -1; /* eslint-enable compat/compat */ if (prevent) { return this.each(function () { From 1dc05380989cdd1b0cc9c1b51da0f097697f48e6 Mon Sep 17 00:00:00 2001 From: Liviu-Mihail Concioiu Date: Sun, 22 Feb 2026 21:40:54 +0100 Subject: [PATCH 41/52] Fix js-lint Signed-off-by: Liviu-Mihail Concioiu --- js/src/functions.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/src/functions.js b/js/src/functions.js index 3f308169a3..ecc1a5bdd4 100644 --- a/js/src/functions.js +++ b/js/src/functions.js @@ -109,7 +109,7 @@ $.ajaxPrefilter(function (options, originalOptions) { Functions.userAgent = function () { try { return navigator.userAgent; - } catch { + } catch (e) { return ''; } }; From 0a2af932bbe8048293f6d785463031c780a1fb61 Mon Sep 17 00:00:00 2001 From: Liviu-Mihail Concioiu Date: Sun, 22 Feb 2026 21:44:09 +0100 Subject: [PATCH 42/52] Fix js-lint Signed-off-by: Liviu-Mihail Concioiu --- js/src/functions.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/js/src/functions.js b/js/src/functions.js index ecc1a5bdd4..66bde267ea 100644 --- a/js/src/functions.js +++ b/js/src/functions.js @@ -105,6 +105,8 @@ $.ajaxPrefilter(function (options, originalOptions) { /** * Get an empty string for user-agent, if undefined + * + * @return {string} */ Functions.userAgent = function () { try { From aa812dba65970d0ca590251258712600b0a96a64 Mon Sep 17 00:00:00 2001 From: Liviu-Mihail Concioiu Date: Mon, 23 Feb 2026 13:09:08 +0100 Subject: [PATCH 43/52] Show error in console Signed-off-by: Liviu-Mihail Concioiu --- js/src/functions.js | 1 + 1 file changed, 1 insertion(+) diff --git a/js/src/functions.js b/js/src/functions.js index 66bde267ea..e42f853d03 100644 --- a/js/src/functions.js +++ b/js/src/functions.js @@ -112,6 +112,7 @@ Functions.userAgent = function () { try { return navigator.userAgent; } catch (e) { + console.error(e); return ''; } }; From 5423ae3e0d55a910d2ea33d9274beda1e3fa1d96 Mon Sep 17 00:00:00 2001 From: Liviu-Mihail Concioiu Date: Mon, 23 Feb 2026 16:02:30 +0100 Subject: [PATCH 44/52] Fix XML test Signed-off-by: Liviu-Mihail Concioiu --- test/classes/Plugins/Import/ImportXmlTest.php | 40 +++++++++---------- 1 file changed, 18 insertions(+), 22 deletions(-) diff --git a/test/classes/Plugins/Import/ImportXmlTest.php b/test/classes/Plugins/Import/ImportXmlTest.php index 3cd5265a8f..e64ee1ad6d 100644 --- a/test/classes/Plugins/Import/ImportXmlTest.php +++ b/test/classes/Plugins/Import/ImportXmlTest.php @@ -79,7 +79,7 @@ class ImportXmlTest extends AbstractTestCase public function testDoImport(): void { //$import_notice will show the import detail result - global $import_notice; + global $sql_query; //Mock DBI $dbi = $this->getMockBuilder(DatabaseInterface::class) @@ -93,28 +93,24 @@ class ImportXmlTest extends AbstractTestCase //Test function called $this->object->doImport($importHandle); - // If import successfully, PMA will show all databases and tables - // imported as following HTML Page - /* - The following structures have either been created or altered. Here you - can: - View a structure's contents by clicking on its name - Change any of its settings by clicking the corresponding "Options" link - Edit structure by following the "Structure" link - - phpmyadmintest (Options) - pma_bookmarktest (Structure) (Options) - */ - - //asset that all databases and tables are imported - self::assertStringContainsString( - 'The following structures have either been created or altered.', - $import_notice + //assert that all sql are executed + self::assertSame( + 'CREATE DATABASE IF NOT EXISTS `phpmyadmintest` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;;' + . 'USE `phpmyadmintest`;' . "\n" + . 'CREATE TABLE IF NOT EXISTS `pma_bookmarktest` (' . "\n" + . ' `id` int(11) NOT NULL AUTO_INCREMENT,' . "\n" + . ' `dbase` varchar(255) COLLATE utf8_bin NOT NULL DEFAULT \'\',' . "\n" + . ' `user` varchar(255) COLLATE utf8_bin NOT NULL DEFAULT \'\',' . "\n" + . ' `label` varchar(255) CHARACTER SET utf8 NOT NULL DEFAULT \'\',' . "\n" + . ' `query` text COLLATE utf8_bin NOT NULL,' . "\n" + . ' PRIMARY KEY (`id`)' . "\n" + . ') ENGINE=MyISAM AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT=\'Bookmarks\';' . "\n" + . ' ;' + . 'INSERT INTO `phpmyadmintest`.`pma_bookmarktest` (`id`, `dbase`, `user`, `label`, `query`) ' + . 'VALUES (, \'\', \'\', \'\', \'\');;', + $sql_query, ); - self::assertStringContainsString('Go to database: `phpmyadmintest`', $import_notice); - self::assertStringContainsString('Edit settings for `phpmyadmintest`', $import_notice); - self::assertStringContainsString('Go to table: `pma_bookmarktest`', $import_notice); - self::assertStringContainsString('Edit settings for `pma_bookmarktest`', $import_notice); + self::assertTrue($GLOBALS['finished']); } From c9097e2c9e2cc53207c613be69bfa29c3e8749d1 Mon Sep 17 00:00:00 2001 From: Liviu-Mihail Concioiu Date: Mon, 23 Feb 2026 16:06:29 +0100 Subject: [PATCH 45/52] Remove comma Signed-off-by: Liviu-Mihail Concioiu --- test/classes/Plugins/Import/ImportXmlTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/classes/Plugins/Import/ImportXmlTest.php b/test/classes/Plugins/Import/ImportXmlTest.php index e64ee1ad6d..6a996d556d 100644 --- a/test/classes/Plugins/Import/ImportXmlTest.php +++ b/test/classes/Plugins/Import/ImportXmlTest.php @@ -108,7 +108,7 @@ class ImportXmlTest extends AbstractTestCase . ' ;' . 'INSERT INTO `phpmyadmintest`.`pma_bookmarktest` (`id`, `dbase`, `user`, `label`, `query`) ' . 'VALUES (, \'\', \'\', \'\', \'\');;', - $sql_query, + $sql_query ); self::assertTrue($GLOBALS['finished']); From 2f09b5cc4eede20c56827ed510eeaedcc75b38ea Mon Sep 17 00:00:00 2001 From: Liviu-Mihail Concioiu Date: Mon, 23 Feb 2026 17:19:16 +0100 Subject: [PATCH 46/52] Update baseline Signed-off-by: Liviu-Mihail Concioiu --- phpstan-baseline.neon | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 45256e9222..4e35312b2b 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -47077,7 +47077,7 @@ parameters: - message: "#^Parameter \\#2 \\$haystack of static method PHPUnit\\\\Framework\\\\Assert\\:\\:assertStringContainsString\\(\\) expects string, mixed given\\.$#" - count: 10 + count: 5 path: test/classes/Plugins/Import/ImportXmlTest.php - From e96c516f9a0f8727fd1f5383387dcbd307ceabb0 Mon Sep 17 00:00:00 2001 From: William Desportes Date: Tue, 24 Feb 2026 09:45:54 +0100 Subject: [PATCH 47/52] Update the psalm baseline --- psalm-baseline.xml | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/psalm-baseline.xml b/psalm-baseline.xml index d2204f7f98..3d9c046e6c 100644 --- a/psalm-baseline.xml +++ b/psalm-baseline.xml @@ -6492,9 +6492,6 @@ $_POST['url'] $exception['url'] - - $_SERVER['HTTP_USER_AGENT'] - @@ -9658,9 +9655,6 @@ $do_mime $do_relation - - $row[$i] - @@ -15987,8 +15981,7 @@ - - $import_notice + $import_notice From 16d63808053854e6d59b0e9805898b6232f4e325 Mon Sep 17 00:00:00 2001 From: William Desportes Date: Tue, 24 Feb 2026 10:23:55 +0100 Subject: [PATCH 48/52] Fix a coding standard warning Signed-off-by: William Desportes --- libraries/classes/Controllers/JavaScriptMessagesController.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libraries/classes/Controllers/JavaScriptMessagesController.php b/libraries/classes/Controllers/JavaScriptMessagesController.php index d2ed13f9d4..43601b0e9a 100644 --- a/libraries/classes/Controllers/JavaScriptMessagesController.php +++ b/libraries/classes/Controllers/JavaScriptMessagesController.php @@ -711,7 +711,8 @@ final class JavaScriptMessagesController 'strShow' => __('Show'), 'strStructure' => __('Structure'), 'strFullscreenRequestDenied' => __( - 'The fullscreen request was denied because the Fullscreen API is disabled by user preference in the browser.' + 'The fullscreen request was denied because' + . ' the Fullscreen API is disabled by user preference in the browser.' ), ]; } From 8da964fa4046fe4932a1ef17718df5d7778999bb Mon Sep 17 00:00:00 2001 From: William Desportes Date: Tue, 24 Feb 2026 10:25:07 +0100 Subject: [PATCH 49/52] Move login to setUp() of parent:: Signed-off-by: William Desportes --- test/selenium/ChangePasswordTest.php | 4 +--- test/selenium/CreateDropDatabaseTest.php | 1 - test/selenium/CreateRemoveUserTest.php | 3 +-- test/selenium/Database/EventsTest.php | 2 +- test/selenium/Database/OperationsTest.php | 9 --------- test/selenium/Database/ProceduresTest.php | 2 -- test/selenium/Database/QueryByExampleTest.php | 2 -- test/selenium/Database/StructureTest.php | 1 - test/selenium/Database/TriggersTest.php | 2 -- test/selenium/ExportTest.php | 2 -- test/selenium/ImportTest.php | 9 --------- test/selenium/LoginTest.php | 9 ++++++++- test/selenium/NormalizationTest.php | 1 - test/selenium/ServerSettingsTest.php | 2 +- test/selenium/SqlQueryTest.php | 1 - test/selenium/Table/BrowseTest.php | 1 - test/selenium/Table/CreateTest.php | 2 -- test/selenium/Table/InsertTest.php | 1 - test/selenium/Table/OperationsTest.php | 1 - test/selenium/Table/StructureTest.php | 1 - test/selenium/TestBase.php | 15 +++++++++++++-- test/selenium/TrackingTest.php | 1 - test/selenium/XssTest.php | 8 +------- 23 files changed, 26 insertions(+), 54 deletions(-) diff --git a/test/selenium/ChangePasswordTest.php b/test/selenium/ChangePasswordTest.php index a1e063ee35..257a58b4dd 100644 --- a/test/selenium/ChangePasswordTest.php +++ b/test/selenium/ChangePasswordTest.php @@ -19,7 +19,7 @@ class ChangePasswordTest extends TestBase * * @var bool */ - protected static $createDatabase = false; + protected $createDatabase = false; /** * Array of AssertionFailedError->toString @@ -35,8 +35,6 @@ class ChangePasswordTest extends TestBase */ public function testChangePassword(): void { - $this->login(); - $e = $this->waitForElement('id', 'change_password_anchor'); $e->click(); diff --git a/test/selenium/CreateDropDatabaseTest.php b/test/selenium/CreateDropDatabaseTest.php index decfb476bf..d6fb0c55f5 100644 --- a/test/selenium/CreateDropDatabaseTest.php +++ b/test/selenium/CreateDropDatabaseTest.php @@ -17,7 +17,6 @@ class CreateDropDatabaseTest extends TestBase parent::setUp(); /* TODO: For now this tests needs superuser for deleting database */ $this->skipIfNotSuperUser(); - $this->login(); } /** diff --git a/test/selenium/CreateRemoveUserTest.php b/test/selenium/CreateRemoveUserTest.php index 3c25762175..ac59fb3969 100644 --- a/test/selenium/CreateRemoveUserTest.php +++ b/test/selenium/CreateRemoveUserTest.php @@ -14,7 +14,7 @@ class CreateRemoveUserTest extends TestBase * * @var bool */ - protected static $createDatabase = false; + protected $createDatabase = false; /** * Username for the user @@ -39,7 +39,6 @@ class CreateRemoveUserTest extends TestBase $this->skipIfNotSuperUser(); $this->txtUsername = 'pma_user'; $this->txtPassword = 'abc_123'; - $this->login(); } /** diff --git a/test/selenium/Database/EventsTest.php b/test/selenium/Database/EventsTest.php index b97555448b..3d00955c52 100644 --- a/test/selenium/Database/EventsTest.php +++ b/test/selenium/Database/EventsTest.php @@ -31,7 +31,7 @@ class EventsTest extends TestBase . 'INSERT INTO `test_table` (val) VALUES (2);' . 'SET GLOBAL event_scheduler="ON";' ); - $this->login(); + $this->navigateDatabase($this->databaseName); // Let the Database page load diff --git a/test/selenium/Database/OperationsTest.php b/test/selenium/Database/OperationsTest.php index 816cd17d94..0f217e138a 100644 --- a/test/selenium/Database/OperationsTest.php +++ b/test/selenium/Database/OperationsTest.php @@ -11,15 +11,6 @@ use PhpMyAdmin\Tests\Selenium\TestBase; */ class OperationsTest extends TestBase { - /** - * setUp function - */ - protected function setUp(): void - { - parent::setUp(); - $this->login(); - } - private function getToDBOperations(): void { $this->gotoHomepage(); diff --git a/test/selenium/Database/ProceduresTest.php b/test/selenium/Database/ProceduresTest.php index 537ed2460a..673a6bd37f 100644 --- a/test/selenium/Database/ProceduresTest.php +++ b/test/selenium/Database/ProceduresTest.php @@ -49,8 +49,6 @@ class ProceduresTest extends TestBase . ');' ); - $this->login(); - $this->navigateDatabase($this->databaseName); $this->expandMore(); } diff --git a/test/selenium/Database/QueryByExampleTest.php b/test/selenium/Database/QueryByExampleTest.php index 247f47e733..8d31cac8b7 100644 --- a/test/selenium/Database/QueryByExampleTest.php +++ b/test/selenium/Database/QueryByExampleTest.php @@ -29,8 +29,6 @@ class QueryByExampleTest extends TestBase . ');' . 'INSERT INTO `test_table` (val) VALUES (2), (6), (5), (3), (4), (4), (5);' ); - - $this->login(); } /** diff --git a/test/selenium/Database/StructureTest.php b/test/selenium/Database/StructureTest.php index 69fd376a35..4134a12dc2 100644 --- a/test/selenium/Database/StructureTest.php +++ b/test/selenium/Database/StructureTest.php @@ -32,7 +32,6 @@ class StructureTest extends TestBase . 'INSERT INTO `test_table` (val) VALUES (2);' ); - $this->login(); $this->navigateDatabase($this->databaseName); // Let the Database page load diff --git a/test/selenium/Database/TriggersTest.php b/test/selenium/Database/TriggersTest.php index 289bf9da83..7cad297758 100644 --- a/test/selenium/Database/TriggersTest.php +++ b/test/selenium/Database/TriggersTest.php @@ -32,8 +32,6 @@ class TriggersTest extends TestBase . 'INSERT INTO `test_table2` (val) VALUES (2);' ); - $this->login(); - $this->navigateDatabase($this->databaseName); } diff --git a/test/selenium/ExportTest.php b/test/selenium/ExportTest.php index 320e8eeaeb..c5827e8d97 100644 --- a/test/selenium/ExportTest.php +++ b/test/selenium/ExportTest.php @@ -24,8 +24,6 @@ class ExportTest extends TestBase . ');' . 'INSERT INTO `test_table` (val) VALUES (2);' ); - - $this->login(); } /** diff --git a/test/selenium/ImportTest.php b/test/selenium/ImportTest.php index c0e26fccc6..79f6694982 100644 --- a/test/selenium/ImportTest.php +++ b/test/selenium/ImportTest.php @@ -9,15 +9,6 @@ namespace PhpMyAdmin\Tests\Selenium; */ class ImportTest extends TestBase { - /** - * setUp function - */ - protected function setUp(): void - { - parent::setUp(); - $this->login(); - } - /** * Test for server level import * diff --git a/test/selenium/LoginTest.php b/test/selenium/LoginTest.php index 7e5344237a..45fdf6f0fa 100644 --- a/test/selenium/LoginTest.php +++ b/test/selenium/LoginTest.php @@ -14,7 +14,14 @@ class LoginTest extends TestBase * * @var bool */ - protected static $createDatabase = false; + protected $createDatabase = false; + + /** + * Login before starting this test + * + * @var bool + */ + protected $login = false; protected function setUp(): void { diff --git a/test/selenium/NormalizationTest.php b/test/selenium/NormalizationTest.php index f0a13b91f9..45a4caf824 100644 --- a/test/selenium/NormalizationTest.php +++ b/test/selenium/NormalizationTest.php @@ -25,7 +25,6 @@ class NormalizationTest extends TestBase . ');' ); - $this->login(); $this->navigateTable('test_table'); $this->waitForElement('xpath', "(//a[contains(., 'Structure')])")->click(); diff --git a/test/selenium/ServerSettingsTest.php b/test/selenium/ServerSettingsTest.php index a797189808..2111b6eaa7 100644 --- a/test/selenium/ServerSettingsTest.php +++ b/test/selenium/ServerSettingsTest.php @@ -16,7 +16,7 @@ class ServerSettingsTest extends TestBase * * @var bool */ - protected static $createDatabase = false; + protected $createDatabase = false; /** * setUp function diff --git a/test/selenium/SqlQueryTest.php b/test/selenium/SqlQueryTest.php index 819a729670..bc7b8b69d3 100644 --- a/test/selenium/SqlQueryTest.php +++ b/test/selenium/SqlQueryTest.php @@ -25,7 +25,6 @@ class SqlQueryTest extends TestBase . ');' . 'INSERT INTO `test_table` (val) VALUES (2), (3), (4), (5);' ); - $this->login(); } /** diff --git a/test/selenium/Table/BrowseTest.php b/test/selenium/Table/BrowseTest.php index a22b869550..33f4a4d956 100644 --- a/test/selenium/Table/BrowseTest.php +++ b/test/selenium/Table/BrowseTest.php @@ -32,7 +32,6 @@ class BrowseTest extends TestBase . " (3, 'Abcd', '2012-01-20 02:00:02');" ); - $this->login(); $this->navigateTable('test_table'); $this->waitAjax(); diff --git a/test/selenium/Table/CreateTest.php b/test/selenium/Table/CreateTest.php index 8a687cc963..8290cfaf4f 100644 --- a/test/selenium/Table/CreateTest.php +++ b/test/selenium/Table/CreateTest.php @@ -16,8 +16,6 @@ class CreateTest extends TestBase protected function setUp(): void { parent::setUp(); - - $this->login(); $this->navigateDatabase($this->databaseName); } diff --git a/test/selenium/Table/InsertTest.php b/test/selenium/Table/InsertTest.php index faf13e68d3..4b5c528aa6 100644 --- a/test/selenium/Table/InsertTest.php +++ b/test/selenium/Table/InsertTest.php @@ -28,7 +28,6 @@ class InsertTest extends TestBase . ');' ); - $this->login(); $this->navigateTable('test_table'); } diff --git a/test/selenium/Table/OperationsTest.php b/test/selenium/Table/OperationsTest.php index 6362abe866..7183c8bdea 100644 --- a/test/selenium/Table/OperationsTest.php +++ b/test/selenium/Table/OperationsTest.php @@ -32,7 +32,6 @@ class OperationsTest extends TestBase . 'INSERT INTO test_table (val, val2) VALUES (33, 44);' ); - $this->login(); $this->navigateTable('test_table'); $this->waitAjax(); diff --git a/test/selenium/Table/StructureTest.php b/test/selenium/Table/StructureTest.php index d8c82cfb4c..d5dbdd832b 100644 --- a/test/selenium/Table/StructureTest.php +++ b/test/selenium/Table/StructureTest.php @@ -27,7 +27,6 @@ class StructureTest extends TestBase . ');' ); - $this->login(); $this->navigateTable('test_table'); $this->waitForElement('xpath', "(//a[contains(., 'Structure')])")->click(); diff --git a/test/selenium/TestBase.php b/test/selenium/TestBase.php index e03e2754d2..fd3f74db7e 100644 --- a/test/selenium/TestBase.php +++ b/test/selenium/TestBase.php @@ -95,7 +95,14 @@ abstract class TestBase extends TestCase * * @var bool */ - protected static $createDatabase = true; + protected $createDatabase = true; + + /** + * Login before starting this test + * + * @var bool + */ + protected $login = true; /** * Did the test create the phpMyAdmin storage database ? @@ -148,7 +155,11 @@ abstract class TestBase extends TestCase $this->navigateTo(''); $this->webDriver->manage()->window()->maximize(); - if (! static::$createDatabase) { + if ($this->login) { + $this->login(); + } + + if (! $this->createDatabase) { // Stop here, we where not asked to create a database return; } diff --git a/test/selenium/TrackingTest.php b/test/selenium/TrackingTest.php index a5b6dba27e..3a66ef75d2 100644 --- a/test/selenium/TrackingTest.php +++ b/test/selenium/TrackingTest.php @@ -30,7 +30,6 @@ class TrackingTest extends TestBase . 'INSERT INTO `test_table` (val) VALUES (2), (3);' ); - $this->login(); $this->skipIfNotPMADB(); $this->navigateDatabase($this->databaseName); diff --git a/test/selenium/XssTest.php b/test/selenium/XssTest.php index 4ebc2b7b36..8972c694c3 100644 --- a/test/selenium/XssTest.php +++ b/test/selenium/XssTest.php @@ -14,13 +14,7 @@ class XssTest extends TestBase * * @var bool */ - protected static $createDatabase = false; - - protected function setUp(): void - { - parent::setUp(); - $this->login(); - } + protected $createDatabase = false; /** * Tests the SQL query tab with a null query From 5139170303d3c6309fc613e0b7eea4942773bcea Mon Sep 17 00:00:00 2001 From: William Desportes Date: Tue, 24 Feb 2026 10:32:13 +0100 Subject: [PATCH 50/52] Import test-selenium from the master branch - Adjust for QA - Add node-version variable Signed-off-by: William Desportes --- .github/workflows/test-selenium.yml | 59 ++++++++++++++++++++--------- 1 file changed, 42 insertions(+), 17 deletions(-) diff --git a/.github/workflows/test-selenium.yml b/.github/workflows/test-selenium.yml index 8003803af7..6addda9d86 100644 --- a/.github/workflows/test-selenium.yml +++ b/.github/workflows/test-selenium.yml @@ -1,4 +1,4 @@ -name: Run Selenium tests +name: "End-to-End tests" on: push: @@ -11,14 +11,18 @@ on: permissions: contents: read +env: + php-version: "7.2" + node-version: "12" + jobs: - test-selenium: - name: Selenium tests on PHP ${{ matrix.php-version }} and ${{ matrix.os }} + selenium: + name: "Selenium" if: "!contains(github.event.head_commit.message, '[ci selenium skip]')" - runs-on: ${{ matrix.os }} + runs-on: "ubuntu-latest" services: database-server: - image: ${{ matrix.db-server }} + image: "mysql:5.7" env: MYSQL_ROOT_PASSWORD: testbench ports: @@ -53,10 +57,30 @@ jobs: --cap-add=NET_RAW --restart on-failure strategy: + fail-fast: false matrix: - php-version: ["7.2"] - os: [ubuntu-latest] - db-server: ["mysql:5.7"] + test-name: + - "ChangePassword" + - "CreateDropDatabase" + - "CreateRemoveUser" + - "Database/Events" + - "Database/Operations" + - "Database/Procedures" + - "Database/Structure" + - "Export" + - "Import" + - "Login" + - "Normalization" + - "ServerSettings" + - "SqlQuery" + - "Table/Browse" + - "Table/Create" + - "Table/Insert" + - "Table/Operations" + - "Table/Structure" + - "Tracking" + - "Triggers" + - "Xss" steps: - name: Checkout code uses: actions/checkout@v6 @@ -67,21 +91,20 @@ jobs: - name: Generate mo files run: ./scripts/generate-mo --quiet - - name: Set up PHP ${{ matrix.php-version }} + - name: Set up PHP ${{ env.php-version }} uses: shivammathur/setup-php@v2 with: - php-version: ${{ matrix.php-version }} - extensions: mbstring, iconv, mysqli, zip, gd, bz2 + coverage: "none" + php-version: ${{ env.php-version }} + extensions: :opcache, mbstring, iconv, mysqli, zip, gd, bz2 - name: Install Composer dependencies uses: ramsey/composer-install@v3 - with: - dependency-versions: highest - name: Set up Node uses: actions/setup-node@v6 with: - node-version: 12 + node-version: '${{ env.node-version }}' cache: 'yarn' - name: Install modules @@ -93,9 +116,11 @@ jobs: - name: Start server env: CI_MODE: selenium - FPM_PATH: php-fpm7.2 + FPM_PATH: php-fpm${{ env.php-version }} SKIP_STANDALONE: 1 run: | + sudo chown -R runner:docker /var/lib/nginx/ + sudo chown -R runner:docker /var/log/nginx/ ./test/start-local-server echo "SELENIUM_TEMPDIR=$(cat /tmp/last_temp_dir_phpMyAdminTests)" >> $GITHUB_OUTPUT id: start-local-server @@ -111,7 +136,7 @@ jobs: TESTSUITE_DATABASE_PREFIX: "selenium" TESTSUITE_SELENIUM_HOST: "127.0.0.1" TESTSUITE_SELENIUM_PORT: "4444" - run: ./vendor/bin/phpunit --testsuite selenium --verbose --debug --no-coverage --stop-on-skipped + run: ./vendor/bin/phpunit --testsuite selenium --no-logging --no-coverage --stop-on-skipped --testdox test/selenium/${{ matrix.test-name }}Test.php - name: Output logs and stop server env: @@ -127,6 +152,6 @@ jobs: uses: actions/upload-artifact@v6 if: ${{ failure() }} with: - name: selenium-screenshots + name: selenium-screenshots-${{ strategy.job-index }} path: ${{ github.workspace }}/build/selenium/**/* retention-days: 3 From 59c349958bd9cd31eb42ad768d82c3690e2f1439 Mon Sep 17 00:00:00 2001 From: William Desportes Date: Tue, 24 Feb 2026 10:48:46 +0100 Subject: [PATCH 51/52] Generate a dynamic matrix of test names for Selenium tests Signed-off-by: William Desportes --- .github/workflows/test-selenium.yml | 39 +++++++++++++---------------- 1 file changed, 17 insertions(+), 22 deletions(-) diff --git a/.github/workflows/test-selenium.yml b/.github/workflows/test-selenium.yml index 6addda9d86..98aa769b39 100644 --- a/.github/workflows/test-selenium.yml +++ b/.github/workflows/test-selenium.yml @@ -16,9 +16,25 @@ env: node-version: "12" jobs: + generate-matrix: + name: Generate the matrix of Selenium tests + if: "!contains(github.event.head_commit.message, '[ci selenium skip]')" + runs-on: ubuntu-latest + outputs: + tests: ${{ steps.tests-list.outputs.tests }} + steps: + - name: Checkout code + uses: actions/checkout@v6 + - id: tests-list + name: Send test names to outputs + run: | + set -euo pipefail + TEST_NAMES="[$(find $PWD/test/selenium/ -type f -name '*Test.php' -print |sed -E "s,$PWD/test/selenium/(.*)Test.php,{\"test-name\": \"\1\"}," | paste -sd ",")]" + echo "tests=$(printf "$TEST_NAMES")" >> $GITHUB_OUTPUT selenium: name: "Selenium" if: "!contains(github.event.head_commit.message, '[ci selenium skip]')" + needs: generate-matrix runs-on: "ubuntu-latest" services: database-server: @@ -59,28 +75,7 @@ jobs: strategy: fail-fast: false matrix: - test-name: - - "ChangePassword" - - "CreateDropDatabase" - - "CreateRemoveUser" - - "Database/Events" - - "Database/Operations" - - "Database/Procedures" - - "Database/Structure" - - "Export" - - "Import" - - "Login" - - "Normalization" - - "ServerSettings" - - "SqlQuery" - - "Table/Browse" - - "Table/Create" - - "Table/Insert" - - "Table/Operations" - - "Table/Structure" - - "Tracking" - - "Triggers" - - "Xss" + include: ${{ fromJSON(needs.generate-matrix.outputs.tests) }} steps: - name: Checkout code uses: actions/checkout@v6 From 9d14719fc2d0570e8ca6c11ba803236baf9f05e2 Mon Sep 17 00:00:00 2001 From: William Desportes Date: Tue, 24 Feb 2026 10:50:12 +0100 Subject: [PATCH 52/52] Fix uses of static $createDatabase Signed-off-by: William Desportes --- test/selenium/TestBase.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/selenium/TestBase.php b/test/selenium/TestBase.php index fd3f74db7e..40005865c3 100644 --- a/test/selenium/TestBase.php +++ b/test/selenium/TestBase.php @@ -176,7 +176,7 @@ abstract class TestBase extends TestCase $this->dbQuery( 'CREATE DATABASE IF NOT EXISTS `' . $this->databaseName . '`; USE `' . $this->databaseName . '`;' ); - static::$createDatabase = true; + $this->createDatabase = true; } public function getDbPrefix(): string @@ -1108,7 +1108,7 @@ JS; */ protected function tearDown(): void { - if (static::$createDatabase) { + if ($this->createDatabase) { $this->dbQuery('DROP DATABASE IF EXISTS `' . $this->databaseName . '`;'); }