diff --git a/libraries/classes/Util.php b/libraries/classes/Util.php
index 53ca6496c6..3c66198d1e 100644
--- a/libraries/classes/Util.php
+++ b/libraries/classes/Util.php
@@ -71,6 +71,7 @@ use function set_time_limit;
use function sort;
use function sprintf;
use function str_contains;
+use function str_getcsv;
use function str_pad;
use function str_replace;
use function strcasecmp;
@@ -1906,11 +1907,16 @@ class Util
// If you are fixing something here,
// you need to also update the JS port.
- preg_match('|\((.*)\)|', $definition, $matches);
+ // This should really be delegated to MySQL but since we also want to HTML encode it,
+ // it is easier this way.
+ // It future replace str_getcsv with $dbi->fetchSingleRow('SELECT '.$expressionInBrackets[1]);
+
+ preg_match('/\((.*)\)/', $definition, $expressionInBrackets);
+ $matches = str_getcsv($expressionInBrackets[1], ',', "'");
$values = [];
- foreach (explode(',', $matches[1]) as $value) {
- $value = strtr(substr($value, 1, -1), ["''" => "'", "\\'" => "'", '\\\\' => '\\']);
+ foreach ($matches as $value) {
+ $value = strtr($value, ['\\\\' => '\\']); // str_getcsv doesn't unescape backslashes so we do it ourselves
$values[] = $escapeHtml ? htmlspecialchars($value, ENT_QUOTES, 'UTF-8') : $value;
}
diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon
index 0a87f82ad3..b9e5ad0278 100644
--- a/phpstan-baseline.neon
+++ b/phpstan-baseline.neon
@@ -1635,6 +1635,16 @@ parameters:
count: 1
path: libraries/classes/Controllers/Table/Structure/SaveController.php
+ -
+ message: "#^Comparison operation \"\\>\" between int\\<1, max\\> and 0 is always true\\.$#"
+ count: 1
+ path: libraries/classes/Controllers/Table/Structure/SaveController.php
+
+ -
+ message: "#^Else branch is unreachable because ternary operator condition is always true\\.$#"
+ count: 1
+ path: libraries/classes/Controllers/Table/Structure/SaveController.php
+
-
message: "#^Method PhpMyAdmin\\\\Controllers\\\\Table\\\\Structure\\\\SaveController\\:\\:adjustColumnPrivileges\\(\\) has parameter \\$adjust_privileges with no value type specified in iterable type array\\.$#"
count: 1
@@ -4520,11 +4530,6 @@ parameters:
count: 2
path: libraries/classes/Import.php
- -
- message: "#^Parameter \\#1 \\$importRunBuffer of method PhpMyAdmin\\\\Import\\:\\:runQueryPost\\(\\) expects array\\|null, array\\|float\\|int\\|string\\|false\\|null given\\.$#"
- count: 1
- path: libraries/classes/Import.php
-
-
message: "#^Parameter \\#1 \\$lastCumulativeSize of method PhpMyAdmin\\\\Import\\:\\:getDecimalPrecision\\(\\) expects string, int\\|string given\\.$#"
count: 3
@@ -5615,9 +5620,14 @@ parameters:
count: 1
path: libraries/classes/ParseAnalyze.php
+ -
+ message: "#^Offset 'select_tables' does not exist on array\\{distinct\\?\\: bool, drop_database\\?\\: bool, group\\?\\: bool, having\\?\\: bool, is_affected\\?\\: bool, is_analyse\\?\\: bool, is_count\\?\\: bool, is_delete\\?\\: bool, \\.\\.\\.\\}\\.$#"
+ count: 3
+ path: libraries/classes/ParseAnalyze.php
+
-
message: "#^Offset 'select_tables' on array\\{distinct\\?\\: bool, drop_database\\?\\: bool, group\\?\\: bool, having\\?\\: bool, is_affected\\?\\: bool, is_analyse\\?\\: bool, is_count\\?\\: bool, is_delete\\?\\: bool, \\.\\.\\.\\} in empty\\(\\) does not exist\\.$#"
- count: 1
+ count: 2
path: libraries/classes/ParseAnalyze.php
-
@@ -9030,6 +9040,11 @@ parameters:
count: 1
path: libraries/classes/Util.php
+ -
+ message: "#^Parameter \\#1 \\$str of function strtr expects string, string\\|null given\\.$#"
+ count: 1
+ path: libraries/classes/Util.php
+
-
message: "#^Cannot cast mixed to int\\.$#"
count: 1
diff --git a/psalm-baseline.xml b/psalm-baseline.xml
index 620a3009b7..666815a6ac 100644
--- a/psalm-baseline.xml
+++ b/psalm-baseline.xml
@@ -14248,19 +14248,12 @@
$value
$values['token']
-
- string
-
get
get
getCookie
getCookie
-
- $html_separator
- $separator
-
(string) $db
(string) $table
@@ -14484,9 +14477,10 @@
$sep
$tableGroup
-
+
$maxSize
$maxUnit
+ $value
$maxSize
diff --git a/test/classes/Controllers/Sql/EnumValuesControllerTest.php b/test/classes/Controllers/Sql/EnumValuesControllerTest.php
index 0363ef30ef..57a373e838 100644
--- a/test/classes/Controllers/Sql/EnumValuesControllerTest.php
+++ b/test/classes/Controllers/Sql/EnumValuesControllerTest.php
@@ -63,7 +63,7 @@ class EnumValuesControllerTest extends AbstractTestCase
[
[
'set',
- "set('','a&b','b&c','vrai&','','漢字','''','\\','\\\"\\\\''')",
+ "set('','a&b','b&c','vrai&','','漢字','''','\\\\','\"\\\\''')",
'No',
'',
'NULL',
@@ -110,7 +110,7 @@ class EnumValuesControllerTest extends AbstractTestCase
. ' ' . "\n"
. ' ' . "\n"
. ' ' . "\n"
- . ' ' . "\n"
+ . ' ' . "\n"
. ' ' . "\n",
],
$this->getResponseJsonResult()
diff --git a/test/classes/UtilTest.php b/test/classes/UtilTest.php
index 0c5cdb27cc..772bf70e2a 100644
--- a/test/classes/UtilTest.php
+++ b/test/classes/UtilTest.php
@@ -782,7 +782,7 @@ class UtilTest extends AbstractTestCase
'zerofill' => false,
'spec_in_brackets' => "'\'a','b'",
'enum_set_values' => [
- "'a",
+ "\'a",
'b',
],
'attribute' => ' ',
@@ -819,7 +819,7 @@ class UtilTest extends AbstractTestCase
'spec_in_brackets' => "'a&b','b''c\\'d','e\\\\f'",
'enum_set_values' => [
'a&b',
- 'b\'c\'d',
+ 'b\'c\\\'d',
'e\\f',
],
'attribute' => ' ',
@@ -890,6 +890,126 @@ class UtilTest extends AbstractTestCase
];
}
+ /**
+ * Test case for parsing ENUM values
+ *
+ * @param string[] $out
+ *
+ * @dataProvider providerParseEnumSetValues
+ */
+ public function testParseEnumSetValues(string $in, bool $escapeHTML, array $out): void
+ {
+ $this->assertEquals(
+ $out,
+ Util::parseEnumSetValues($in, $escapeHTML)
+ );
+ }
+
+ /**
+ * Data provider for testParseEnumSetValues
+ *
+ * @return iterable
+ */
+ public function providerParseEnumSetValues(): iterable
+ {
+ $enumSpec = "enum('a&b','b''c''d','e\\f')";
+
+ yield [
+ $enumSpec,
+ false,
+ [
+ 'a&b',
+ 'b\'c\'d',
+ 'e\\f',
+ ],
+ ];
+
+ yield [
+ $enumSpec,
+ true,
+ [
+ 'a&b',
+ 'b'c'd',
+ 'e\\f',
+ ],
+ ];
+
+ $enumSpec = "set('','a&b','b&c','vrai&','','漢字','''','\\\\','\"\\\\''')";
+
+ yield [
+ $enumSpec,
+ false,
+ [
+ '',
+ 'a&b',
+ 'b&c',
+ 'vrai&',
+ '',
+ '漢字',
+ "'",
+ '\\',
+ '"\\\'',
+ ],
+ ];
+
+ yield [
+ $enumSpec,
+ true,
+ [
+ '<script>alert("ok")</script>',
+ 'a&b',
+ 'b&c',
+ 'vrai&',
+ '',
+ '漢字',
+ ''',
+ '\\',
+ '"\'',
+ ],
+ ];
+
+ $enumSpec = "enum('1','2,','3''','''4')";
+
+ yield [
+ $enumSpec,
+ false,
+ [
+ '1',
+ '2,',
+ '3\'',
+ '\'4',
+ ],
+ ];
+
+ yield [
+ $enumSpec,
+ true,
+ [
+ '1',
+ '2,',
+ '3'',
+ ''4',
+ ],
+ ];
+
+ $enumSpec = "enum('''','''''','\"','\\\\','\\\\''','\\\\\"',',','()')";
+
+ yield [
+ $enumSpec,
+ false,
+ [
+ "'",
+ "''",
+ '"',
+ '\\',
+ "\\'",
+ '\\"',
+ ',',
+ '()',
+ ],
+ ];
+ }
+
/**
* Test for Util::extractValueFromFormattedSize
*