Skip to content

Commit 6149673

Browse files
Merge pull request #18351 from kamil-tekiela/CheckUserPrivileges
Create a value object for ShowGrants
2 parents 0910b68 + 862e69d commit 6149673

7 files changed

Lines changed: 153 additions & 246 deletions

File tree

libraries/classes/CheckUserPrivileges.php

Lines changed: 25 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -25,91 +25,42 @@ public function __construct(private DatabaseInterface $dbi)
2525
{
2626
}
2727

28-
/**
29-
* Extracts details from a result row of a SHOW GRANT query
30-
*
31-
* @param string $row grant row
32-
*
33-
* @return array<int,string>
34-
*/
35-
public function getItemsFromShowGrantsRow(string $row): array
36-
{
37-
$dbNameOffset = mb_strpos($row, ' ON ') + 4;
38-
39-
$tableNameEndOffset = mb_strpos($row, ' TO ');
40-
$tableNameStartOffset = false;
41-
$tableNameStartOffset2 = mb_strpos($row, '`.', $dbNameOffset);
42-
43-
if ($tableNameStartOffset2 && $tableNameStartOffset2 < $tableNameEndOffset) {
44-
$tableNameStartOffset = $tableNameStartOffset2 + 1;
45-
}
46-
47-
if ($tableNameStartOffset === false) {
48-
$tableNameStartOffset = mb_strpos($row, '.', $dbNameOffset);
49-
}
50-
51-
$showGrantsDbName = mb_substr($row, $dbNameOffset, $tableNameStartOffset - $dbNameOffset);
52-
53-
$showGrantsDbName = Util::unQuote($showGrantsDbName, '`');
54-
55-
$showGrantsString = mb_substr(
56-
$row,
57-
6,
58-
mb_strpos($row, ' ON ') - 6,
59-
);
60-
61-
$showGrantsTableName = mb_substr(
62-
$row,
63-
$tableNameStartOffset + 1,
64-
$tableNameEndOffset - $tableNameStartOffset - 1,
65-
);
66-
$showGrantsTableName = Util::unQuote($showGrantsTableName, '`');
67-
68-
return [$showGrantsString, $showGrantsDbName, $showGrantsTableName];
69-
}
70-
7128
/**
7229
* Check if user has required privileges for
7330
* performing 'Adjust privileges' operations
74-
*
75-
* @param string $showGrantsString string containing grants for user
76-
* @param string $showGrantsDbName name of db extracted from grant string
77-
* @param string $showGrantsTableName name of table extracted from grant string
7831
*/
7932
public function checkRequiredPrivilegesForAdjust(
80-
string $showGrantsString,
81-
string $showGrantsDbName,
82-
string $showGrantsTableName,
33+
ShowGrants $showGrants,
8334
): void {
8435
// '... ALL PRIVILEGES ON *.* ...' OR '... ALL PRIVILEGES ON `mysql`.* ..'
8536
// OR
8637
// SELECT, INSERT, UPDATE, DELETE .... ON *.* OR `mysql`.*
8738
if (
88-
$showGrantsString !== 'ALL'
89-
&& $showGrantsString !== 'ALL PRIVILEGES'
90-
&& (mb_strpos($showGrantsString, 'SELECT, INSERT, UPDATE, DELETE') === false)
39+
$showGrants->grants !== 'ALL'
40+
&& $showGrants->grants !== 'ALL PRIVILEGES'
41+
&& (mb_strpos($showGrants->grants, 'SELECT, INSERT, UPDATE, DELETE') === false)
9142
) {
9243
return;
9344
}
9445

95-
if ($showGrantsDbName === '*' && $showGrantsTableName === '*') {
46+
if ($showGrants->dbName === '*' && $showGrants->tableName === '*') {
9647
$GLOBALS['col_priv'] = true;
9748
$GLOBALS['db_priv'] = true;
9849
$GLOBALS['proc_priv'] = true;
9950
$GLOBALS['table_priv'] = true;
10051

101-
if ($showGrantsString === 'ALL PRIVILEGES' || $showGrantsString === 'ALL') {
52+
if ($showGrants->grants === 'ALL PRIVILEGES' || $showGrants->grants === 'ALL') {
10253
$GLOBALS['is_reload_priv'] = true;
10354
}
10455
}
10556

10657
// check for specific tables in `mysql` db
10758
// Ex. '... ALL PRIVILEGES on `mysql`.`columns_priv` .. '
108-
if ($showGrantsDbName !== 'mysql') {
59+
if ($showGrants->dbName !== 'mysql') {
10960
return;
11061
}
11162

112-
switch ($showGrantsTableName) {
63+
switch ($showGrants->tableName) {
11364
case 'columns_priv':
11465
$GLOBALS['col_priv'] = true;
11566
break;
@@ -154,7 +105,6 @@ private function analyseShowGrant(): void
154105
$GLOBALS['is_create_db_priv'] = SessionCache::get('is_create_db_priv');
155106
$GLOBALS['is_reload_priv'] = SessionCache::get('is_reload_priv');
156107
$GLOBALS['db_to_create'] = SessionCache::get('db_to_create');
157-
$GLOBALS['dbs_where_create_table_allowed'] = SessionCache::get('dbs_where_create_table_allowed');
158108
$GLOBALS['dbs_to_test'] = SessionCache::get('dbs_to_test');
159109

160110
$GLOBALS['db_priv'] = SessionCache::get('db_priv');
@@ -169,7 +119,6 @@ private function analyseShowGrant(): void
169119
$GLOBALS['is_create_db_priv'] = false;
170120
$GLOBALS['is_reload_priv'] = false;
171121
$GLOBALS['db_to_create'] = '';
172-
$GLOBALS['dbs_where_create_table_allowed'] = [];
173122
$GLOBALS['dbs_to_test'] = Utilities::getSystemSchemas();
174123
$GLOBALS['proc_priv'] = false;
175124
$GLOBALS['db_priv'] = false;
@@ -185,52 +134,48 @@ private function analyseShowGrant(): void
185134
$re0 = '(^|(\\\\\\\\)+|[^\\\\])'; // non-escaped wildcards
186135
$re1 = '(^|[^\\\\])(\\\)+'; // escaped wildcards
187136

188-
while ($row = $showGrantsResult->fetchRow()) {
189-
[$showGrantsString, $showGrantsDbName, $showGrantsTableName] = $this->getItemsFromShowGrantsRow($row[0]);
137+
while ($showGrants = $showGrantsResult->fetchValue()) {
138+
$showGrants = new ShowGrants($showGrants);
190139

191-
if ($showGrantsDbName === '*') {
192-
if ($showGrantsString !== 'USAGE') {
140+
if ($showGrants->dbName === '*') {
141+
if ($showGrants->grants !== 'USAGE') {
193142
$GLOBALS['dbs_to_test'] = false;
194143
}
195144
} elseif ($GLOBALS['dbs_to_test'] !== false) {
196-
$GLOBALS['dbs_to_test'][] = $showGrantsDbName;
145+
$GLOBALS['dbs_to_test'][] = $showGrants->dbName;
197146
}
198147

199-
if (str_contains($showGrantsString, 'RELOAD')) {
148+
if (str_contains($showGrants->grants, 'RELOAD')) {
200149
$GLOBALS['is_reload_priv'] = true;
201150
}
202151

203152
// check for the required privileges for adjust
204-
$this->checkRequiredPrivilegesForAdjust($showGrantsString, $showGrantsDbName, $showGrantsTableName);
153+
$this->checkRequiredPrivilegesForAdjust($showGrants);
205154

206155
/**
207156
* @todo if we find CREATE VIEW but not CREATE, do not offer
208157
* the create database dialog box
209158
*/
210159
if (
211-
$showGrantsString !== 'ALL'
212-
&& $showGrantsString !== 'ALL PRIVILEGES'
213-
&& $showGrantsString !== 'CREATE'
214-
&& ! str_contains($showGrantsString, 'CREATE,')
160+
$showGrants->grants !== 'ALL'
161+
&& $showGrants->grants !== 'ALL PRIVILEGES'
162+
&& $showGrants->grants !== 'CREATE'
163+
&& ! str_contains($showGrants->grants, 'CREATE,')
215164
) {
216165
continue;
217166
}
218167

219-
if ($showGrantsDbName === '*') {
168+
if ($showGrants->dbName === '*') {
220169
// a global CREATE privilege
221170
$GLOBALS['is_create_db_priv'] = true;
222171
$GLOBALS['is_reload_priv'] = true;
223172
$GLOBALS['db_to_create'] = '';
224-
$GLOBALS['dbs_where_create_table_allowed'][] = '*';
225173
// @todo we should not break here, cause GRANT ALL *.*
226174
// could be revoked by a later rule like GRANT SELECT ON db.*
227175
break;
228176
}
229177

230-
// this array may contain wildcards
231-
$GLOBALS['dbs_where_create_table_allowed'][] = $showGrantsDbName;
232-
233-
$dbNameToTest = Util::backquote($showGrantsDbName);
178+
$dbNameToTest = Util::backquote($showGrants->dbName);
234179

235180
if ($GLOBALS['is_create_db_priv']) {
236181
// no need for any more tests if we already know this
@@ -239,8 +184,8 @@ private function analyseShowGrant(): void
239184

240185
// does this db exist?
241186
if (
242-
(! preg_match('/' . $re0 . '%|_/', $showGrantsDbName)
243-
|| preg_match('/\\\\%|\\\\_/', $showGrantsDbName))
187+
(! preg_match('/' . $re0 . '%|_/', $showGrants->dbName)
188+
|| preg_match('/\\\\%|\\\\_/', $showGrants->dbName))
244189
&& ($this->dbi->tryQuery(
245190
'USE ' . preg_replace(
246191
'/' . $re1 . '(%|_)/',
@@ -257,7 +202,7 @@ private function analyseShowGrant(): void
257202
* Do not handle the underscore wildcard
258203
* (this case must be rare anyway)
259204
*/
260-
$GLOBALS['db_to_create'] = preg_replace('/' . $re0 . '%/', '\\1', $showGrantsDbName);
205+
$GLOBALS['db_to_create'] = preg_replace('/' . $re0 . '%/', '\\1', $showGrants->dbName);
261206
$GLOBALS['db_to_create'] = preg_replace('/' . $re1 . '(%|_)/', '\\1\\3', $GLOBALS['db_to_create']);
262207
$GLOBALS['is_create_db_priv'] = true;
263208

@@ -274,7 +219,6 @@ private function analyseShowGrant(): void
274219
SessionCache::set('is_create_db_priv', $GLOBALS['is_create_db_priv']);
275220
SessionCache::set('is_reload_priv', $GLOBALS['is_reload_priv']);
276221
SessionCache::set('db_to_create', $GLOBALS['db_to_create']);
277-
SessionCache::set('dbs_where_create_table_allowed', $GLOBALS['dbs_where_create_table_allowed']);
278222
SessionCache::set('dbs_to_test', $GLOBALS['dbs_to_test']);
279223

280224
SessionCache::set('proc_priv', $GLOBALS['proc_priv']);
@@ -291,7 +235,7 @@ public function getPrivileges(): void
291235
$username = '';
292236

293237
$current = $this->dbi->getCurrentUserAndHost();
294-
if (! empty($current)) {
238+
if ($current !== []) {
295239
[$username] = $current;
296240
}
297241

@@ -300,7 +244,6 @@ public function getPrivileges(): void
300244
$GLOBALS['is_create_db_priv'] = true;
301245
$GLOBALS['is_reload_priv'] = true;
302246
$GLOBALS['db_to_create'] = '';
303-
$GLOBALS['dbs_where_create_table_allowed'] = ['*'];
304247
$GLOBALS['dbs_to_test'] = false;
305248
$GLOBALS['db_priv'] = true;
306249
$GLOBALS['col_priv'] = true;

libraries/classes/Plugins/Auth/AuthenticationCookie.php

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -381,7 +381,6 @@ public function readCredentials(): bool
381381
SessionCache::remove('is_create_db_priv');
382382
SessionCache::remove('is_reload_priv');
383383
SessionCache::remove('db_to_create');
384-
SessionCache::remove('dbs_where_create_table_allowed');
385384
SessionCache::remove('dbs_to_test');
386385
SessionCache::remove('db_priv');
387386
SessionCache::remove('col_priv');

libraries/classes/ShowGrants.php

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace PhpMyAdmin;
6+
7+
use function mb_strpos;
8+
use function mb_substr;
9+
10+
final class ShowGrants
11+
{
12+
public readonly string $grants;
13+
public readonly string $tableName;
14+
public readonly string $dbName;
15+
private int $tableNameEndOffset;
16+
private int $tableNameStartOffset;
17+
private int $dbNameOffset;
18+
19+
public function __construct(string $showGrants)
20+
{
21+
$this->dbNameOffset = (int) mb_strpos($showGrants, ' ON ') + 4;
22+
$this->tableNameEndOffset = (int) mb_strpos($showGrants, ' TO ');
23+
$this->tableNameStartOffset = $this->getTableNameStartOffset($showGrants);
24+
$this->grants = $this->getShowGrantsString($showGrants);
25+
$this->tableName = $this->getGrantsTableName($showGrants);
26+
$this->dbName = $this->getGrantsDbName($showGrants);
27+
}
28+
29+
private function getTableNameStartOffset(string $showGrants): int
30+
{
31+
$tableNameStartOffset = mb_strpos($showGrants, '`.', $this->dbNameOffset);
32+
33+
if (
34+
$tableNameStartOffset !== false
35+
&& $tableNameStartOffset !== 0
36+
&& $tableNameStartOffset < $this->tableNameEndOffset
37+
) {
38+
return $tableNameStartOffset + 1;
39+
}
40+
41+
return (int) mb_strpos($showGrants, '.', $this->dbNameOffset);
42+
}
43+
44+
private function getShowGrantsString(string $showGrants): string
45+
{
46+
return mb_substr($showGrants, 6, (int) mb_strpos($showGrants, ' ON ') - 6);
47+
}
48+
49+
private function getGrantsTableName(string $showGrants): string
50+
{
51+
$showGrantsTableName = mb_substr(
52+
$showGrants,
53+
$this->tableNameStartOffset + 1,
54+
$this->tableNameEndOffset - $this->tableNameStartOffset - 1,
55+
);
56+
57+
return Util::unQuote($showGrantsTableName, '`');
58+
}
59+
60+
private function getGrantsDbName(string $showGrants): string
61+
{
62+
$showGrantsDbName = mb_substr(
63+
$showGrants,
64+
$this->dbNameOffset,
65+
$this->tableNameStartOffset - $this->dbNameOffset,
66+
);
67+
68+
return Util::unQuote($showGrantsDbName, '`');
69+
}
70+
}

phpstan-baseline.neon

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -90,26 +90,6 @@ parameters:
9090
count: 1
9191
path: libraries/classes/Charsets.php
9292

93-
-
94-
message: "#^Only numeric types are allowed in \\+, int\\<0, max\\>\\|false given on the left side\\.$#"
95-
count: 2
96-
path: libraries/classes/CheckUserPrivileges.php
97-
98-
-
99-
message: "#^Only numeric types are allowed in \\-, int\\<0, max\\>\\|false given on the left side\\.$#"
100-
count: 3
101-
path: libraries/classes/CheckUserPrivileges.php
102-
103-
-
104-
message: "#^Only numeric types are allowed in \\-, int\\<0, max\\>\\|false given on the right side\\.$#"
105-
count: 1
106-
path: libraries/classes/CheckUserPrivileges.php
107-
108-
-
109-
message: "#^Parameter \\#1 \\$row of method PhpMyAdmin\\\\CheckUserPrivileges\\:\\:getItemsFromShowGrantsRow\\(\\) expects string, string\\|null given\\.$#"
110-
count: 1
111-
path: libraries/classes/CheckUserPrivileges.php
112-
11393
-
11494
message: "#^Parameter \\#3 \\$subject of function preg_replace expects array\\|string, string\\|null given\\.$#"
11595
count: 1

psalm-baseline.xml

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -132,23 +132,11 @@
132132
<code><![CDATA[$GLOBALS['db_priv']]]></code>
133133
<code><![CDATA[$GLOBALS['db_to_create']]]></code>
134134
<code><![CDATA[$GLOBALS['dbs_to_test']]]></code>
135-
<code><![CDATA[$GLOBALS['dbs_where_create_table_allowed']]]></code>
136135
<code><![CDATA[$GLOBALS['is_create_db_priv']]]></code>
137136
<code><![CDATA[$GLOBALS['is_reload_priv']]]></code>
138137
<code><![CDATA[$GLOBALS['proc_priv']]]></code>
139138
<code><![CDATA[$GLOBALS['table_priv']]]></code>
140139
</MixedAssignment>
141-
<PossiblyFalseOperand>
142-
<code>$tableNameEndOffset</code>
143-
<code>$tableNameStartOffset</code>
144-
<code>$tableNameStartOffset</code>
145-
<code>$tableNameStartOffset</code>
146-
<code><![CDATA[mb_strpos($row, ' ON ')]]></code>
147-
<code><![CDATA[mb_strpos($row, ' ON ')]]></code>
148-
</PossiblyFalseOperand>
149-
<PossiblyNullArgument>
150-
<code>$row[0]</code>
151-
</PossiblyNullArgument>
152140
</file>
153141
<file src="libraries/classes/Command/CacheWarmupCommand.php">
154142
<UnusedClass>
@@ -14090,12 +14078,6 @@
1409014078
<code>assertTrue</code>
1409114079
<code>assertTrue</code>
1409214080
</RedundantConditionGivenDocblockType>
14093-
<UnusedVariable>
14094-
<code>$showGrantsStr</code>
14095-
<code>$showGrantsStr</code>
14096-
<code>$showGrantsTblname</code>
14097-
<code>$showGrantsTblname</code>
14098-
</UnusedVariable>
1409914081
</file>
1410014082
<file src="test/classes/Command/SetVersionCommandTest.php">
1410114083
<PossiblyInvalidArgument>

0 commit comments

Comments
 (0)