GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Completed
Push — master ( a81d72...271609 )
by Robert
14:15
created

PhpManager::assign()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 16
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 10
CRAP Score 3.0416

Importance

Changes 0
Metric Value
dl 0
loc 16
rs 9.4285
c 0
b 0
f 0
ccs 10
cts 12
cp 0.8333
cc 3
eloc 12
nc 3
nop 2
crap 3.0416
1
<?php
2
/**
3
 * @link http://www.yiiframework.com/
4
 * @copyright Copyright (c) 2008 Yii Software LLC
5
 * @license http://www.yiiframework.com/license/
6
 */
7
8
namespace yii\rbac;
9
10
use yii\base\InvalidCallException;
11
use yii\base\InvalidParamException;
12
use Yii;
13
use yii\helpers\VarDumper;
14
15
/**
16
 * PhpManager represents an authorization manager that stores authorization
17
 * information in terms of a PHP script file.
18
 *
19
 * The authorization data will be saved to and loaded from three files
20
 * specified by [[itemFile]], [[assignmentFile]] and [[ruleFile]].
21
 *
22
 * PhpManager is mainly suitable for authorization data that is not too big
23
 * (for example, the authorization data for a personal blog system).
24
 * Use [[DbManager]] for more complex authorization data.
25
 *
26
 * Note that PhpManager is not compatible with facebooks [HHVM](http://hhvm.com/) because
27
 * it relies on writing php files and including them afterwards which is not supported by HHVM.
28
 *
29
 * @author Qiang Xue <[email protected]>
30
 * @author Alexander Kochetov <[email protected]>
31
 * @author Christophe Boulain <[email protected]>
32
 * @author Alexander Makarov <[email protected]>
33
 * @since 2.0
34
 */
