Passed
Push — develop ( ce7da4...69770d )
by Felipe
05:27
created

RoleTrait::setPrivileges()   F

Complexity

Conditions 36
Paths 13839

Size

Total Lines 129
Code Lines 77

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 129
rs 2
c 0
b 0
f 0
cc 36
eloc 77
nc 13839
nop 10

How to fix   Long Method    Complexity    Many Parameters   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
<?php
2
3
/**
4
 * PHPPgAdmin v6.0.0-beta.40
5
 */
6
7
namespace PHPPgAdmin\Database;
8
9
/**
10
 * Common trait for roles and users manipulation.
11
 */
12
trait RoleTrait
13
{
14
15
    /**
16
     * Returns all roles in the database cluster.
17
     *
18
     * @param $rolename (optional) The role name to exclude from the select
0 ignored issues
show
Bug introduced by
The type PHPPgAdmin\Database\optional was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
19
     *
20
     * @return All roles
0 ignored issues
show
Bug introduced by
The type PHPPgAdmin\Database\All was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
21
     */
22
    public function getRoles($rolename = '')
23
    {
24
        $sql = '
25
			SELECT rolname, rolsuper, rolcreatedb, rolcreaterole, rolinherit,
26
				rolcanlogin, rolconnlimit, rolvaliduntil, rolconfig
27
			FROM pg_catalog.pg_roles';
28
        if ($rolename) {
29
            $sql .= " WHERE rolname!='{$rolename}'";
30
        }
31
32
        $sql .= ' ORDER BY rolname';
33
34
        return $this->selectSet($sql);
0 ignored issues
show
Bug introduced by
It seems like selectSet() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

34
        return $this->/** @scrutinizer ignore-call */ selectSet($sql);
Loading history...
35
    }
36
37
    /**
38
     * Returns information about a single role.
39
     *
40
     * @param $rolename The name of the role to retrieve
0 ignored issues
show
Bug introduced by
The type PHPPgAdmin\Database\The was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
41
     *
42
     * @return The role's data
43
     */
44
    public function getRole($rolename)
45
    {
46
        $this->clean($rolename);
0 ignored issues
show
Bug introduced by
It seems like clean() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

46
        $this->/** @scrutinizer ignore-call */ 
47
               clean($rolename);
Loading history...
47
48
        $sql = "
49
			SELECT rolname, rolsuper, rolcreatedb, rolcreaterole, rolinherit,
50
				rolcanlogin, rolconnlimit, rolvaliduntil, rolconfig
51
			FROM pg_catalog.pg_roles WHERE rolname='{$rolename}'";
52
53
        return $this->selectSet($sql);
54
    }
55
56
    /**
57
     * Returns all users in the database cluster.
58
     *
59
     * @return All users
60
     */
61
    public function getUsers()
62
    {
63
        $sql = 'SELECT usename, usesuper, usecreatedb, valuntil AS useexpires, useconfig
64
			FROM pg_user
65
			ORDER BY usename';
66
67
        return $this->selectSet($sql);
68
    }
69
70
    /**
71
     * Returns information about a single user.
72
     *
73
     * @param $username The username of the user to retrieve
74
     *
75
     * @return The user's data
76
     */
77
    public function getUser($username)
78
    {
79
        $this->clean($username);
80
81
        $sql = "SELECT usename, usesuper, usecreatedb, valuntil AS useexpires, useconfig
82
			FROM pg_user
83
			WHERE usename='{$username}'";
84
85
        return $this->selectSet($sql);
86
    }
87
88
    /**
89
     * Creates a new role.
90
     *
91
     * @param $rolename     The name of the role to create
92
     * @param $password     A password for the role
93
     * @param $superuser    Boolean whether or not the role is a superuser
94
     * @param $createdb     Boolean whether or not the role can create databases
95
     * @param $createrole   Boolean whether or not the role can create other roles
96
     * @param $inherits     Boolean whether or not the role inherits the privileges from parent roles
97
     * @param $login        Boolean whether or not the role will be allowed to login
98
     * @param $connlimit    Number of concurrent connections the role can make
99
     * @param $expiry       String Format 'YYYY-MM-DD HH:MM:SS'.  '' means never expire
100
     * @param $memberof     (array) Roles to which the new role will be immediately added as a new member
101
     * @param $members      (array) Roles which are automatically added as members of the new role
102
     * @param $adminmembers (array) Roles which are automatically added as admin members of the new role
103
     *
104
     * @return int 0 if operation was successful
105
     */
106
    public function createRole(
107
        $rolename,
108
        $password,
109
        $superuser,
110
        $createdb,
111
        $createrole,
112
        $inherits,
113
        $login,
114
        $connlimit,
115
        $expiry,
116
        $memberof,
117
        $members,
118
        $adminmembers
119
    ) {
120
        $enc = $this->_encryptPassword($rolename, $password);
121
        $this->fieldClean($rolename);
0 ignored issues
show
Bug introduced by
It seems like fieldClean() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

121
        $this->/** @scrutinizer ignore-call */ 
122
               fieldClean($rolename);
Loading history...
122
        $this->clean($enc);
123
        $this->clean($connlimit);
124
        $this->clean($expiry);
125
        $this->fieldArrayClean($memberof);
0 ignored issues
show
Bug introduced by
It seems like fieldArrayClean() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

125
        $this->/** @scrutinizer ignore-call */ 
126
               fieldArrayClean($memberof);
Loading history...
126
        $this->fieldArrayClean($members);
127
        $this->fieldArrayClean($adminmembers);
128
129
        $sql = "CREATE ROLE \"{$rolename}\"";
130
        if ($password != '') {
131
            $sql .= " WITH ENCRYPTED PASSWORD '{$enc}'";
132
        }
133
134
        $sql .= $superuser ? ' SUPERUSER' : ' NOSUPERUSER';
135
        $sql .= $createdb ? ' CREATEDB' : ' NOCREATEDB';
136
        $sql .= $createrole ? ' CREATEROLE' : ' NOCREATEROLE';
137
        $sql .= $inherits ? ' INHERIT' : ' NOINHERIT';
138
        $sql .= $login ? ' LOGIN' : ' NOLOGIN';
139
        if ($connlimit != '') {
140
            $sql .= " CONNECTION LIMIT {$connlimit}";
141
        } else {
142
            $sql .= ' CONNECTION LIMIT -1';
143
        }
144
145
        if ($expiry != '') {
146
            $sql .= " VALID UNTIL '{$expiry}'";
147
        } else {
148
            $sql .= " VALID UNTIL 'infinity'";
149
        }
150
151
        if (is_array($memberof) && sizeof($memberof) > 0) {
152
            $sql .= ' IN ROLE "' . join('", "', $memberof) . '"';
153
        }
154
155
        if (is_array($members) && sizeof($members) > 0) {
156
            $sql .= ' ROLE "' . join('", "', $members) . '"';
157
        }
158
159
        if (is_array($adminmembers) && sizeof($adminmembers) > 0) {
160
            $sql .= ' ADMIN "' . join('", "', $adminmembers) . '"';
161
        }
162
163
        return $this->execute($sql);
0 ignored issues
show
Bug introduced by
It seems like execute() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

163
        return $this->/** @scrutinizer ignore-call */ execute($sql);
Loading history...
164
    }
165
166
    /**
167
     * Helper function that computes encypted PostgreSQL passwords.
168
     *
169
     * @param $username The username
170
     * @param $password The password
171
     *
172
     * @return string
173
     */
174
    public function _encryptPassword($username, $password)
1 ignored issue
show
Coding Style introduced by
Public method name "RoleTrait::_encryptPassword" must not be prefixed with an underscore
Loading history...
175
    {
176
        return 'md5' . md5($password . $username);
177
    }
178
179
    /**
180
     * Adjusts a role's info and renames it.
181
     *
182
     * @param $rolename        The name of the role to adjust
183
     * @param $password        A password for the role
184
     * @param $superuser       Boolean whether or not the role is a superuser
185
     * @param $createdb        Boolean whether or not the role can create databases
186
     * @param $createrole      Boolean whether or not the role can create other roles
187
     * @param $inherits        Boolean whether or not the role inherits the privileges from parent roles
188
     * @param $login           Boolean whether or not the role will be allowed to login
189
     * @param $connlimit       Number of concurrent connections the role can make
190
     * @param $expiry          string Format 'YYYY-MM-DD HH:MM:SS'.  '' means never expire
191
     * @param $memberof        (array) Roles to which the role will be immediately added as a new member
192
     * @param $members         (array) Roles which are automatically added as members of the role
193
     * @param $adminmembers    (array) Roles which are automatically added as admin members of the role
194
     * @param $memberofold     (array) Original roles whose the role belongs to
195
     * @param $membersold      (array) Original roles that are members of the role
196
     * @param $adminmembersold (array) Original roles that are admin members of the role
197
     * @param $newrolename     The new name of the role
198
     *
199
     * @return bool|int 0 success
200
     */
201
    public function setRenameRole(
202
        $rolename,
203
        $password,
204
        $superuser,
205
        $createdb,
206
        $createrole,
207
        $inherits,
208
        $login,
209
        $connlimit,
210
        $expiry,
211
        $memberof,
212
        $members,
213
        $adminmembers,
214
        $memberofold,
215
        $membersold,
216
        $adminmembersold,
217
        $newrolename
218
    ) {
219
        $status = $this->beginTransaction();
0 ignored issues
show
Bug introduced by
It seems like beginTransaction() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

219
        /** @scrutinizer ignore-call */ 
220
        $status = $this->beginTransaction();
Loading history...
220
        if ($status != 0) {
221
            return -1;
222
        }
223
224
        if ($rolename != $newrolename) {
225
            $status = $this->renameRole($rolename, $newrolename);
226
            if ($status != 0) {
227
                $this->rollbackTransaction();
0 ignored issues
show
Bug introduced by
It seems like rollbackTransaction() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

227
                $this->/** @scrutinizer ignore-call */ 
228
                       rollbackTransaction();
Loading history...
228
229
                return -3;
230
            }
231
            $rolename = $newrolename;
232
        }
233
234
        $status =
0 ignored issues
show
Coding Style introduced by
Multi-line assignments must have the equal sign on the second line
Loading history...
235
        $this->setRole(
236
            $rolename,
237
            $password,
238
            $superuser,
239
            $createdb,
240
            $createrole,
241
            $inherits,
242
            $login,
243
            $connlimit,
244
            $expiry,
245
            $memberof,
246
            $members,
247
            $adminmembers,
248
            $memberofold,
249
            $membersold,
250
            $adminmembersold
251
        );
252
        if ($status != 0) {
253
            $this->rollbackTransaction();
254
255
            return -2;
256
        }
257
258
        return $this->endTransaction();
0 ignored issues
show
Bug introduced by
It seems like endTransaction() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

258
        return $this->/** @scrutinizer ignore-call */ endTransaction();
Loading history...
259
    }
260
261
    /**
262
     * Renames a role.
263
     *
264
     * @param $rolename    The name of the role to rename
265
     * @param $newrolename The new name of the role
266
     *
267
     * @return int 0 if operation was successful
268
     */
269
    public function renameRole($rolename, $newrolename)
270
    {
271
        $this->fieldClean($rolename);
272
        $this->fieldClean($newrolename);
273
274
        $sql = "ALTER ROLE \"{$rolename}\" RENAME TO \"{$newrolename}\"";
275
276
        return $this->execute($sql);
277
    }
278
279
    /**
280
     * Adjusts a role's info.
281
     *
282
     * @param $rolename        The name of the role to adjust
283
     * @param $password        A password for the role
284
     * @param $superuser       Boolean whether or not the role is a superuser
285
     * @param $createdb        Boolean whether or not the role can create databases
286
     * @param $createrole      Boolean whether or not the role can create other roles
287
     * @param $inherits        Boolean whether or not the role inherits the privileges from parent roles
288
     * @param $login           Boolean whether or not the role will be allowed to login
289
     * @param $connlimit       Number of concurrent connections the role can make
290
     * @param $expiry          string Format 'YYYY-MM-DD HH:MM:SS'.  '' means never expire
291
     * @param $memberof        (array) Roles to which the role will be immediately added as a new member
292
     * @param $members         (array) Roles which are automatically added as members of the role
293
     * @param $adminmembers    (array) Roles which are automatically added as admin members of the role
294
     * @param $memberofold     (array) Original roles whose the role belongs to
295
     * @param $membersold      (array) Original roles that are members of the role
296
     * @param $adminmembersold (array) Original roles that are admin members of the role
297
     *
298
     * @return int 0 if operation was successful
299
     */
300
    public function setRole(
301
        $rolename,
302
        $password,
303
        $superuser,
304
        $createdb,
305
        $createrole,
306
        $inherits,
307
        $login,
308
        $connlimit,
309
        $expiry,
310
        $memberof,
311
        $members,
312
        $adminmembers,
313
        $memberofold,
314
        $membersold,
315
        $adminmembersold
316
    ) {
317
        $enc = $this->_encryptPassword($rolename, $password);
318
        $this->fieldClean($rolename);
319
        $this->clean($enc);
320
        $this->clean($connlimit);
321
        $this->clean($expiry);
322
        $this->fieldArrayClean($memberof);
323
        $this->fieldArrayClean($members);
324
        $this->fieldArrayClean($adminmembers);
325
326
        $sql = "ALTER ROLE \"{$rolename}\"";
327
        if ($password != '') {
328
            $sql .= " WITH ENCRYPTED PASSWORD '{$enc}'";
329
        }
330
331
        $sql .= $superuser ? ' SUPERUSER' : ' NOSUPERUSER';
332
        $sql .= $createdb ? ' CREATEDB' : ' NOCREATEDB';
333
        $sql .= $createrole ? ' CREATEROLE' : ' NOCREATEROLE';
334
        $sql .= $inherits ? ' INHERIT' : ' NOINHERIT';
335
        $sql .= $login ? ' LOGIN' : ' NOLOGIN';
336
        if ($connlimit != '') {
337
            $sql .= " CONNECTION LIMIT {$connlimit}";
338
        } else {
339
            $sql .= ' CONNECTION LIMIT -1';
340
        }
341
342
        if ($expiry != '') {
343
            $sql .= " VALID UNTIL '{$expiry}'";
344
        } else {
345
            $sql .= " VALID UNTIL 'infinity'";
346
        }
347
348
        $status = $this->execute($sql);
349
350
        if ($status != 0) {
351
            return -1;
352
        }
353
354
        //memberof
355
        $old = explode(',', $memberofold);
356
        foreach ($memberof as $m) {
357
            if (!in_array($m, $old, true)) {
358
                $status = $this->grantRole($m, $rolename);
359
                if ($status != 0) {
360
                    return -1;
361
                }
362
            }
363
        }
364
        if ($memberofold) {
365
            foreach ($old as $o) {
366
                if (!in_array($o, $memberof, true)) {
367
                    $status = $this->revokeRole($o, $rolename, 0, 'CASCADE');
368
                    if ($status != 0) {
369
                        return -1;
370
                    }
371
                }
372
            }
373
        }
374
375
        //members
376
        $old = explode(',', $membersold);
377
        foreach ($members as $m) {
378
            if (!in_array($m, $old, true)) {
379
                $status = $this->grantRole($rolename, $m);
380
                if ($status != 0) {
381
                    return -1;
382
                }
383
            }
384
        }
385
        if ($membersold) {
386
            foreach ($old as $o) {
387
                if (!in_array($o, $members, true)) {
388
                    $status = $this->revokeRole($rolename, $o, 0, 'CASCADE');
389
                    if ($status != 0) {
390
                        return -1;
391
                    }
392
                }
393
            }
394
        }
395
396
        //adminmembers
397
        $old = explode(',', $adminmembersold);
398
        foreach ($adminmembers as $m) {
399
            if (!in_array($m, $old, true)) {
400
                $status = $this->grantRole($rolename, $m, 1);
401
                if ($status != 0) {
402
                    return -1;
403
                }
404
            }
405
        }
406
        if ($adminmembersold) {
407
            foreach ($old as $o) {
408
                if (!in_array($o, $adminmembers, true)) {
409
                    $status = $this->revokeRole($rolename, $o, 1, 'CASCADE');
410
                    if ($status != 0) {
411
                        return -1;
412
                    }
413
                }
414
            }
415
        }
416
417
        return $status;
418
    }
419
420
    /**
421
     * Grants membership in a role.
422
     *
423
     * @param     $role     The name of the target role
424
     * @param     $rolename The name of the role that will belong to the target role
425
     * @param int $admin    (optional) Flag to grant the admin option
426
     *
427
     * @return int 0 if operation was successful
428
     */
429
    public function grantRole($role, $rolename, $admin = 0)
430
    {
431
        $this->fieldClean($role);
432
        $this->fieldClean($rolename);
433
434
        $sql = "GRANT \"{$role}\" TO \"{$rolename}\"";
435
        if ($admin == 1) {
436
            $sql .= ' WITH ADMIN OPTION';
437
        }
438
439
        return $this->execute($sql);
440
    }
441
442
    /**
443
     * Revokes membership in a role.
444
     *
445
     * @param        $role     The name of the target role
446
     * @param        $rolename The name of the role that will not belong to the target role
447
     * @param int    $admin    (optional) Flag to revoke only the admin option
448
     * @param string $type     (optional) Type of revoke: RESTRICT | CASCADE
449
     *
450
     * @return int 0 if operation was successful
451
     */
452
    public function revokeRole($role, $rolename, $admin = 0, $type = 'RESTRICT')
453
    {
454
        $this->fieldClean($role);
455
        $this->fieldClean($rolename);
456
457
        $sql = 'REVOKE ';
458
        if ($admin == 1) {
459
            $sql .= 'ADMIN OPTION FOR ';
460
        }
461
462
        $sql .= "\"{$role}\" FROM \"{$rolename}\" {$type}";
463
464
        return $this->execute($sql);
465
    }
466
467
    /**
468
     * Removes a role.
469
     *
470
     * @param $rolename The name of the role to drop
471
     *
472
     * @return int 0 if operation was successful
473
     */
474
    public function dropRole($rolename)
475
    {
476
        $this->fieldClean($rolename);
477
478
        $sql = "DROP ROLE \"{$rolename}\"";
479
480
        return $this->execute($sql);
481
    }
482
483
    /**
484
     * Creates a new user.
485
     *
486
     * @param $username   The username of the user to create
487
     * @param $password   A password for the user
488
     * @param $createdb   boolean Whether or not the user can create databases
489
     * @param $createuser boolean Whether or not the user can create other users
490
     * @param $expiry     string Format 'YYYY-MM-DD HH:MM:SS'.  '' means never expire
491
     * @param $groups
492
     *
493
     * @return int 0 if operation was successful
494
     *
495
     * @internal param $group (array) The groups to create the user in
496
     */
497
    public function createUser($username, $password, $createdb, $createuser, $expiry, $groups)
498
    {
499
        $enc = $this->_encryptPassword($username, $password);
500
        $this->fieldClean($username);
501
        $this->clean($enc);
502
        $this->clean($expiry);
503
        $this->fieldArrayClean($groups);
504
505
        $sql = "CREATE USER \"{$username}\"";
506
        if ($password != '') {
507
            $sql .= " WITH ENCRYPTED PASSWORD '{$enc}'";
508
        }
509
510
        $sql .= $createdb ? ' CREATEDB' : ' NOCREATEDB';
511
        $sql .= $createuser ? ' CREATEUSER' : ' NOCREATEUSER';
512
        if (is_array($groups) && sizeof($groups) > 0) {
513
            $sql .= ' IN GROUP "' . join('", "', $groups) . '"';
514
        }
515
516
        if ($expiry != '') {
517
            $sql .= " VALID UNTIL '{$expiry}'";
518
        } else {
519
            $sql .= " VALID UNTIL 'infinity'";
520
        }
521
522
        return $this->execute($sql);
523
    }
524
525
    /**
526
     * Adjusts a user's info and renames the user.
527
     *
528
     * @param $username   The username of the user to modify
529
     * @param $password   A new password for the user
530
     * @param $createdb   boolean Whether or not the user can create databases
531
     * @param $createuser boolean Whether or not the user can create other users
532
     * @param $expiry     string Format 'YYYY-MM-DD HH:MM:SS'.  '' means never expire.
533
     * @param $newname    The new name of the user
534
     *
535
     * @return bool|int 0 success
536
     */
537
    public function setRenameUser($username, $password, $createdb, $createuser, $expiry, $newname)
538
    {
539
        $status = $this->beginTransaction();
540
        if ($status != 0) {
541
            return -1;
542
        }
543
544
        if ($username != $newname) {
545
            $status = $this->renameUser($username, $newname);
546
            if ($status != 0) {
547
                $this->rollbackTransaction();
548
549
                return -3;
550
            }
551
            $username = $newname;
552
        }
553
554
        $status = $this->setUser($username, $password, $createdb, $createuser, $expiry);
555
        if ($status != 0) {
556
            $this->rollbackTransaction();
557
558
            return -2;
559
        }
560
561
        return $this->endTransaction();
562
    }
563
564
    /**
565
     * Renames a user.
566
     *
567
     * @param $username The username of the user to rename
568
     * @param $newname  The new name of the user
569
     *
570
     * @return int 0 if operation was successful
571
     */
572
    public function renameUser($username, $newname)
573
    {
574
        $this->fieldClean($username);
575
        $this->fieldClean($newname);
576
577
        $sql = "ALTER USER \"{$username}\" RENAME TO \"{$newname}\"";
578
579
        return $this->execute($sql);
580
    }
581
582
    // Tablespace functions
583
584
    /**
585
     * Adjusts a user's info.
586
     *
587
     * @param $username   The username of the user to modify
588
     * @param $password   A new password for the user
589
     * @param $createdb   boolean Whether or not the user can create databases
590
     * @param $createuser boolean Whether or not the user can create other users
591
     * @param $expiry     string Format 'YYYY-MM-DD HH:MM:SS'.  '' means never expire.
592
     *
593
     * @return int 0 if operation was successful
594
     */
595
    public function setUser($username, $password, $createdb, $createuser, $expiry)
596
    {
597
        $enc = $this->_encryptPassword($username, $password);
598
        $this->fieldClean($username);
599
        $this->clean($enc);
600
        $this->clean($expiry);
601
602
        $sql = "ALTER USER \"{$username}\"";
603
        if ($password != '') {
604
            $sql .= " WITH ENCRYPTED PASSWORD '{$enc}'";
605
        }
606
607
        $sql .= $createdb ? ' CREATEDB' : ' NOCREATEDB';
608
        $sql .= $createuser ? ' CREATEUSER' : ' NOCREATEUSER';
609
        if ($expiry != '') {
610
            $sql .= " VALID UNTIL '{$expiry}'";
611
        } else {
612
            $sql .= " VALID UNTIL 'infinity'";
613
        }
614
615
        return $this->execute($sql);
616
    }
617
618
    /**
619
     * Removes a user.
620
     *
621
     * @param $username The username of the user to drop
622
     *
623
     * @return int 0 if operation was successful
624
     */
625
    public function dropUser($username)
626
    {
627
        $this->fieldClean($username);
628
629
        $sql = "DROP USER \"{$username}\"";
630
631
        return $this->execute($sql);
632
    }
633
634
    /**
635
     * Changes a role's password.
636
     *
637
     * @param $rolename The role name
638
     * @param $password The new password
639
     *
640
     * @return int 0 if operation was successful
641
     */
642
    public function changePassword($rolename, $password)
643
    {
644
        $enc = $this->_encryptPassword($rolename, $password);
645
        $this->fieldClean($rolename);
646
        $this->clean($enc);
647
648
        $sql = "ALTER ROLE \"{$rolename}\" WITH ENCRYPTED PASSWORD '{$enc}'";
649
650
        return $this->execute($sql);
651
    }
652
653
    /**
654
     * Adds a group member.
655
     *
656
     * @param $groname The name of the group
657
     * @param $user    The name of the user to add to the group
658
     *
659
     * @return int 0 if operation was successful
660
     */
661
    public function addGroupMember($groname, $user)
662
    {
663
        $this->fieldClean($groname);
664
        $this->fieldClean($user);
665
666
        $sql = "ALTER GROUP \"{$groname}\" ADD USER \"{$user}\"";
667
668
        return $this->execute($sql);
669
    }
670
671
    /**
672
     * Returns all role names which the role belongs to.
673
     *
674
     * @param $rolename The role name
675
     *
676
     * @return All role names
677
     */
678
    public function getMemberOf($rolename)
679
    {
680
        $this->clean($rolename);
681
682
        $sql = "
683
			SELECT rolname FROM pg_catalog.pg_roles R, pg_auth_members M
684
			WHERE R.oid=M.roleid
685
				AND member IN (
686
					SELECT oid FROM pg_catalog.pg_roles
687
					WHERE rolname='{$rolename}')
688
			ORDER BY rolname";
689
690
        return $this->selectSet($sql);
691
    }
692
693
    // Administration functions
694
695
    /**
696
     * Returns all role names that are members of a role.
697
     *
698
     * @param $rolename The role name
699
     * @param $admin    (optional) Find only admin members
700
     *
701
     * @return All role names
702
     */
703
    public function getMembers($rolename, $admin = 'f')
704
    {
705
        $this->clean($rolename);
706
707
        $sql = "
708
			SELECT rolname FROM pg_catalog.pg_roles R, pg_auth_members M
709
			WHERE R.oid=M.member AND admin_option='{$admin}'
710
				AND roleid IN (SELECT oid FROM pg_catalog.pg_roles
711
					WHERE rolname='{$rolename}')
712
			ORDER BY rolname";
713
714
        return $this->selectSet($sql);
715
    }
716
717
    /**
718
     * Removes a group member.
719
     *
720
     * @param $groname The name of the group
721
     * @param $user    The name of the user to remove from the group
722
     *
723
     * @return int 0 if operation was successful
724
     */
725
    public function dropGroupMember($groname, $user)
726
    {
727
        $this->fieldClean($groname);
728
        $this->fieldClean($user);
729
730
        $sql = "ALTER GROUP \"{$groname}\" DROP USER \"{$user}\"";
731
732
        return $this->execute($sql);
733
    }
734
735
    /**
736
     * Return users in a specific group.
737
     *
738
     * @param $groname The name of the group
739
     *
740
     * @return All users in the group
741
     */
742
    public function getGroup($groname)
743
    {
744
        $this->clean($groname);
745
746
        $sql = "
747
			SELECT s.usename FROM pg_catalog.pg_user s, pg_catalog.pg_group g
748
			WHERE g.groname='{$groname}' AND s.usesysid = ANY (g.grolist)
749
			ORDER BY s.usename";
750
751
        return $this->selectSet($sql);
752
    }
753
754
    /**
755
     * Returns all groups in the database cluser.
756
     *
757
     * @return All groups
758
     */
759
    public function getGroups()
760
    {
761
        $sql = 'SELECT groname FROM pg_group ORDER BY groname';
762
763
        return $this->selectSet($sql);
764
    }
765
766
    /**
767
     * Creates a new group.
768
     *
769
     * @param $groname The name of the group
770
     * @param $users   An array of users to add to the group
0 ignored issues
show
Bug introduced by
The type PHPPgAdmin\Database\An was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
771
     *
772
     * @return int 0 if operation was successful
773
     */
774
    public function createGroup($groname, $users)
775
    {
776
        $this->fieldClean($groname);
777
778
        $sql = "CREATE GROUP \"{$groname}\"";
779
780
        if (is_array($users) && sizeof($users) > 0) {
781
            $this->fieldArrayClean($users);
782
            $sql .= ' WITH USER "' . join('", "', $users) . '"';
783
        }
784
785
        return $this->execute($sql);
786
    }
787
788
    /**
789
     * Removes a group.
790
     *
791
     * @param $groname The name of the group to drop
792
     *
793
     * @return int 0 if operation was successful
794
     */
795
    public function dropGroup($groname)
796
    {
797
        $this->fieldClean($groname);
798
799
        $sql = "DROP GROUP \"{$groname}\"";
800
801
        return $this->execute($sql);
802
    }
803
804
    /**
805
     * Grants a privilege to a user, group or public.
806
     *
807
     * @param $mode        'GRANT' or 'REVOKE';
0 ignored issues
show
Documentation Bug introduced by
The doc comment 'GRANT' at position 0 could not be parsed: Unknown type name ''GRANT'' at position 0 in 'GRANT'.
Loading history...
808
     * @param $type        The type of object
809
     * @param $object      The name of the object
810
     * @param $public      True to grant to public, false otherwise
811
     * @param $usernames   the array of usernames to grant privs to
812
     * @param $groupnames  the array of group names to grant privs to
813
     * @param $privileges  The array of privileges to grant (eg. ('SELECT', 'ALL PRIVILEGES', etc.) )
814
     * @param $grantoption True if has grant option, false otherwise
815
     * @param $cascade     True for cascade revoke, false otherwise
816
     * @param $table       the column's table if type=column
817
     *
818
     * @return int 0 if operation was successful
819
     */
820
    public function setPrivileges(
821
        $mode,
822
        $type,
823
        $object,
824
        $public,
825
        $usernames,
826
        $groupnames,
827
        $privileges,
828
        $grantoption,
829
        $cascade,
830
        $table
831
    ) {
832
        $f_schema = $this->_schema;
833
        $this->fieldClean($f_schema);
834
        $this->fieldArrayClean($usernames);
835
        $this->fieldArrayClean($groupnames);
836
837
        // Input checking
838
        if (!is_array($privileges) || sizeof($privileges) == 0) {
839
            return -3;
840
        }
841
842
        if (!is_array($usernames) || !is_array($groupnames) ||
843
            (!$public && sizeof($usernames) == 0 && sizeof($groupnames) == 0)) {
2 ignored issues
show
Coding Style introduced by
Each line in a multi-line IF statement must begin with a boolean operator
Loading history...
Coding Style introduced by
Closing parenthesis of a multi-line IF statement must be on a new line
Loading history...
844
            return -4;
845
        }
846
847
        if ($mode != 'GRANT' && $mode != 'REVOKE') {
848
            return -5;
849
        }
850
851
        $sql = $mode;
852
853
        // Grant option
854
        if ($this->hasGrantOption() && $mode == 'REVOKE' && $grantoption) {
0 ignored issues
show
Bug introduced by
It seems like hasGrantOption() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

854
        if ($this->/** @scrutinizer ignore-call */ hasGrantOption() && $mode == 'REVOKE' && $grantoption) {
Loading history...
855
            $sql .= ' GRANT OPTION FOR';
856
        }
857
858
        if (in_array('ALL PRIVILEGES', $privileges, true)) {
859
            $sql .= ' ALL PRIVILEGES';
860
        } else {
861
            if ($type == 'column') {
862
                $this->fieldClean($object);
863
                $sql .= ' ' . join(" (\"{$object}\"), ", $privileges);
864
            } else {
865
                $sql .= ' ' . join(', ', $privileges);
866
            }
867
        }
868
869
        switch ($type) {
870
            case 'column':
871
                $sql .= " (\"{$object}\")";
872
                $object = $table;
873
            // no break
874
            case 'table':
875
            case 'view':
876
            case 'sequence':
877
                $this->fieldClean($object);
878
                $sql .= " ON \"{$f_schema}\".\"{$object}\"";
879
880
                break;
881
            case 'database':
882
                $this->fieldClean($object);
883
                $sql .= " ON DATABASE \"{$object}\"";
884
885
                break;
886
            case 'function':
887
                // Function comes in with $object as function OID
888
                $fn = $this->getFunction($object);
0 ignored issues
show
Bug introduced by
It seems like getFunction() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

888
                /** @scrutinizer ignore-call */ 
889
                $fn = $this->getFunction($object);
Loading history...
889
                $this->fieldClean($fn->fields['proname']);
890
                $sql .= " ON FUNCTION \"{$f_schema}\".\"{$fn->fields['proname']}\"({$fn->fields['proarguments']})";
891
892
                break;
893
            case 'language':
894
                $this->fieldClean($object);
895
                $sql .= " ON LANGUAGE \"{$object}\"";
896
897
                break;
898
            case 'schema':
899
                $this->fieldClean($object);
900
                $sql .= " ON SCHEMA \"{$object}\"";
901
902
                break;
903
            case 'tablespace':
904
                $this->fieldClean($object);
905
                $sql .= " ON TABLESPACE \"{$object}\"";
906
907
                break;
908
            default:
909
                return -1;
910
        }
911
912
        // Dump PUBLIC
913
        $first = true;
914
        $sql .= ($mode == 'GRANT') ? ' TO ' : ' FROM ';
915
        if ($public) {
916
            $sql .= 'PUBLIC';
917
            $first = false;
918
        }
919
        // Dump users
920
        foreach ($usernames as $v) {
921
            if ($first) {
922
                $sql .= "\"{$v}\"";
923
                $first = false;
924
            } else {
925
                $sql .= ", \"{$v}\"";
926
            }
927
        }
928
        // Dump groups
929
        foreach ($groupnames as $v) {
930
            if ($first) {
931
                $sql .= "GROUP \"{$v}\"";
932
                $first = false;
933
            } else {
934
                $sql .= ", GROUP \"{$v}\"";
935
            }
936
        }
937
938
        // Grant option
939
        if ($this->hasGrantOption() && $mode == 'GRANT' && $grantoption) {
940
            $sql .= ' WITH GRANT OPTION';
941
        }
942
943
        // Cascade revoke
944
        if ($this->hasGrantOption() && $mode == 'REVOKE' && $cascade) {
945
            $sql .= ' CASCADE';
946
        }
947
948
        return $this->execute($sql);
949
    }
950
951
}
952