Passed
Push — develop ( 49abac...9864d8 )
by Felipe
05:09
created

RoleTrait::setRole()   B

Complexity

Conditions 8
Paths 16

Size

Total Lines 54
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 54
rs 7.4119
c 0
b 0
f 0
cc 8
eloc 20
nc 16
nop 15

How to fix   Long Method    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.43
5
 */
6
7
namespace PHPPgAdmin\Traits;
8
9
/**
10
 * Common trait for roles and users manipulation.
11
 */
12
trait RoleTrait
13
{
14
    /**
15
     * Returns all roles in the database cluster.
16
     *
17
     * @param string $rolename (optional) The role name to exclude from the select
18
     *
19
     * @return \PHPPgAdmin\ADORecordSet Either one or All roles
20
     */
21
    public function getRoles($rolename = '')
22
    {
23
        $sql = '
24
			SELECT rolname, rolsuper, rolcreatedb, rolcreaterole, rolinherit,
25
				rolcanlogin, rolconnlimit, rolvaliduntil, rolconfig
26
			FROM pg_catalog.pg_roles';
27
        if ($rolename) {
28
            $sql .= " WHERE rolname!='{$rolename}'";
29
        }
30
31
        $sql .= ' ORDER BY rolname';
32
33
        return $this->selectSet($sql);
34
    }
35
36
    /**
37
     * Returns information about a single role.
38
     *
39
     * @param string $rolename The name of the role to retrieve
40
     *
41
     * @return \PHPPgAdmin\ADORecordSet The role's data
42
     */
43
    public function getRole($rolename)
44
    {
45
        $this->clean($rolename);
46
47
        $sql = "
48
			SELECT rolname, rolsuper, rolcreatedb, rolcreaterole, rolinherit,
49
				rolcanlogin, rolconnlimit, rolvaliduntil, rolconfig
50
			FROM pg_catalog.pg_roles WHERE rolname='{$rolename}'";
51
52
        return $this->selectSet($sql);
53
    }
54
55
    /**
56
     * Returns all users in the database cluster.
57
     *
58
     * @return \PHPPgAdmin\ADORecordSet All users
59
     */
60
    public function getUsers()
61
    {
62
        $sql = 'SELECT usename, usesuper, usecreatedb, valuntil AS useexpires, useconfig
63
			FROM pg_user
64
			ORDER BY usename';
65
66
        return $this->selectSet($sql);
67
    }
68
69
    /**
70
     * Returns information about a single user.
71
     *
72
     * @param string $username The username of the user to retrieve
73
     *
74
     * @return \PHPPgAdmin\ADORecordSet The user's data
75
     */
76
    public function getUser($username)
77
    {
78
        $this->clean($username);
79
80
        $sql = "SELECT usename, usesuper, usecreatedb, valuntil AS useexpires, useconfig
81
			FROM pg_user
82
			WHERE usename='{$username}'";
83
84
        return $this->selectSet($sql);
85
    }
86
87
    /**
88
     * Creates a new role.
89
     *
90
     * @param string $rolename     The name of the role to create
91
     * @param string $password     A password for the role
92
     * @param bool   $superuser    Boolean whether or not the role is a superuser
93
     * @param bool   $createdb     Boolean whether or not the role can create databases
94
     * @param bool   $createrole   Boolean whether or not the role can create other roles
95
     * @param bool   $inherits     Boolean whether or not the role inherits the privileges from parent roles
96
     * @param bool   $login        Boolean whether or not the role will be allowed to login
97
     * @param number $connlimit    Number of concurrent connections the role can make
98
     * @param string $expiry       String Format 'YYYY-MM-DD HH:MM:SS'.  '' means never expire
99
     * @param array  $new_roles_to_add     (array) Roles to which the new role will be immediately added as a new member
100
     * @param array  $new_members_of_role      (array) Roles which are automatically added as members of the new role
101
     * @param array  $new_admins_of_role (array) Roles which are automatically added as admin members of the new role
102
     *
103
     * @return int 0 if operation was successful
104
     */
105
    public function createRole(
106
        $rolename,
107
        $password,
108
        $superuser,
109
        $createdb,
110
        $createrole,
111
        $inherits,
112
        $login,
113
        $connlimit,
114
        $expiry,
115
        $new_roles_to_add,
116
        $new_members_of_role,
117
        $new_admins_of_role
118
    ) {
119
        $enc = $this->_encryptPassword($rolename, $password);
120
        $this->fieldClean($rolename);
121
        $this->clean($enc);
122
        $this->clean($connlimit);
123
        $this->clean($expiry);
124
        $this->fieldArrayClean($new_roles_to_add);
125
        $this->fieldArrayClean($new_members_of_role);
126
        $this->fieldArrayClean($new_admins_of_role);
127
128
        $sql = "CREATE ROLE \"{$rolename}\"";
129
        if ($password != '') {
130
            $sql .= " WITH ENCRYPTED PASSWORD '{$enc}'";
131
        }
132
133
        $sql .= $superuser ? ' SUPERUSER' : ' NOSUPERUSER';
134
        $sql .= $createdb ? ' CREATEDB' : ' NOCREATEDB';
135
        $sql .= $createrole ? ' CREATEROLE' : ' NOCREATEROLE';
136
        $sql .= $inherits ? ' INHERIT' : ' NOINHERIT';
137
        $sql .= $login ? ' LOGIN' : ' NOLOGIN';
138
        if ($connlimit != '') {
139
            $sql .= " CONNECTION LIMIT {$connlimit}";
140
        } else {
141
            $sql .= ' CONNECTION LIMIT -1';
142
        }
143
144
        if ($expiry != '') {
145
            $sql .= " VALID UNTIL '{$expiry}'";
146
        } else {
147
            $sql .= " VALID UNTIL 'infinity'";
148
        }
149
150
        if (is_array($new_roles_to_add) && sizeof($new_roles_to_add) > 0) {
151
            $sql .= ' IN ROLE "' . join('", "', $new_roles_to_add) . '"';
152
        }
153
154
        if (is_array($new_members_of_role) && sizeof($new_members_of_role) > 0) {
155
            $sql .= ' ROLE "' . join('", "', $new_members_of_role) . '"';
156
        }
157
158
        if (is_array($new_admins_of_role) && sizeof($new_admins_of_role) > 0) {
159
            $sql .= ' ADMIN "' . join('", "', $new_admins_of_role) . '"';
160
        }
161
162
        return $this->execute($sql);
163
    }
164
165
    /**
166
     * Helper function that computes encypted PostgreSQL passwords.
167
     *
168
     * @param string $username The username
169
     * @param string $password The password
170
     *
171
     * @return string
172
     */
173
    public function _encryptPassword($username, $password)
174
    {
175
        return 'md5' . md5($password . $username);
176
    }
177
178
    /**
179
     * Adjusts a role's info and renames it.
180
     *
181
     * @param string $rolename        The name of the role to adjust
182
     * @param string $password        A password for the role
183
     * @param bool   $superuser       Boolean whether or not the role is a superuser
184
     * @param bool   $createdb        Boolean whether or not the role can create databases
185
     * @param bool   $createrole      Boolean whether or not the role can create other roles
186
     * @param bool   $inherits        Boolean whether or not the role inherits the privileges from parent roles
187
     * @param bool   $login           Boolean whether or not the role will be allowed to login
188
     * @param number $connlimit       Number of concurrent connections the role can make
189
     * @param string $expiry          string Format 'YYYY-MM-DD HH:MM:SS'.  '' means never expire
190
     *
191
     * @param array  $new_roles_to_add        (array) Roles to which the role will be immediately added as a new member
0 ignored issues
show
Coding Style introduced by
Parameter tags must be grouped together in a doc comment
Loading history...
192
     * @param array  $new_members_of_role         (array) Roles which are automatically added as members of the role
0 ignored issues
show
Coding Style introduced by
Parameter tags must be grouped together in a doc comment
Loading history...
193
     * @param array  $new_admins_of_role    (array) Roles which are automatically added as admin members of the role
0 ignored issues
show
Coding Style introduced by
Parameter tags must be grouped together in a doc comment
Loading history...
194
     *
195
     * @param string  $original_parent_roles     Original roles whose the role belongs to, comma separated
0 ignored issues
show
Coding Style introduced by
Parameter tags must be grouped together in a doc comment
Loading history...
196
     * @param string  $original_members      Original roles that are members of the role, comma separated
0 ignored issues
show
Coding Style introduced by
Parameter tags must be grouped together in a doc comment
Loading history...
197
     * @param string  $original_admins Original roles that are admin members of the role, comma separated
0 ignored issues
show
Coding Style introduced by
Parameter tags must be grouped together in a doc comment
Loading history...
198
     * @param string $newrolename     The new name of the role
0 ignored issues
show
Coding Style introduced by
Parameter tags must be grouped together in a doc comment
Loading history...
199
     *
200
     * @return bool|int 0 success
201
     */
202
    public function setRenameRole(
203
        $rolename,
204
        $password,
205
        $superuser,
206
        $createdb,
207
        $createrole,
208
        $inherits,
209
        $login,
210
        $connlimit,
211
        $expiry,
212
        $new_roles_to_add,
213
        $new_members_of_role,
214
        $new_admins_of_role,
215
        $original_parent_roles,
216
        $original_members,
217
        $original_admins,
218
        $newrolename
219
    ) {
220
        $status = $this->beginTransaction();
221
        if ($status != 0) {
222
            return -1;
223
        }
224
225
        if ($rolename != $newrolename) {
226
            $status = $this->renameRole($rolename, $newrolename);
227
            if ($status != 0) {
228
                $this->rollbackTransaction();
229
230
                return -3;
231
            }
232
            $rolename = $newrolename;
233
        }
234
235
        $status =
0 ignored issues
show
Coding Style introduced by
Multi-line assignments must have the equal sign on the second line
Loading history...
236
        $this->setRole(
237
            $rolename,
238
            $password,
239
            $superuser,
240
            $createdb,
241
            $createrole,
242
            $inherits,
243
            $login,
244
            $connlimit,
245
            $expiry,
246
            $new_roles_to_add,
247
            $new_members_of_role,
248
            $new_admins_of_role,
249
            $original_parent_roles,
250
            $original_members,
251
            $original_admins
252
        );
253
        if ($status != 0) {
254
            $this->rollbackTransaction();
255
256
            return -2;
257
        }
258
259
        return $this->endTransaction();
260
    }
261
262
    /**
263
     * Renames a role.
264
     *
265
     * @param string $rolename    The name of the role to rename
266
     * @param string $newrolename The new name of the role
267
     *
268
     * @return int 0 if operation was successful
269
     */
270
    public function renameRole($rolename, $newrolename)
271
    {
272
        $this->fieldClean($rolename);
273
        $this->fieldClean($newrolename);
274
275
        $sql = "ALTER ROLE \"{$rolename}\" RENAME TO \"{$newrolename}\"";
276
277
        return $this->execute($sql);
278
    }
279
280
    private function _dealWithOldParentRoles($original_parent_roles, $new_roles_to_add, $rolename)
281
    {
282
        $old = explode(',', $original_parent_roles);
283
284
        // Grant the roles of the old role owners to the new owner
285
        foreach ($new_roles_to_add as $m) {
286
            if (!in_array($m, $old, true)) {
287
                $status = $this->grantRole($m, $rolename);
288
                if ($status != 0) {
289
                    return -1;
290
                }
291
            }
292
        }
293
294
        // Revoke the new role to the old members if they don't have the requested role name
295
296
        foreach ($old as $o) {
297
            if (!in_array($o, $new_roles_to_add, true)) {
298
                $status = $this->revokeRole($o, $rolename, 0, 'CASCADE');
299
                if ($status != 0) {
300
                    return -1;
301
                }
302
            }
303
        }
304
        return 0;
305
306
    }
307
308
    private function _dealWithOriginalMembers($original_members, $new_members_of_role, $rolename)
309
    {
310
        //members
311
        $old = explode(',', $original_members);
312
        foreach ($new_members_of_role as $m) {
313
            if (!in_array($m, $old, true)) {
314
                $status = $this->grantRole($rolename, $m);
315
                if ($status != 0) {
316
                    return -1;
317
                }
318
            }
319
        }
320
        if ($original_members) {
321
            foreach ($old as $o) {
322
                if (!in_array($o, $new_members_of_role, true)) {
323
                    $status = $this->revokeRole($rolename, $o, 0, 'CASCADE');
324
                    if ($status != 0) {
325
                        return -1;
326
                    }
327
                }
328
            }
329
        }
330
        return 0;
331
    }
332
333
    private function _dealWithOriginalAdmins($original_admins, $new_admins_of_role, $rolename)
334
    {
335
        $old = explode(',', $original_admins);
336
        foreach ($new_admins_of_role as $m) {
337
            if (!in_array($m, $old, true)) {
338
                $status = $this->grantRole($rolename, $m, 1);
339
                if ($status != 0) {
340
                    return -1;
341
                }
342
            }
343
        }
344
345
        foreach ($old as $o) {
346
            if (!in_array($o, $new_admins_of_role, true)) {
347
                $status = $this->revokeRole($rolename, $o, 1, 'CASCADE');
348
                if ($status != 0) {
349
                    return -1;
350
                }
351
            }
352
        }
353
        return 0;
354
    }
355
356
    private function _alterRole($rolename, $password, $connlimit, $expiry)
357
    {
358
        $enc = $this->_encryptPassword($rolename, $password);
359
        $this->clean($enc);
360
        $this->clean($connlimit);
361
        $this->clean($expiry);
362
363
        $sql = "ALTER ROLE \"{$rolename}\"";
364
        if ($password != '') {
365
            $sql .= " WITH ENCRYPTED PASSWORD '{$enc}'";
366
        }
367
368
        $sql .= $superuser ? ' SUPERUSER' : ' NOSUPERUSER';
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $superuser seems to be never defined.
Loading history...
369
        $sql .= $createdb ? ' CREATEDB' : ' NOCREATEDB';
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $createdb seems to be never defined.
Loading history...
370
        $sql .= $createrole ? ' CREATEROLE' : ' NOCREATEROLE';
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $createrole seems to be never defined.
Loading history...
371
        $sql .= $inherits ? ' INHERIT' : ' NOINHERIT';
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $inherits seems to be never defined.
Loading history...
372
        $sql .= $login ? ' LOGIN' : ' NOLOGIN';
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $login seems to be never defined.
Loading history...
373
        if ($connlimit != '') {
374
            $sql .= " CONNECTION LIMIT {$connlimit}";
375
        } else {
376
            $sql .= ' CONNECTION LIMIT -1';
377
        }
378
379
        if ($expiry != '') {
380
            $sql .= " VALID UNTIL '{$expiry}'";
381
        } else {
382
            $sql .= " VALID UNTIL 'infinity'";
383
        }
384
385
        return $this->execute($sql);
386
387
    }
388
389
    /**
390
     * Adjusts a role's info.
391
     *
392
     * @param string $rolename        The name of the role to adjust
393
     * @param string $password        A password for the role
394
     * @param bool   $superuser       Boolean whether or not the role is a superuser
395
     * @param bool   $createdb        Boolean whether or not the role can create databases
396
     * @param bool   $createrole      Boolean whether or not the role can create other roles
397
     * @param bool   $inherits        Boolean whether or not the role inherits the privileges from parent roles
398
     * @param bool   $login           Boolean whether or not the role will be allowed to login
399
     * @param number $connlimit       Number of concurrent connections the role can make
400
     * @param string $expiry          string Format 'YYYY-MM-DD HH:MM:SS'.  '' means never expire
401
     * @param array  $new_roles_to_add        (array) Roles to which the role will be immediately added as a new member
402
     * @param array  $new_members_of_role         (array) Roles which are automatically added as members of the role
403
     * @param array  $new_admins_of_role    (array) Roles which are automatically added as admin members of the role
404
     * @param string $original_parent_roles     Original roles whose the role belongs to, comma separated
405
     * @param string $original_members      Original roles that are members of the role, comma separated
406
     * @param string $original_admins Original roles that are admin members of the role, comma separated
407
     *
408
     * @return int 0 if operation was successful
409
     */
410
    public function setRole(
411
        $rolename,
412
        $password,
413
        $superuser,
0 ignored issues
show
Unused Code introduced by
The parameter $superuser is not used and could be removed. ( Ignorable by Annotation )

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

413
        /** @scrutinizer ignore-unused */ $superuser,

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
414
        $createdb,
0 ignored issues
show
Unused Code introduced by
The parameter $createdb is not used and could be removed. ( Ignorable by Annotation )

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

414
        /** @scrutinizer ignore-unused */ $createdb,

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
415
        $createrole,
0 ignored issues
show
Unused Code introduced by
The parameter $createrole is not used and could be removed. ( Ignorable by Annotation )

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

415
        /** @scrutinizer ignore-unused */ $createrole,

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
416
        $inherits,
0 ignored issues
show
Unused Code introduced by
The parameter $inherits is not used and could be removed. ( Ignorable by Annotation )

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

416
        /** @scrutinizer ignore-unused */ $inherits,

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
417
        $login,
0 ignored issues
show
Unused Code introduced by
The parameter $login is not used and could be removed. ( Ignorable by Annotation )

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

417
        /** @scrutinizer ignore-unused */ $login,

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
418
        $connlimit,
419
        $expiry,
420
        $new_roles_to_add,
421
        $new_members_of_role,
422
        $new_admins_of_role,
423
        $original_parent_roles,
424
        $original_members,
425
        $original_admins
426
    ) {
427
        $this->fieldClean($rolename);
428
429
        $this->fieldArrayClean($new_roles_to_add);
430
        $this->fieldArrayClean($new_members_of_role);
431
        $this->fieldArrayClean($new_admins_of_role);
432
433
        $status = $this->_alterRole($rolename, $password, $connlimit, $expiry);
434
        if ($status !== 0) {
435
            return -1;
436
        }
437
438
        // If there were existing users with the requested role,
439
        // assign their roles to the new user, and remove said
440
        // role from them if they are not among the new authorized members
441
        if ($original_parent_roles) {
442
            $status = $this->_dealWithOldParentRoles($original_parent_roles, $new_roles_to_add, $rolename);
443
            if ($status !== 0) {
444
                return -1;
445
            }
446
        }
447
448
        if ($original_members) {
449
            $status = $this->_dealWithOriginalMembers($original_members, $new_members_of_role, $rolename);
450
            if ($status !== 0) {
451
                return -1;
452
            }
453
        }
454
455
        if ($original_admins) {
456
            $status = $this->_dealWithOriginalAdmins($original_admins, $new_admins_of_role, $rolename);
457
            if ($status !== 0) {
458
                return -1;
459
            }
460
461
        }
462
463
        return $status;
464
    }
465
466
    /**
467
     * Grants membership in a role.
468
     *
469
     * @param string $role     The name of the target role
470
     * @param string $rolename The name of the role that will belong to the target role
471
     * @param int    $admin    (optional) Flag to grant the admin option
472
     *
473
     * @return int 0 if operation was successful
474
     */
475
    public function grantRole($role, $rolename, $admin = 0)
476
    {
477
        $this->fieldClean($role);
478
        $this->fieldClean($rolename);
479
480
        $sql = "GRANT \"{$role}\" TO \"{$rolename}\"";
481
        if ($admin == 1) {
482
            $sql .= ' WITH ADMIN OPTION';
483
        }
484
485
        return $this->execute($sql);
486
    }
487
488
    /**
489
     * Revokes membership in a role.
490
     *
491
     * @param string $role     The name of the target role
492
     * @param string $rolename The name of the role that will not belong to the target role
493
     * @param int    $admin    (optional) Flag to revoke only the admin option
494
     * @param string $type     (optional) Type of revoke: RESTRICT | CASCADE
495
     *
496
     * @return int 0 if operation was successful
497
     */
498
    public function revokeRole($role, $rolename, $admin = 0, $type = 'RESTRICT')
499
    {
500
        $this->fieldClean($role);
501
        $this->fieldClean($rolename);
502
503
        $sql = 'REVOKE ';
504
        if ($admin == 1) {
505
            $sql .= 'ADMIN OPTION FOR ';
506
        }
507
508
        $sql .= "\"{$role}\" FROM \"{$rolename}\" {$type}";
509
510
        return $this->execute($sql);
511
    }
512
513
    /**
514
     * Removes a role.
515
     *
516
     * @param string $rolename The name of the role to drop
517
     *
518
     * @return int 0 if operation was successful
519
     */
520
    public function dropRole($rolename)
521
    {
522
        $this->fieldClean($rolename);
523
524
        $sql = "DROP ROLE \"{$rolename}\"";
525
526
        return $this->execute($sql);
527
    }
528
529
    /**
530
     * Creates a new user.
531
     *
532
     * @param string $username   The username of the user to create
533
     * @param string $password   A password for the user
534
     * @param bool   $createdb   boolean Whether or not the user can create databases
535
     * @param bool   $createuser boolean Whether or not the user can create other users
536
     * @param string $expiry     string Format 'YYYY-MM-DD HH:MM:SS'.  '' means never expire
537
     * @param array  $groups     The groups to create the user in
538
     *
539
     * @return int 0 if operation was successful
540
     *
541
     * @internal param $group (array) The groups to create the user in
542
     */
543
    public function createUser($username, $password, $createdb, $createuser, $expiry, $groups)
544
    {
545
        $enc = $this->_encryptPassword($username, $password);
546
        $this->fieldClean($username);
547
        $this->clean($enc);
548
        $this->clean($expiry);
549
        $this->fieldArrayClean($groups);
550
551
        $sql = "CREATE USER \"{$username}\"";
552
        if ($password != '') {
553
            $sql .= " WITH ENCRYPTED PASSWORD '{$enc}'";
554
        }
555
556
        $sql .= $createdb ? ' CREATEDB' : ' NOCREATEDB';
557
        $sql .= $createuser ? ' CREATEUSER' : ' NOCREATEUSER';
558
        if (is_array($groups) && sizeof($groups) > 0) {
559
            $sql .= ' IN GROUP "' . join('", "', $groups) . '"';
560
        }
561
562
        if ($expiry != '') {
563
            $sql .= " VALID UNTIL '{$expiry}'";
564
        } else {
565
            $sql .= " VALID UNTIL 'infinity'";
566
        }
567
568
        return $this->execute($sql);
569
    }
570
571
    /**
572
     * Adjusts a user's info and renames the user.
573
     *
574
     * @param string $username   The username of the user to modify
575
     * @param string $password   A new password for the user
576
     * @param bool   $createdb   boolean Whether or not the user can create databases
577
     * @param bool   $createuser boolean Whether or not the user can create other users
578
     * @param string $expiry     string Format 'YYYY-MM-DD HH:MM:SS'.  '' means never expire.
579
     * @param string $newname    The new name of the user
580
     *
581
     * @return bool|int 0 success
582
     */
583
    public function setRenameUser($username, $password, $createdb, $createuser, $expiry, $newname)
584
    {
585
        $status = $this->beginTransaction();
586
        if ($status != 0) {
587
            return -1;
588
        }
589
590
        if ($username != $newname) {
591
            $status = $this->renameUser($username, $newname);
592
            if ($status != 0) {
593
                $this->rollbackTransaction();
594
595
                return -3;
596
            }
597
            $username = $newname;
598
        }
599
600
        $status = $this->setUser($username, $password, $createdb, $createuser, $expiry);
601
        if ($status != 0) {
602
            $this->rollbackTransaction();
603
604
            return -2;
605
        }
606
607
        return $this->endTransaction();
608
    }
609
610
    /**
611
     * Renames a user.
612
     *
613
     * @param string $username The username of the user to rename
614
     * @param string $newname  The new name of the user
615
     *
616
     * @return int 0 if operation was successful
617
     */
618
    public function renameUser($username, $newname)
619
    {
620
        $this->fieldClean($username);
621
        $this->fieldClean($newname);
622
623
        $sql = "ALTER USER \"{$username}\" RENAME TO \"{$newname}\"";
624
625
        return $this->execute($sql);
626
    }
627
628
    // Tablespace functions
629
630
    /**
631
     * Adjusts a user's info.
632
     *
633
     * @param string $username   The username of the user to modify
634
     * @param string $password   A new password for the user
635
     * @param bool   $createdb   boolean Whether or not the user can create databases
636
     * @param bool   $createuser boolean Whether or not the user can create other users
637
     * @param string $expiry     string Format 'YYYY-MM-DD HH:MM:SS'.  '' means never expire.
638
     *
639
     * @return int 0 if operation was successful
640
     */
641
    public function setUser($username, $password, $createdb, $createuser, $expiry)
642
    {
643
        $enc = $this->_encryptPassword($username, $password);
644
        $this->fieldClean($username);
645
        $this->clean($enc);
646
        $this->clean($expiry);
647
648
        $sql = "ALTER USER \"{$username}\"";
649
        if ($password != '') {
650
            $sql .= " WITH ENCRYPTED PASSWORD '{$enc}'";
651
        }
652
653
        $sql .= $createdb ? ' CREATEDB' : ' NOCREATEDB';
654
        $sql .= $createuser ? ' CREATEUSER' : ' NOCREATEUSER';
655
        if ($expiry != '') {
656
            $sql .= " VALID UNTIL '{$expiry}'";
657
        } else {
658
            $sql .= " VALID UNTIL 'infinity'";
659
        }
660
661
        return $this->execute($sql);
662
    }
663
664
    /**
665
     * Removes a user.
666
     *
667
     * @param string $username The username of the user to drop
668
     *
669
     * @return int 0 if operation was successful
670
     */
671
    public function dropUser($username)
672
    {
673
        $this->fieldClean($username);
674
675
        $sql = "DROP USER \"{$username}\"";
676
677
        return $this->execute($sql);
678
    }
679
680
    /**
681
     * Changes a role's password.
682
     *
683
     * @param string $rolename The role name
684
     * @param string $password The new password
685
     *
686
     * @return int 0 if operation was successful
687
     */
688
    public function changePassword($rolename, $password)
689
    {
690
        $enc = $this->_encryptPassword($rolename, $password);
691
        $this->fieldClean($rolename);
692
        $this->clean($enc);
693
694
        $sql = "ALTER ROLE \"{$rolename}\" WITH ENCRYPTED PASSWORD '{$enc}'";
695
696
        return $this->execute($sql);
697
    }
698
699
    /**
700
     * Adds a group member.
701
     *
702
     * @param string $groname The name of the group
703
     * @param string $user    The name of the user to add to the group
704
     *
705
     * @return int 0 if operation was successful
706
     */
707
    public function addGroupMember($groname, $user)
708
    {
709
        $this->fieldClean($groname);
710
        $this->fieldClean($user);
711
712
        $sql = "ALTER GROUP \"{$groname}\" ADD USER \"{$user}\"";
713
714
        return $this->execute($sql);
715
    }
716
717
    /**
718
     * Returns all role names which the role belongs to.
719
     *
720
     * @param string $rolename The role name
721
     *
722
     * @return \PHPPgAdmin\ADORecordSet All role names
723
     */
724
    public function getMemberOf($rolename)
725
    {
726
        $this->clean($rolename);
727
728
        $sql = "
729
			SELECT rolname FROM pg_catalog.pg_roles R, pg_auth_members M
730
			WHERE R.oid=M.roleid
731
				AND member IN (
732
					SELECT oid FROM pg_catalog.pg_roles
733
					WHERE rolname='{$rolename}')
734
			ORDER BY rolname";
735
736
        return $this->selectSet($sql);
737
    }
738
739
    // Administration functions
740
741
    /**
742
     * Returns all role names that are members of a role.
743
     *
744
     * @param string $rolename The role name
745
     * @param string $admin    (optional) Find only admin members
746
     *
747
     * @return \PHPPgAdmin\ADORecordSet All role names
748
     */
749
    public function getMembers($rolename, $admin = 'f')
750
    {
751
        $this->clean($rolename);
752
753
        $sql = "
754
			SELECT rolname FROM pg_catalog.pg_roles R, pg_auth_members M
755
			WHERE R.oid=M.member AND admin_option='{$admin}'
756
				AND roleid IN (SELECT oid FROM pg_catalog.pg_roles
757
					WHERE rolname='{$rolename}')
758
			ORDER BY rolname";
759
760
        return $this->selectSet($sql);
761
    }
762
763
    /**
764
     * Removes a group member.
765
     *
766
     * @param string $groname The name of the group
767
     * @param string $user    The name of the user to remove from the group
768
     *
769
     * @return int 0 if operation was successful
770
     */
771
    public function dropGroupMember($groname, $user)
772
    {
773
        $this->fieldClean($groname);
774
        $this->fieldClean($user);
775
776
        $sql = "ALTER GROUP \"{$groname}\" DROP USER \"{$user}\"";
777
778
        return $this->execute($sql);
779
    }
780
781
    /**
782
     * Return users in a specific group.
783
     *
784
     * @param string $groname The name of the group
785
     *
786
     * @return \PHPPgAdmin\ADORecordSet All users in the group
787
     */
788
    public function getGroup($groname)
789
    {
790
        $this->clean($groname);
791
792
        $sql = "
793
			SELECT s.usename FROM pg_catalog.pg_user s, pg_catalog.pg_group g
794
			WHERE g.groname='{$groname}' AND s.usesysid = ANY (g.grolist)
795
			ORDER BY s.usename";
796
797
        return $this->selectSet($sql);
798
    }
799
800
    /**
801
     * Returns all groups in the database cluser.
802
     *
803
     * @return \PHPPgAdmin\ADORecordSet All groups
804
     */
805
    public function getGroups()
806
    {
807
        $sql = 'SELECT groname FROM pg_group ORDER BY groname';
808
809
        return $this->selectSet($sql);
810
    }
811
812
    /**
813
     * Creates a new group.
814
     *
815
     * @param string $groname The name of the group
816
     * @param array  $users   An array of users to add to the group
817
     *
818
     * @return int 0 if operation was successful
819
     */
820
    public function createGroup($groname, $users)
821
    {
822
        $this->fieldClean($groname);
823
824
        $sql = "CREATE GROUP \"{$groname}\"";
825
826
        if (is_array($users) && sizeof($users) > 0) {
827
            $this->fieldArrayClean($users);
828
            $sql .= ' WITH USER "' . join('", "', $users) . '"';
829
        }
830
831
        return $this->execute($sql);
832
    }
833
834
    /**
835
     * Removes a group.
836
     *
837
     * @param string $groname The name of the group to drop
838
     *
839
     * @return int 0 if operation was successful
840
     */
841
    public function dropGroup($groname)
842
    {
843
        $this->fieldClean($groname);
844
845
        $sql = "DROP GROUP \"{$groname}\"";
846
847
        return $this->execute($sql);
848
    }
849
850
    /**
851
     * Grants a privilege to a user, group or public.
852
     *
853
     * @param string $mode        'GRANT' or 'REVOKE';
854
     * @param mixed  $type        The type of object
855
     * @param string $object      The name of the object
856
     * @param bool   $public      True to grant to public, false otherwise
857
     * @param mixed  $usernames   the array of usernames to grant privs to
858
     * @param mixed  $groupnames  the array of group names to grant privs to
859
     * @param mixed  $privileges  The array of privileges to grant (eg. ('SELECT', 'ALL PRIVILEGES', etc.) )
860
     * @param bool   $grantoption True if has grant option, false otherwise
861
     * @param bool   $cascade     True for cascade revoke, false otherwise
862
     * @param string $table       the column's table if type=column
863
     *
864
     * @return int 0 if operation was successful
865
     */
866
    public function setPrivileges(
867
        $mode,
868
        $type,
869
        $object,
870
        $public,
871
        $usernames,
872
        $groupnames,
873
        $privileges,
874
        $grantoption,
875
        $cascade,
876
        $table
877
    ) {
878
        $f_schema = $this->_schema;
879
        $this->fieldClean($f_schema);
880
        $this->fieldArrayClean($usernames);
881
        $this->fieldArrayClean($groupnames);
882
883
        // Input checking
884
        if (!is_array($privileges) || sizeof($privileges) == 0) {
885
            return -3;
886
        }
887
888
        if (!is_array($usernames) || !is_array($groupnames) ||
889
            (!$public && sizeof($usernames) == 0 && sizeof($groupnames) == 0)) {
890
            return -4;
891
        }
892
893
        if ($mode != 'GRANT' && $mode != 'REVOKE') {
894
            return -5;
895
        }
896
897
        $sql = $mode;
898
899
        // Grant option
900
        if ($this->hasGrantOption() && $mode == 'REVOKE' && $grantoption) {
901
            $sql .= ' GRANT OPTION FOR';
902
        }
903
904
        if (in_array('ALL PRIVILEGES', $privileges, true)) {
905
            $sql .= ' ALL PRIVILEGES';
906
        } else {
907
            if ($type == 'column') {
908
                $this->fieldClean($object);
909
                $sql .= ' ' . join(" (\"{$object}\"), ", $privileges);
910
            } else {
911
                $sql .= ' ' . join(', ', $privileges);
912
            }
913
        }
914
915
        switch ($type) {
916
            case 'column':
917
                $sql .= " (\"{$object}\")";
918
                $object = $table;
919
            // no break
920
            case 'table':
921
            case 'view':
922
            case 'sequence':
923
                $this->fieldClean($object);
924
                $sql .= " ON \"{$f_schema}\".\"{$object}\"";
925
926
                break;
927
            case 'database':
928
                $this->fieldClean($object);
929
                $sql .= " ON DATABASE \"{$object}\"";
930
931
                break;
932
            case 'function':
933
                // Function comes in with $object as function OID
934
                $fn = $this->getFunction($object);
935
                $this->fieldClean($fn->fields['proname']);
936
                $sql .= " ON FUNCTION \"{$f_schema}\".\"{$fn->fields['proname']}\"({$fn->fields['proarguments']})";
937
938
                break;
939
            case 'language':
940
                $this->fieldClean($object);
941
                $sql .= " ON LANGUAGE \"{$object}\"";
942
943
                break;
944
            case 'schema':
945
                $this->fieldClean($object);
946
                $sql .= " ON SCHEMA \"{$object}\"";
947
948
                break;
949
            case 'tablespace':
950
                $this->fieldClean($object);
951
                $sql .= " ON TABLESPACE \"{$object}\"";
952
953
                break;
954
            default:
955
                return -1;
956
        }
957
958
        // Dump PUBLIC
959
        $first = true;
960
        $sql .= ($mode == 'GRANT') ? ' TO ' : ' FROM ';
961
        if ($public) {
962
            $sql .= 'PUBLIC';
963
            $first = false;
964
        }
965
        // Dump users
966
        foreach ($usernames as $v) {
967
            if ($first) {
968
                $sql .= "\"{$v}\"";
969
                $first = false;
970
            } else {
971
                $sql .= ", \"{$v}\"";
972
            }
973
        }
974
        // Dump groups
975
        foreach ($groupnames as $v) {
976
            if ($first) {
977
                $sql .= "GROUP \"{$v}\"";
978
                $first = false;
979
            } else {
980
                $sql .= ", GROUP \"{$v}\"";
981
            }
982
        }
983
984
        // Grant option
985
        if ($this->hasGrantOption() && $mode == 'GRANT' && $grantoption) {
986
            $sql .= ' WITH GRANT OPTION';
987
        }
988
989
        // Cascade revoke
990
        if ($this->hasGrantOption() && $mode == 'REVOKE' && $cascade) {
991
            $sql .= ' CASCADE';
992
        }
993
994
        return $this->execute($sql);
995
    }
996
997
    abstract public function fieldClean(&$str);
998
999
    abstract public function beginTransaction();
1000
1001
    abstract public function rollbackTransaction();
1002
1003
    abstract public function endTransaction();
1004
1005
    abstract public function execute($sql);
1006
1007
    abstract public function setComment($obj_type, $obj_name, $table, $comment, $basetype = null);
1008
1009
    abstract public function selectSet($sql);
1010
1011
    abstract public function clean(&$str);
1012
1013
    abstract public function hasGrantOption();
1014
1015
    abstract public function getFunction($function_oid);
1016
1017
    abstract public function fieldArrayClean(&$arr);
1018
}
1019