35
class PhpManager extends BaseManager
36
{
37
    /**
38
     * @var string the path of the PHP script that contains the authorization items.
39
     * This can be either a file path or a path alias to the file.
40
     * Make sure this file is writable by the Web server process if the authorization needs to be changed online.
41
     * @see loadFromFile()
42
     * @see saveToFile()
43
     */
44
    public $itemFile = '@app/rbac/items.php';
45
    /**
46
     * @var string the path of the PHP script that contains the authorization assignments.
47
     * This can be either a file path or a path alias to the file.
48
     * Make sure this file is writable by the Web server process if the authorization needs to be changed online.
49
     * @see loadFromFile()
50
     * @see saveToFile()
51
     */
52
    public $assignmentFile = '@app/rbac/assignments.php';
53
    /**
54
     * @var string the path of the PHP script that contains the authorization rules.
55
     * This can be either a file path or a path alias to the file.
56
     * Make sure this file is writable by the Web server process if the authorization needs to be changed online.
57
     * @see loadFromFile()
58
     * @see saveToFile()
59
     */
60
    public $ruleFile = '@app/rbac/rules.php';
61
62
    /**
63
     * @var Item[]
64
     */
65
    protected $items = []; // itemName => item
66
    /**
67
     * @var array
68
     */
69
    protected $children = []; // itemName, childName => child
70
    /**
71
     * @var array
72
     */
73
    protected $assignments = []; // userId, itemName => assignment
74
    /**
75
     * @var Rule[]
76
     */
77
    protected $rules = []; // ruleName => rule
78
79
80
    /**
81
     * Initializes the application component.
82
     * This method overrides parent implementation by loading the authorization data
83
     * from PHP script.
84
     */
85 27
    public function init()
86
    {
87 27
        parent::init();
88 27
        $this->itemFile = Yii::getAlias($this->itemFile);
0 ignored issues
show
Documentation Bug introduced by
It seems like \Yii::getAlias($this->itemFile) can also be of type boolean. However, the property $itemFile is declared as type string. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
89 27
        $this->assignmentFile = Yii::getAlias($this->assignmentFile);
0 ignored issues
show
Documentation Bug introduced by
It seems like \Yii::getAlias($this->assignmentFile) can also be of type boolean. However, the property $assignmentFile is declared as type string. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
90 27
        $this->ruleFile = Yii::getAlias($this->ruleFile);
0 ignored issues
show
Documentation Bug introduced by
It seems like \Yii::getAlias($this->ruleFile) can also be of type boolean. However, the property $ruleFile is declared as type string. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
91 27
        $this->load();
92 27
    }
93
94
    /**
95
     * @inheritdoc
96
     */
97 2
    public function checkAccess($userId, $permissionName, $params = [])
98
    {
99 2
        $assignments = $this->getAssignments($userId);
100 2
        return $this->checkAccessRecursive($userId, $permissionName, $params, $assignments);
101
    }
102
103
    /**
104
     * @inheritdoc
105
     */
106 6
    public function getAssignments($userId)
107
    {
108 6
        return isset($this->assignments[$userId]) ? $this->assignments[$userId] : [];
109
    }
110
111
    /**
112
     * Performs access check for the specified user.
113
     * This method is internally called by [[checkAccess()]].
114
     *
115
     * @param string|integer $user the user ID. This should can be either an integer or a string representing
116
     * the unique identifier of a user. See [[\yii\web\User::id]].
117
     * @param string $itemName the name of the operation that need access check
118
     * @param array $params name-value pairs that would be passed to rules associated
119
     * with the tasks and roles assigned to the user. A param with name 'user' is added to this array,
120
     * which holds the value of `$userId`.
121
     * @param Assignment[] $assignments the assignments to the specified user
122
     * @return boolean whether the operations can be performed by the user.
123
     */
124 2
    protected function checkAccessRecursive($user, $itemName, $params, $assignments)
125
    {
126 2
        if (!isset($this->items[$itemName])) {
127 1
            return false;
128
        }
129
130
        /* @var $item Item */
131 2
        $item = $this->items[$itemName];
132 2
        Yii::trace($item instanceof Role ? "Checking role: $itemName" : "Checking permission : $itemName", __METHOD__);
133
134 2
        if (!$this->executeRule($user, $item, $params)) {
135 2
            return false;
136
        }
137
138 2
        if (isset($assignments[$itemName]) || in_array($itemName, $this->defaultRoles)) {
139 2
            return true;
140
        }
141
142 1
        foreach ($this->children as $parentName => $children) {
143 1
            if (isset($children[$itemName]) && $this->checkAccessRecursive($user, $parentName, $params, $assignments)) {
144 1
                return true;
145
            }
146 1
        }
147
148 1
        return false;
149
    }
150
151
    /**
152
     * @inheritdoc
153
     * @since 2.0.8
154
     */
155 1
    public function canAddChild($parent, $child)
156
    {
157 1
        return !$this->detectLoop($parent, $child);
158
    }
159
160
    /**
161
     * @inheritdoc
162
     */
163 22
    public function addChild($parent, $child)
164
    {
165 22
        if (!isset($this->items[$parent->name], $this->items[$child->name])) {
166
            throw new InvalidParamException("Either '{$parent->name}' or '{$child->name}' does not exist.");
167
        }
168
169 22
        if ($parent->name === $child->name) {
170
            throw new InvalidParamException("Cannot add '{$parent->name} ' as a child of itself.");
171
        }
172 22
        if ($parent instanceof Permission && $child instanceof Role) {
173
            throw new InvalidParamException('Cannot add a role as a child of a permission.');
174
        }
175
176 22
        if ($this->detectLoop($parent, $child)) {
177
            throw new InvalidCallException("Cannot add '{$child->name}' as a child of '{$parent->name}'. A loop has been detected.");
178
        }
179 22
        if (isset($this->children[$parent->name][$child->name])) {
180
            throw new InvalidCallException("The item '{$parent->name}' already has a child '{$child->name}'.");
181
        }
182 22
        $this->children[$parent->name][$child->name] = $this->items[$child->name];
183 22
        $this->saveItems();
184
185 22
        return true;
186
    }
187
188
    /**
189
     * Checks whether there is a loop in the authorization item hierarchy.
190
     *
191
     * @param Item $parent parent item
192
     * @param Item $child the child item that is to be added to the hierarchy
193
     * @return boolean whether a loop exists
194
     */
195 22
    protected function detectLoop($parent, $child)
196
    {
197 22
        if ($child->name === $parent->name) {
198 1
            return true;
199
        }
200 22
        if (!isset($this->children[$child->name], $this->items[$parent->name])) {
201 22
            return false;
202
        }
203 21
        foreach ($this->children[$child->name] as $grandchild) {
204
            /* @var $grandchild Item */
205 21
            if ($this->detectLoop($parent, $grandchild)) {
206 1
                return true;
207
            }
208 21
        }
209
210 21
        return false;
211
    }
212
213
    /**
214
     * @inheritdoc
215
     */
216
    public function removeChild($parent, $child)
217
    {
218
        if (isset($this->children[$parent->name][$child->name])) {
219
            unset($this->children[$parent->name][$child->name]);
220
            $this->saveItems();
221
            return true;
222
        } else {
223
            return false;
224
        }
225
    }
226
227
    /**
228
     * @inheritdoc
229
     */
230
    public function removeChildren($parent)
231
    {
232
        if (isset($this->children[$parent->name])) {
233
            unset($this->children[$parent->name]);
234
            $this->saveItems();
235
            return true;
236
        } else {
237
            return false;
238
        }
239
    }
240
241
    /**
242
     * @inheritdoc
243
     */
244
    public function hasChild($parent, $child)
245
    {
246
        return isset($this->children[$parent->name][$child->name]);
247
    }
248
249
    /**
250
     * @inheritdoc
251
     */
252 23
    public function assign($role, $userId)
253
    {
254 23
        if (!isset($this->items[$role->name])) {
255
            throw new InvalidParamException("Unknown role '{$role->name}'.");
256 23
        } elseif (isset($this->assignments[$userId][$role->name])) {
257
            throw new InvalidParamException("Authorization item '{$role->name}' has already been assigned to user '$userId'.");
258
        } else {
259 23
            $this->assignments[$userId][$role->name] = new Assignment([
260 23
                'userId' => $userId,
261 23
                'roleName' => $role->name,
262 23
                'createdAt' => time(),
263 23
            ]);
264 23
            $this->saveAssignments();
265 23
            return $this->assignments[$userId][$role->name];
266
        }
267
    }
268
269
    /**
270
     * @inheritdoc
271
     */
272
    public function revoke($role, $userId)
273
    {
274
        if (isset($this->assignments[$userId][$role->name])) {
275
            unset($this->assignments[$userId][$role->name]);
276
            $this->saveAssignments();
277
            return true;
278
        } else {
279
            return false;
280
        }
281
    }
282
283
    /**
284
     * @inheritdoc
285
     */
286
    public function revokeAll($userId)
287
    {
288
        if (isset($this->assignments[$userId]) && is_array($this->assignments[$userId])) {
289
            foreach ($this->assignments[$userId] as $itemName => $value) {
290
                unset($this->assignments[$userId][$itemName]);
291
            }
292
            $this->saveAssignments();
293
            return true;
294
        } else {
295
            return false;
296
        }
297
    }
298
299
    /**
300
     * @inheritdoc
301
     */
302
    public function getAssignment($roleName, $userId)
303
    {
304
        return isset($this->assignments[$userId][$roleName]) ? $this->assignments[$userId][$roleName] : null;
305
    }
306
307
    /**
308
     * @inheritdoc
309
     */
310 4
    public function getItems($type)
311
    {
312 4
        $items = [];
313
314 4
        foreach ($this->items as $name => $item) {
315
            /* @var $item Item */
316 4
            if ($item->type == $type) {
317 4
                $items[$name] = $item;
318 4
            }
319 4
        }
320
321 4
        return $items;
322
    }
323
324
325
    /**
326
     * @inheritdoc
327
     */
328 2
    public function removeItem($item)
329
    {
330 2
        if (isset($this->items[$item->name])) {
331 2
            foreach ($this->children as &$children) {
332 1
                unset($children[$item->name]);
333 2
            }
334 2
            foreach ($this->assignments as &$assignments) {
335 2
                unset($assignments[$item->name]);
336 2
            }
337 2
            unset($this->items[$item->name]);
338 2
            $this->saveItems();
339 2
            $this->saveAssignments();
340 2
            return true;
341
        } else {
342
            return false;
343
        }
344
    }
345
346
    /**
347
     * @inheritdoc
348
     */
349 11
    public function getItem($name)
350
    {
351 11
        return isset($this->items[$name]) ? $this->items[$name] : null;
352
    }
353
354
    /**
355
     * @inheritdoc
356
     */
357 1
    public function updateRule($name, $rule)
358
    {
359 1
        if ($rule->name !== $name) {
360 1
            unset($this->rules[$name]);
361 1
        }
362 1
        $this->rules[$rule->name] = $rule;
363 1
        $this->saveRules();
364 1
        return true;
365
    }
366
367
    /**
368
     * @inheritdoc
369
     */
370 22
    public function getRule($name)
371
    {
372 22
        return isset($this->rules[$name]) ? $this->rules[$name] : null;
373
    }
374
375
    /**
376
     * @inheritdoc
377
     */
378 5
    public function getRules()
379
    {
380 5
        return $this->rules;
381
    }
382
383
    /**
384
     * @inheritdoc
385
     */
386 2
    public function getRolesByUser($userId)
387
    {
388 2
        $roles = [];
389 2
        foreach ($this->getAssignments($userId) as $name => $assignment) {
390 2
            $role = $this->items[$assignment->roleName];
391 2
            if ($role->type === Item::TYPE_ROLE) {
392 2
                $roles[$name] = $role;
393 2
            }
394 2
        }
395
396 2
        return $roles;
397
    }
398
399
    /**
400
     * @inheritdoc
401
     */
402 1
    public function getChildRoles($roleName)
403
    {
404 1
        $role = $this->getRole($roleName);
405
406 1
        if (is_null($role)) {
407
            throw new InvalidParamException("Role \"$roleName\" not found.");
408
        }
409
410 1
        $result = [];
411 1
        $this->getChildrenRecursive($roleName, $result);
412
413 1
        $roles = [$roleName => $role];
414
415 1
        $roles += array_filter($this->getRoles(), function (Role $roleItem) use ($result) {
416 1
            return array_key_exists($roleItem->name, $result);
417 1
        });
418
419 1
        return $roles;
420
    }
421
422
    /**
423
     * @inheritdoc
424
     */
425 1
    public function getPermissionsByRole($roleName)
426
    {
427 1
        $result = [];
428 1
        $this->getChildrenRecursive($roleName, $result);
429 1
        if (empty($result)) {
430
            return [];
431
        }
432 1
        $permissions = [];
433 1
        foreach (array_keys($result) as $itemName) {
434 1
            if (isset($this->items[$itemName]) && $this->items[$itemName] instanceof Permission) {
435 1
                $permissions[$itemName] = $this->items[$itemName];
436 1
            }
437 1
        }
438 1
        return $permissions;
439
    }
440
441
    /**
442
     * Recursively finds all children and grand children of the specified item.
443
     *
444
     * @param string $name the name of the item whose children are to be looked for.
445
     * @param array $result the children and grand children (in array keys)
446
     */
447 3
    protected function getChildrenRecursive($name, &$result)
448
    {
449 3
        if (isset($this->children[$name])) {
450 3
            foreach ($this->children[$name] as $child) {
451 3
                $result[$child->name] = true;
452 3
                $this->getChildrenRecursive($child->name, $result);
453 3
            }
454 3
        }
455 3
    }
456
457
    /**
458
     * @inheritdoc
459
     */
460 1
    public function getPermissionsByUser($userId)
461
    {
462 1
        $directPermission = $this->getDirectPermissionsByUser($userId);
463 1
        $inheritedPermission = $this->getInheritedPermissionsByUser($userId);
464
465 1
        return array_merge($directPermission, $inheritedPermission);
466
    }
467
468
    /**
469
     * Returns all permissions that are directly assigned to user.
470
     * @param string|integer $userId the user ID (see [[\yii\web\User::id]])
471
     * @return Permission[] all direct permissions that the user has. The array is indexed by the permission names.
472
     * @since 2.0.7
473
     */
474 1
    protected function getDirectPermissionsByUser($userId)
475
    {
476 1
        $permissions = [];
477 1
        foreach ($this->getAssignments($userId) as $name => $assignment) {
478 1
            $permission = $this->items[$assignment->roleName];
479 1
            if ($permission->type === Item::TYPE_PERMISSION) {
480 1
                $permissions[$name] = $permission;
481 1
            }
482 1
        }
483
484 1
        return $permissions;
485
    }
486
487
    /**
488
     * Returns all permissions that the user inherits from the roles assigned to him.
489
     * @param string|integer $userId the user ID (see [[\yii\web\User::id]])
490
     * @return Permission[] all inherited permissions that the user has. The array is indexed by the permission names.
491
     * @since 2.0.7
492
     */
493 1
    protected function getInheritedPermissionsByUser($userId)
494
    {
495 1
        $assignments = $this->getAssignments($userId);
496 1
        $result = [];
497 1
        foreach (array_keys($assignments) as $roleName) {
498 1
            $this->getChildrenRecursive($roleName, $result);
499 1
        }
500
501 1
        if (empty($result)) {
502
            return [];
503
        }
504
505 1
        $permissions = [];
506 1
        foreach (array_keys($result) as $itemName) {
507 1
            if (isset($this->items[$itemName]) && $this->items[$itemName] instanceof Permission) {
508 1
                $permissions[$itemName] = $this->items[$itemName];
509 1
            }
510 1
        }
511 1
        return $permissions;
512
    }
513
514
    /**
515
     * @inheritdoc
516
     */
517 1
    public function getChildren($name)
518
    {
519 1
        return isset($this->children[$name]) ? $this->children[$name] : [];
520
    }
521
522
    /**
523
     * @inheritdoc
524
     */
525 2
    public function removeAll()
526
    {
527 2
        $this->children = [];
528 2
        $this->items = [];
529 2
        $this->assignments = [];
530 2
        $this->rules = [];
531 2
        $this->save();
532 2
    }
533
534
    /**
535
     * @inheritdoc
536
     */
537 1
    public function removeAllPermissions()
538
    {
539 1
        $this->removeAllItems(Item::TYPE_PERMISSION);
540 1
    }
541
542
    /**
543
     * @inheritdoc
544
     */
545 1
    public function removeAllRoles()
546
    {
547 1
        $this->removeAllItems(Item::TYPE_ROLE);
548 1
    }
549
550
    /**
551
     * Removes all auth items of the specified type.
552
     * @param integer $type the auth item type (either Item::TYPE_PERMISSION or Item::TYPE_ROLE)
553
     */
554 2
    protected function removeAllItems($type)
555
    {
556 2
        $names = [];
557 2
        foreach ($this->items as $name => $item) {
558 2
            if ($item->type == $type) {
559 2
                unset($this->items[$name]);
560 2
                $names[$name] = true;
561 2
            }
562 2
        }
563 2
        if (empty($names)) {
564
            return;
565
        }
566
567 2
        foreach ($this->assignments as $i => $assignments) {
568 2
            foreach ($assignments as $n => $assignment) {
569 2
                if (isset($names[$assignment->roleName])) {
570 2
                    unset($this->assignments[$i][$n]);
571 2
                }
572 2
            }
573 2
        }
574 2
        foreach ($this->children as $name => $children) {
575 2
            if (isset($names[$name])) {
576 1
                unset($this->children[$name]);
577 1
            } else {
578 1
                foreach ($children as $childName => $item) {
579 1
                    if (isset($names[$childName])) {
580 1
                        unset($children[$childName]);
581 1
                    }
582 1
                }
583 1
                $this->children[$name] = $children;
584
            }
585 2
        }
586
587 2
        $this->saveItems();
588 2
    }
589
590
    /**
591
     * @inheritdoc
592
     */
593 1
    public function removeAllRules()
594
    {
595 1
        foreach ($this->items as $item) {
596 1
            $item->ruleName = null;
597 1
        }
598 1
        $this->rules = [];
599 1
        $this->saveRules();
600 1
    }
601
602
    /**
603
     * @inheritdoc
604
     */
605
    public function removeAllAssignments()
606
    {
607
        $this->assignments = [];
608
        $this->saveAssignments();
609
    }
610
611
    /**
612
     * @inheritdoc
613
     */
614 1
    protected function removeRule($rule)
615
    {
616 1
        if (isset($this->rules[$rule->name])) {
617 1
            unset($this->rules[$rule->name]);
618 1
            foreach ($this->items as $item) {
619 1
                if ($item->ruleName === $rule->name) {
620 1
                    $item->ruleName = null;
621 1
                }
622 1
            }
623 1
            $this->saveRules();
624 1
            return true;
625
        } else {
626
            return false;
627
        }
628
    }
629
630
    /**
631
     * @inheritdoc
632
     */
633 23
    protected function addRule($rule)
634
    {
635 23
        $this->rules[$rule->name] = $rule;
636 23
        $this->saveRules();
637 23
        return true;
638
    }
639
640
    /**
641
     * @inheritdoc
642
     */
643 6
    protected function updateItem($name, $item)
644
    {
645 6
        if ($name !== $item->name) {
646 5
            if (isset($this->items[$item->name])) {
647 1
                throw new InvalidParamException("Unable to change the item name. The name '{$item->name}' is already used by another item.");
648
            } else {
649
                // Remove old item in case of renaming
650 4
                unset($this->items[$name]);
651
652 4
                if (isset($this->children[$name])) {
653
                    $this->children[$item->name] = $this->children[$name];
654
                    unset($this->children[$name]);
655
                }
656 4
                foreach ($this->children as &$children) {
657 2
                    if (isset($children[$name])) {
658 2
                        $children[$item->name] = $children[$name];
659 2
                        unset($children[$name]);
660 2
                    }
661 4
                }
662 4
                foreach ($this->assignments as &$assignments) {
663 4
                    if (isset($assignments[$name])) {
664 2
                        $assignments[$item->name] = $assignments[$name];
665 2
                        $assignments[$item->name]->roleName = $item->name;
666 2
                        unset($assignments[$name]);
667 2
                    }
668 4
                }
669 4
                $this->saveAssignments();
670
            }
671 4
        }
672
673 5
        $this->items[$item->name] = $item;
674
675 5
        $this->saveItems();
676 5
        return true;
677
    }
678
679
    /**
680
     * @inheritdoc
681
     */
682 25
    protected function addItem($item)
683
    {
684 25
        $time = time();
685 25
        if ($item->createdAt === null) {
686 25
            $item->createdAt = $time;
687 25
        }
688 25
        if ($item->updatedAt === null) {
689 25
            $item->updatedAt = $time;
690 25
        }
691
692 25
        $this->items[$item->name] = $item;
693
694 25
        $this->saveItems();
695
696 25
        return true;
697
698
    }
699
700
    /**
701
     * Loads authorization data from persistent storage.
702
     */
703 27
    protected function load()
704
    {
705 27
        $this->children = [];
706 27
        $this->rules = [];
707 27
        $this->assignments = [];
708 27
        $this->items = [];
709
710 27
        $items = $this->loadFromFile($this->itemFile);
711 27
        $itemsMtime = @filemtime($this->itemFile);
712 27
        $assignments = $this->loadFromFile($this->assignmentFile);
713 27
        $assignmentsMtime = @filemtime($this->assignmentFile);
714 27
        $rules = $this->loadFromFile($this->ruleFile);
715
716 27
        foreach ($items as $name => $item) {
717 4
            $class = $item['type'] == Item::TYPE_PERMISSION ? Permission::className() : Role::className();
718
719 4
            $this->items[$name] = new $class([
720 4
                'name' => $name,
721 4
                'description' => isset($item['description']) ? $item['description'] : null,
722 4
                'ruleName' => isset($item['ruleName']) ? $item['ruleName'] : null,
723 4
                'data' => isset($item['data']) ? $item['data'] : null,
724 4
                'createdAt' => $itemsMtime,
725 4
                'updatedAt' => $itemsMtime,
726 4
            ]);
727 27
        }
728
729 27
        foreach ($items as $name => $item) {
730 4
            if (isset($item['children'])) {
731 4
                foreach ($item['children'] as $childName) {
732 4
                    if (isset($this->items[$childName])) {
733 4
                        $this->children[$name][$childName] = $this->items[$childName];
734 4
                    }
735 4
                }
736 4
            }
737 27
        }
738
739 27
        foreach ($assignments as $userId => $roles) {
740 4
            foreach ($roles as $role) {
741 4
                $this->assignments[$userId][$role] = new Assignment([
742 4
                    'userId' => $userId,
743 4
                    'roleName' => $role,
744 4
                    'createdAt' => $assignmentsMtime,
745 4
                ]);
746 4
            }
747 27
        }
748
749 27
        foreach ($rules as $name => $ruleData) {
750 4
            $this->rules[$name] = unserialize($ruleData);
751 27
        }
752 27
    }
753
754
    /**
755
     * Saves authorization data into persistent storage.
756
     */
757 3
    protected function save()
758
    {
759 3
        $this->saveItems();
760 3
        $this->saveAssignments();
761 3
        $this->saveRules();
762 3
    }
763
764
    /**
765
     * Loads the authorization data from a PHP script file.
766
     *
767
     * @param string $file the file path.
768
     * @return array the authorization data
769
     * @see saveToFile()
770
     */
771 27
    protected function loadFromFile($file)
772
    {
773 27
        if (is_file($file)) {
774 4
            return require($file);
775
        } else {
776 27
            return [];
777
        }
778
    }
779
780
    /**
781
     * Saves the authorization data to a PHP script file.
782
     *
783
     * @param array $data the authorization data
784
     * @param string $file the file path.
785
     * @see loadFromFile()
786
     */
787 25
    protected function saveToFile($data, $file)
788
    {
789 25
        file_put_contents($file, "<?php\nreturn " . VarDumper::export($data) . ";\n", LOCK_EX);
790 25
        $this->invalidateScriptCache($file);
791 25
    }
792
793
    /**
794
     * Invalidates precompiled script cache (such as OPCache or APC) for the given file.
795
     * @param string $file the file path.
796
     * @since 2.0.9
797
     */
798 25
    protected function invalidateScriptCache($file)
799
    {
800 25
        if (function_exists('opcache_invalidate')) {
801 25
            opcache_invalidate($file, true);
802 25
        }
803 25
        if (function_exists('apc_delete_file')) {
804
            @apc_delete_file($file);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
805
        }
806 25
    }
807
808
    /**
809
     * Saves items data into persistent storage.
810
     */
811 25
    protected function saveItems()
812
    {
813 25
        $items = [];
814 25
        foreach ($this->items as $name => $item) {
815
            /* @var $item Item */
816 25
            $items[$name] = array_filter(
817
                [
818 25
                    'type' => $item->type,
819 25
                    'description' => $item->description,
820 25
                    'ruleName' => $item->ruleName,
821 25
                    'data' => $item->data,
822
                ]
823 25
            );
824 25
            if (isset($this->children[$name])) {
825 22
                foreach ($this->children[$name] as $child) {
826
                    /* @var $child Item */
827 22
                    $items[$name]['children'][] = $child->name;
828 22
                }
829 22
            }
830 25
        }
831 25
        $this->saveToFile($items, $this->itemFile);
832 25
    }
833
834
    /**
835
     * Saves assignments data into persistent storage.
836
     */
837 23
    protected function saveAssignments()
838
    {
839 23
        $assignmentData = [];
840 23
        foreach ($this->assignments as $userId => $assignments) {
841 23
            foreach ($assignments as $name => $assignment) {
842
                /* @var $assignment Assignment */
843 23
                $assignmentData[$userId][] = $assignment->roleName;
844 23
            }
845 23
        }
846 23
        $this->saveToFile($assignmentData, $this->assignmentFile);
847 23
    }
848
849
    /**
850
     * Saves rules data into persistent storage.
851
     */
852 24
    protected function saveRules()
853
    {
854 24
        $rules = [];
855 24
        foreach ($this->rules as $name => $rule) {
856 23
            $rules[$name] = serialize($rule);
857 24
        }
858 24
        $this->saveToFile($rules, $this->ruleFile);
859 24
    }
860
861
    /**
862
     * @inheritdoc
863
     * @since 2.0.7
864
     */
865 1
    public function getUserIdsByRole($roleName)
866
    {
867 1
        $result = [];
868 1
        foreach ($this->assignments as $userID => $assignments) {
869 1
            foreach ($assignments as $userAssignment) {
870 1
                if ($userAssignment->roleName === $roleName && $userAssignment->userId == $userID) {
871 1
                    $result[] = (string)$userID;
872 1
                }
873 1
            }
874 1
        }
875 1
        return $result;
876
    }
877
}
878