Completed
Push — master ( 579af5...b29473 )
by Oleg
07:53
created

micro/auth/Rbac.php (1 issue)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php /** MicroRBAC */
2
3
namespace Micro\Auth;
4
5
use Micro\Base\IContainer;
6
use Micro\Mvc\Models\Query;
7
8
/**
9
 * Abstract RBAC class file.
10
 *
11
 * @author Oleg Lunegov <[email protected]>
12
 * @link https://github.com/lugnsk/micro
13
 * @copyright Copyright &copy; 2013 Oleg Lunegov
14
 * @license /LICENSE
15
 * @package Micro
16
 * @subpackage Auth
17
 * @version 1.0
18
 * @since 1.0
19
 */
20
abstract class Rbac
21
{
22
    const TYPE_ROLE = 0;
23
    const TYPE_PERMISSION = 1;
24
    const TYPE_OPERATION = 2;
25
26
    /** @var IContainer $container */
27
    protected $container;
28
29
30
    /**
31
     * Based constructor for RBAC rules
32
     *
33
     * @access public
34
     *
35
     * @param array $params
36
     *
37
     * @result void
38
     */
39
    public function __construct(array $params = [])
40
    {
41
        $this->container = $params['container'];
42
43 View Code Duplication
        if (!$this->container->db->tableExists('rbac_user')) {
44
            $this->container->db->createTable('rbac_user', [
45
                '`role` varchar(127) NOT NULL',
46
                '`user` int(10) unsigned NOT NULL',
47
                'UNIQUE KEY `name` (`name`,`user`)'
48
            ], 'ENGINE=MyISAM DEFAULT CHARSET=utf8');
49
        }
50
    }
51
52
    /**
53
     * Assign RBAC element into user
54
     *
55
     * @access public
56
     *
57
     * @param integer $userId user id
58
     * @param string $name element name
59
     *
60
     * @return bool
61
     */
62
    abstract public function assign($userId, $name);
63
64
    /**
65
     * Check privileges to operation
66
     *
67
     * @access public
68
     *
69
     * @param integer $userId user id
70
     * @param string $permission permission name
71
     * @param array $data action params
72
     *
73
     * @return boolean
74
     * @throws \Micro\Base\Exception
75
     */
76
    public function check($userId, $permission, array $data = [])
77
    {
78
        $tree = $this->tree($this->rawRoles());
79
80
        /** @var array $roles */
81
        $roles = $this->assigned($userId);
82
        if (!$roles) {
83
            return false;
84
        }
85
86
        foreach ($roles AS $role) {
87
88
            $actionRole = $this->searchRoleRecursive($tree, $role['name']);
89
            if ($actionRole) {
90
                /** @var array $trustRole */
91
                $trustRole = $this->searchRoleRecursive($actionRole, $permission);
0 ignored issues
show
It seems like $actionRole defined by $this->searchRoleRecursive($tree, $role['name']) on line 88 can also be of type boolean; however, Micro\Auth\Rbac::searchRoleRecursive() does only seem to accept array, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
92
                if ($trustRole) {
93
                    return $this->execute($trustRole[$permission], $data);
94
                }
95
            }
96
        }
97
98
        return false;
99
    }
100
101
    /**
102
     * Build tree from RBAC rules
103
     *
104
     * @access public
105
     *
106
     * @param array $elements elements array
107
     * @param string $parentId parent ID
108
     *
109
     * @return array
110
     */
111
    public function tree(&$elements, $parentId = '0')
112
    {
113
        $branch = [];
114
        foreach ($elements AS $key => $element) {
115
            if ($element['based'] === (string)$parentId) {
116
                $children = $this->tree($elements, $element['name']);
117
                if ($children) {
118
                    $element['childs'] = $children;
119
                }
120
                $branch[$element['name']] = $element;
121
                unset($elements[$key]);
122
            }
123
        }
124
125
        return $branch;
126
    }
127
128
    /**
129
     * Get raw roles
130
     *
131
     * @access public
132
     * @return mixed
133
     */
134
    abstract public function rawRoles();
135
136
    /**
137
     * Get assigned to user RBAC elements
138
     *
139
     * @access public
140
     *
141
     * @param integer $userId user ID
142
     *
143
     * @return mixed
144
     * @throws \Micro\Base\Exception
145
     */
146 View Code Duplication
    public function assigned($userId)
147
    {
148
        $query = new Query($this->container->db);
149
        $query->distinct = true;
150
        $query->select = '`role` AS `name`';
151
        $query->table = '`rbac_user`';
152
        $query->addWhere('`user`=' . $userId);
153
        $query->single = false;
154
155
        return $query->run(\PDO::FETCH_ASSOC);
156
    }
157
158
    /**
159
     * Recursive search in roles array
160
     *
161
     * @access public
162
     *
163
     * @param array $roles elements
164
     * @param string $finder element name to search
165
     *
166
     * @return bool|array
167
     */
168
    protected function searchRoleRecursive($roles, $finder)
169
    {
170
        $result = false;
171
        foreach ($roles AS $id => $role) {
172
            if ($id === $finder) {
173
                $result = [$id => $role];
174
                break;
175
            } else {
176
                if (!empty($role['childs'])) {
177
                    $result = $this->searchRoleRecursive($role['childs'], $finder);
178
                    break;
179
                }
180
            }
181
        }
182
183
        return $result;
184
    }
185
186
    /**
187
     * Execute rule
188
     *
189
     * @access public
190
     *
191
     * @param array $role element
192
     * @param array $data action params
193
     *
194
     * @return bool
195
     */
196
    public function execute(array $role, array $data)
197
    {
198
        if (!$role['data']) {
199
            return true;
200
        } else {
201
            extract($data);
202
203
            return eval('return ' . $role['data']);
204
        }
205
    }
206
207
    /**
208
     * Revoke RBAC element from user
209
     *
210
     * @access public
211
     *
212
     * @param integer $userId user id
213
     * @param string $name element name
214
     *
215
     * @return bool
216
     */
217
    public function revoke($userId, $name)
218
    {
219
        return $this->container->db->delete('rbac_user', 'name=:name AND user=:user',
220
            ['name' => $name, 'user' => $userId]);
221
    }
222
}
223