This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | |||
3 | namespace BootPress\Auth; |
||
4 | |||
5 | use BootPress\Page\Component as Page; |
||
6 | use BootPress\SQLite\Component as SQLite; |
||
7 | use Symfony\Component\Yaml\Yaml; |
||
8 | |||
9 | /* |
||
10 | http://stackoverflow.com/questions/549/the-definitive-guide-to-form-based-website-authentication#477579 |
||
11 | http://stackoverflow.com/questions/244882/what-is-the-best-way-to-implement-remember-me-for-a-website?lq=1 |
||
12 | http://security.stackexchange.com/questions/63435/why-use-an-authentication-token-instead-of-the-username-password-per-request/63438#63438 |
||
13 | - Store token hash (a weak one is fine) in database, and original in cookie |
||
14 | https://paragonie.com/blog/2015/04/secure-authentication-php-with-long-term-persistence |
||
15 | - Query database on a unique id (and not the token) for speed, and to thwart a timing attack |
||
16 | Charles Miller - http://fishbowl.pastiche.org/2004/01/19/persistent_login_cookie_best_practice/) |
||
17 | - Change token with each new session to give attacker a smaller window of opportunity to exploit a stolen cookie |
||
18 | - If an id (username) and token do not match, then remove all of the users persistent logins |
||
19 | - Do not allow access to sensitive actions on a cookie-based login, but only through typing a valid password |
||
20 | Barry Jaspan - http://jaspan.com/improved_persistent_login_cookie_best_practice) |
||
21 | - If attacker steals cookie, he becomes the legitimate user (with an updated token), whilst the victim must login again |
||
22 | - Deleting all sessions for a user submitting an invalid token (only) makes it too easy for an attacker to log everyone out |
||
23 | - If a series (constant) token is submitted with an invalid (variable) token, then a theft has occurred |
||
24 | - If anything is missing from the cookie, then just ignore it |
||
25 | http://security.stackexchange.com/questions/19676/token-based-authentication-securing-the-token#19677 |
||
26 | - In the Barry Jaspan improved plan, an attacker can fly under the radar if they delete the original cookie |
||
27 | */ |
||
28 | |||
29 | class Component |
||
30 | { |
||
31 | |||
32 | /** @var object This property gives you access to the SQLite3 (or custom) users database. */ |
||
33 | public $db; |
||
34 | |||
35 | /** @var object BootPress\Page\Component instance. */ |
||
36 | private $page; |
||
37 | |||
38 | /** @var null|string The HTTP Authenticated username or null. */ |
||
39 | private $basic; |
||
40 | |||
41 | /** @var array Password hashing options. */ |
||
42 | private $password; |
||
43 | |||
44 | /** $var array Information we user to sanity check with a cookie. Has '**id**', '**series**', '**token**', '**time**', and '**user_agent**' keys. */ |
||
45 | private $session = array(); |
||
46 | |||
47 | /** var array Stored information about a logged in user. Has '**id**', '**name**', '**email**', '**admin**', and '**login**' keys. */ |
||
48 | private $user = array(); |
||
49 | |||
50 | /** |
||
51 | * Establishes the authentication settings, and runs all of our security checks. Authentication is either session-based, or via HTTP Basic Auth. Session-based authentication relies on the user database. HTTP Basic Auth can use either the database, an array, or a YAML file of usernames and passwords. A user can be both HTTP and session authenticated as long as Basic Auth is not using the database. This allows an administrator to be logged in as a regular user, yet still retain super admin privileges. |
||
52 | * |
||
53 | * @param array $options Allows you to customize the authorization settings. You can set the: |
||
54 | * |
||
55 | * - '**db**' - A custom BootPress\Database\Component instance. The default is an SQLite Users.db we will automatically create. |
||
56 | * - '**basic**' - Either ``null`` (the default) to use the users database, an ``array('username'=>'password', ...)`` of users, or a YAML file of username's and password's. |
||
57 | * - '**password**' - '**algo**' and '**options**' for hashing passwords. |
||
58 | */ |
||
59 | 9 | public function __construct(array $options = array()) { |
|
60 | 9 | extract(array_merge(array( |
|
0 ignored issues
–
show
Bug
introduced
by
![]() |
|||
61 | 9 | 'db' => null, |
|
62 | 9 | 'basic' => null, |
|
63 | 9 | 'password' => array(), |
|
64 | 9 | ), $options)); |
|
65 | 9 | $this->password = array_merge(array( |
|
66 | 9 | 'algo' => \PASSWORD_DEFAULT, |
|
67 | 9 | 'options' => array(), |
|
68 | 9 | ), (array) $password); |
|
69 | 9 | $this->page = Page::html(); |
|
70 | 9 | $this->db = ($db instanceof \BootPress\Database\Component) ? $db : null; |
|
71 | 9 | if (is_null($this->db)) { |
|
72 | 9 | $this->db = new SQLite($this->page->dir['page'].'Users.db'); |
|
73 | 9 | if ($this->db->created) { |
|
74 | 1 | $this->db->create('user_group_names', array( |
|
75 | 1 | 'id' => 'INTEGER PRIMARY KEY', |
|
76 | 1 | 'name' => 'TEXT UNIQUE COLLATE NOCASE', |
|
77 | 1 | )); |
|
78 | 1 | $this->db->create('user_groups', array( |
|
79 | 1 | 'user_id' => 'INTEGER NOT NULL DEFAULT 0', |
|
80 | 1 | 'group_id' => 'INTEGER NOT NULL DEFAULT 0', |
|
81 | 1 | ), array('unique' => 'user_id, group_id')); |
|
82 | 1 | $this->db->create('user_sessions', array( |
|
83 | 1 | 'id' => 'INTEGER PRIMARY KEY', |
|
84 | 1 | 'user_id' => 'INTEGER NOT NULL DEFAULT 0', |
|
85 | 1 | 'adjourn' => 'INTEGER NOT NULL DEFAULT 0', // 'last_activity' + 'relapse' |
|
86 | 1 | 'relapse' => 'INTEGER NOT NULL DEFAULT 0', // unsigned integer |
|
87 | 1 | 'last_activity' => 'INTEGER NOT NULL DEFAULT 0', // time() |
|
88 | 1 | 'ip_address' => 'TEXT NOT NULL DEFAULT ""', // of last updated session |
|
89 | 1 | 'user_agent' => 'TEXT NOT NULL DEFAULT ""', // up to 255 varchar constant |
|
90 | 1 | 'series' => 'TEXT NOT NULL DEFAULT ""', // sha1(salt) constant |
|
91 | 1 | 'token' => 'TEXT NOT NULL DEFAULT ""', // sha1(salt) updated |
|
92 | 1 | 'login' => 'TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP', // original date('Y-m-d H:i:s') |
|
93 | 1 | ), 'user_id, adjourn'); |
|
0 ignored issues
–
show
'user_id, adjourn' is of type string , but the function expects a array .
It seems like the type of the argument is not accepted by the function/method which you are calling. In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug. We suggest to add an explicit type cast like in the following example: function acceptsInteger($int) { }
$x = '123'; // string "123"
// Instead of
acceptsInteger($x);
// we recommend to use
acceptsInteger((integer) $x);
![]() |
|||
94 | 1 | $this->db->create('users', array( |
|
95 | 1 | 'id' => 'INTEGER PRIMARY KEY', |
|
96 | 1 | 'name' => 'TEXT NOT NULL DEFAULT ""', |
|
97 | 1 | 'email' => 'TEXT UNIQUE COLLATE NOCASE', |
|
98 | 1 | 'admin' => 'INTEGER NOT NULL DEFAULT 0', // unsigned integer |
|
99 | 1 | 'password' => 'TEXT NOT NULL DEFAULT ""', // up to 255 varchar hash |
|
100 | 1 | 'approved' => 'TEXT NOT NULL DEFAULT "Y"', // 'Y' or 'N' char |
|
101 | 1 | 'registered' => 'TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP', // date('Y-m-d H:i:s') |
|
102 | 1 | 'last_activity' => 'INTEGER NOT NULL DEFAULT 0', // time() |
|
103 | 1 | )); |
|
104 | 1 | } |
|
105 | 9 | } |
|
106 | 9 | $username = $this->page->request->getUser(); |
|
107 | 9 | $password = $this->page->request->getPassword(); |
|
108 | 9 | if (!empty($username) && !empty($password)) { |
|
109 | 1 | if (is_null($basic)) { // use the user database (default) |
|
110 | 1 | if ($user_id = $this->check($username, $password, 'approved = "Y"')) { |
|
111 | 1 | $this->user = $this->db->row('SELECT id, name, email, admin FROM users WHERE id = ?', $user_id, 'assoc'); |
|
112 | 1 | $this->user['login'] = 0; |
|
113 | 1 | } |
|
114 | 1 | } elseif (is_array($basic)) { // an array of users |
|
115 | 1 | if (isset($basic[$username]) && $password == $basic[$username]) { |
|
116 | 1 | $this->basic = $username; |
|
117 | 1 | } |
|
118 | 1 | } elseif (substr($basic, -4) == '.yml' && is_file($basic)) { // a YAML file of users |
|
119 | 1 | $users = array(); |
|
120 | 1 | $current = (array) Yaml::parse(file_get_contents($basic)); |
|
121 | 1 | foreach ($current as $name => $pw) { |
|
122 | 1 | if (!is_numeric($name) && !empty($name) && !empty($pw)) { |
|
123 | 1 | $users[$name] = (substr($pw, 0, 4) == '$2y$') ? $pw : password_hash($pw, $this->password['algo'], $this->password['options']); |
|
124 | 1 | } |
|
125 | 1 | } |
|
126 | 1 | if (isset($users[$username]) && password_verify($password, $users[$username])) { |
|
127 | 1 | if (password_needs_rehash($users[$username], $this->password['algo'], $this->password['options'])) { |
|
128 | 1 | $users[$username] = password_hash($password, $this->password['algo'], $this->password['options']); |
|
129 | 1 | } |
|
130 | 1 | $this->basic = $username; |
|
131 | 1 | } |
|
132 | 1 | if ($users != $current) { |
|
133 | 1 | file_put_contents($basic, Yaml::dump($users)); |
|
134 | 1 | } |
|
135 | 1 | } |
|
136 | |||
137 | 1 | return; // HTTP Basic Authentication takes precedence |
|
138 | } |
||
139 | 8 | $user = false; |
|
0 ignored issues
–
show
$user is not used, you could remove the assignment.
This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently. $myVar = 'Value';
$higher = false;
if (rand(1, 6) > 3) {
$higher = true;
} else {
$higher = false;
}
Both the ![]() |
|||
140 | 8 | $session = $this->page->session->get('bootpress/cookie'); // vs. bootpress/verified |
|
141 | 8 | if ($cookie = $this->page->request->cookies->get('bootpress')) { |
|
142 | 5 | $cookie = base64_decode($cookie); |
|
143 | 5 | } |
|
144 | 8 | if ($session && $session != $cookie) { // These two must match if they both exist |
|
145 | // We set the $session so we know that's good, but ... |
||
146 | // if $session doesn't equal $cookie then it has been compromised |
||
147 | // if $session and no $cookie, then it's assumed to have been stolen and deleted |
||
148 | 3 | $this->logout($this->db->value('SELECT user_id FROM user_sessions WHERE id = ?', strstr($session.' ', ' ', true))); |
|
149 | |||
150 | 3 | return $this->setCookie(); |
|
0 ignored issues
–
show
|
|||
151 | } |
||
152 | 6 | if ($cookie) { // We can have a $cookie and no $session (just log them in again) |
|
153 | 3 | list($id, $series, $token) = explode(' ', $cookie.' '); |
|
154 | 3 | if (!$user = $this->db->row(array( |
|
155 | 3 | 'SELECT u.id, u.name, u.email, u.admin, strftime("%s", s.login) AS login, s.user_agent, s.last_activity, s.relapse, s.adjourn, s.token, u.approved', |
|
156 | 3 | 'FROM user_sessions AS s', |
|
157 | 3 | 'INNER JOIN users AS u ON s.user_id = u.id', |
|
158 | 3 | 'WHERE s.id = ? AND s.series = ?', |
|
159 | 3 | ), array($id, sha1($series)), 'assoc')) { |
|
160 | 1 | return $this->setCookie(); // ie. unset the cookie - it is defective, but not necessarily malicious |
|
0 ignored issues
–
show
|
|||
161 | } |
||
162 | $session = array( |
||
163 | 3 | 'id' => $id, |
|
164 | 3 | 'series' => $series, |
|
165 | 3 | 'token' => $token, |
|
166 | 3 | 'time' => time(), |
|
167 | 3 | 'user_agent' => trim(substr($this->page->request->headers->get('User-Agent'), 0, 255)), |
|
168 | 3 | ); |
|
169 | 3 | if ($user['user_agent'] != $session['user_agent'] || |
|
170 | 3 | $user['token'] != sha1($session['token']) || |
|
171 | 1 | $user['adjourn'] <= $session['time'] || |
|
172 | 3 | $user['approved'] != 'Y') { |
|
173 | // Something we take seriously has been changed |
||
174 | 3 | $this->logout($user['id']); |
|
175 | |||
176 | 3 | return $this->setCookie(); |
|
0 ignored issues
–
show
|
|||
177 | } |
||
178 | // Update records every 5 minutes |
||
179 | 1 | if (($user['last_activity'] + 300) <= $session['time'] && !$this->page->request->isXmlHttpRequest()) { |
|
180 | 1 | $session['token'] = $this->salt(); |
|
181 | 1 | $this->db->update('user_sessions', 'id', array($session['id'] => array( |
|
182 | 1 | 'ip_address' => $this->page->request->getClientIp(), |
|
183 | 1 | 'last_activity' => $session['time'], |
|
184 | 1 | 'adjourn' => $session['time'] + $user['relapse'], |
|
185 | 1 | 'token' => sha1($session['token']), |
|
186 | 1 | ))); |
|
187 | 1 | $this->db->update('users', 'id', array($user['id'] => array('last_activity' => $session['time']))); |
|
188 | 1 | $this->setCookie(implode(' ', array($session['id'], $session['series'], $session['token'])), $user['relapse']); |
|
189 | 1 | } |
|
190 | 1 | $this->session = $session; // 'id', 'series', 'token', 'time', 'user_agent' |
|
191 | 1 | $this->user = array_slice($user, 0, 5, true); // 'id', 'name', 'email', 'admin', 'login' |
|
192 | 1 | $this->user['login'] = time() - $this->user['login']; |
|
193 | 1 | } |
|
194 | 4 | } |
|
195 | |||
196 | /** |
||
197 | * @return null|string The basic username if HTTP authenticated, or null if not. |
||
198 | */ |
||
199 | 1 | public function http() |
|
200 | { |
||
201 | 1 | return $this->basic; |
|
202 | } |
||
203 | |||
204 | /** |
||
205 | * HTTP Authenticate a user for current directory and all subdirectories whether they are signed in or not. |
||
206 | * |
||
207 | * @param string $name Identifies the set of resources to which the username and password will apply. |
||
208 | * |
||
209 | * @see http://stackoverflow.com/questions/12701085/what-is-the-realm-in-basic-authentication |
||
210 | * |
||
211 | * ```php |
||
212 | * if (!$auth->http()) { |
||
213 | * $auth->realm('Website'); |
||
214 | * } |
||
215 | * ``` |
||
216 | */ |
||
217 | 1 | public function realm($name, $message = null) |
|
218 | { |
||
219 | 1 | $content = $message ?: '<h1>401 Unauthorized</h1><p>Access Denied</p>'; |
|
220 | 1 | $this->page->send($content, 401, array( |
|
221 | 1 | 'WWW-Authenticate' => 'Basic realm="'.htmlspecialchars($name).'"', |
|
222 | 1 | )); |
|
223 | 1 | } |
|
224 | |||
225 | /** |
||
226 | * Retrieve some information about the signed in user. |
||
227 | * |
||
228 | * @param string $param Can be any of the following: |
||
229 | * - '**id**' - From the database's user table. |
||
230 | * - '**name**' - Of the user. |
||
231 | * - '**email**' - Of the user. |
||
232 | * - '**admin**' level - The default is 0 meaning they have no admin privileges. |
||
233 | * - '**login**' - The number of seconds ago that they actually signed in with a username and password for the current session. If using HTTP Basic Authentication, this will always be 0. |
||
234 | * |
||
235 | * @return array|string|null An array if you don't set $param, a string if the user is logged in and the $param exists, or null if not. |
||
236 | * |
||
237 | * ```php |
||
238 | * echo 'Hello '.$auth->user('name'); |
||
239 | * ``` |
||
240 | */ |
||
241 | 7 | public function user($param = null) |
|
242 | { |
||
243 | 7 | if (is_null($param)) { |
|
244 | 1 | return $this->user; |
|
245 | } |
||
246 | |||
247 | 7 | return (isset($this->user[$param])) ? $this->user[$param] : null; |
|
248 | } |
||
249 | |||
250 | /** |
||
251 | * Gives you the following information about your user(s): |
||
252 | * |
||
253 | * - '**id**' |
||
254 | * - '**name**' |
||
255 | * - '**email**' |
||
256 | * - '**admin**' - Integer. |
||
257 | * - '**approved**' - Y (yes) or N (no). |
||
258 | * - '**registered**' - A GMT timestamp. |
||
259 | * - '**last_activity**' - A GMT timestamp (updated at 5 minute intervals) or 0 if we don't know. |
||
260 | * - A '**groups**' ``array($group, ...)`` of groups they are in. |
||
261 | * |
||
262 | * @param int|int[] $user_id An integer, or an ``array($user_id, ...)``` of users you would like to return information for. |
||
263 | * |
||
264 | * @return array An associative array of information about your user(s). If $user_id is an array, then this will be a multidimensional ``array($user_id => $info, ...)``` for every user in the order given. If there was no record found for a given $user_id, then it will be an empty array. |
||
265 | */ |
||
266 | 2 | public function info($user_id) |
|
267 | { |
||
268 | 2 | $single = (is_array($user_id)) ? false : true; |
|
269 | 2 | $ids = ($single) ? array($user_id) : $user_id; |
|
270 | 2 | $users = array(); |
|
271 | 2 | foreach ($ids as $id) { |
|
0 ignored issues
–
show
The expression
$ids of type array|integer is not guaranteed to be traversable. How about adding an additional type check?
There are different options of fixing this problem.
![]() |
|||
272 | 2 | $users[$id] = array(); |
|
273 | 2 | } |
|
274 | 2 | $groups = $this->getUsersGroups($ids); |
|
0 ignored issues
–
show
It seems like
$ids defined by $single ? array($user_id) : $user_id on line 269 can also be of type array ; however, BootPress\Auth\Component::getUsersGroups() does only seem to accept integer , 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. ![]() |
|||
275 | 2 | foreach ($this->db->all('SELECT * FROM users WHERE id IN('.implode(', ', $ids).')', '', 'assoc') as $row) { |
|
276 | 2 | unset($row['password']); |
|
277 | 2 | $users[$row['id']] = $row; |
|
278 | 2 | $users[$row['id']]['registered'] = strtotime($row['registered']); |
|
279 | 2 | $users[$row['id']]['groups'] = $groups[$row['id']]; |
|
280 | 2 | } |
|
281 | |||
282 | 2 | return ($single) ? array_shift($users) : $users; |
|
283 | } |
||
284 | |||
285 | /** |
||
286 | * This takes the submitted parameters and check to see if they exist in the users database. |
||
287 | * |
||
288 | * @param string $email This is the only required argument. If you stop here then we are only checking to see if the email already exists. |
||
289 | * @param string $password The submitted password to check if the user is who they are claiming to be. Encryption is handled in vitro. |
||
290 | * @param string $and Additional qualifier's to check against. |
||
291 | * |
||
292 | * @return int|false (bool) false if the record does not exist, or the id (integer) of the user if we have a match. |
||
293 | * |
||
294 | * ```php |
||
295 | * if ($user_id = $auth->check('[email protected]', 'password', 'approved = "Y"')) { |
||
296 | * // Then you may proceed with $user_id |
||
297 | * } |
||
298 | * ``` |
||
299 | */ |
||
300 | 5 | public function check($email, $password = null, $and = null) |
|
0 ignored issues
–
show
|
|||
301 | { |
||
302 | 5 | $check = func_get_args(); |
|
303 | 5 | $email = array_shift($check); |
|
304 | 5 | if (empty($check)) { |
|
305 | 2 | return $this->db->value('SELECT id FROM users WHERE email = ?', $email); |
|
306 | } |
||
307 | 4 | $password = array_shift($check); |
|
308 | 4 | $and = (!empty($check)) ? ' AND '.array_shift($check) : ''; |
|
309 | 4 | if ($user = $this->db->row('SELECT id, password AS hash FROM users WHERE email = ?'.$and, $email, 'assoc')) { |
|
310 | 4 | if (password_verify($password, $user['hash'])) { |
|
311 | 4 | if (password_needs_rehash($user['hash'], $this->password['algo'], $this->password['options'])) { |
|
312 | 2 | $this->db->update('users', 'id', array($user['id'] => array( |
|
313 | 2 | 'password' => password_hash($password, $this->password['algo'], $this->password['options']), |
|
314 | 2 | ))); |
|
315 | 2 | } |
|
316 | 4 | $this->page->session->set('bootpress/verified', $user['id']); |
|
317 | |||
318 | 4 | return $user['id']; |
|
319 | } |
||
320 | 1 | } |
|
321 | |||
322 | 1 | return false; |
|
323 | } |
||
324 | |||
325 | /** |
||
326 | * Verifies whether or not an email address looks valid. |
||
327 | * |
||
328 | * @param string $address The email you would like to verify the looks of. |
||
329 | * |
||
330 | * @return bool True or False. Whether the $address looks like a real email or not. |
||
331 | * |
||
332 | * ```php |
||
333 | * if ($auth->isEmail('[email protected]')) { |
||
334 | * // Then you may proceed |
||
335 | * } |
||
336 | * ``` |
||
337 | */ |
||
338 | 1 | public function isEmail($address) |
|
339 | { |
||
340 | 1 | return (bool) preg_match('/^[a-zA-Z0-9.!#$%&\'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/', $address); |
|
341 | } |
||
342 | |||
343 | /** |
||
344 | * This creates a random password that you can suggest to a user, or use to reset and email them the new password, or to just create a random alpha-numeric string for yourself. |
||
345 | * |
||
346 | * @param int $length The desired length of your password |
||
347 | * |
||
348 | * @return string The random password. |
||
349 | */ |
||
350 | 1 | public function randomPassword($length = 8) |
|
351 | { |
||
352 | 1 | $password = ''; |
|
353 | 1 | for ($i = 0; $i < $length; ++$i) { |
|
354 | 1 | switch (mt_rand(0, 2)) { |
|
355 | 1 | case 0: |
|
356 | 1 | $password .= mt_rand(0, 9); |
|
357 | 1 | break; // 0-9 |
|
358 | 1 | case 1: |
|
359 | 1 | $password .= chr(mt_rand(65, 90)); |
|
360 | 1 | break; // A-Z |
|
361 | 1 | case 2: |
|
362 | 1 | $password .= chr(mt_rand(97, 122)); |
|
363 | 1 | break; // a-z |
|
364 | 1 | } |
|
365 | 1 | } |
|
366 | |||
367 | 1 | return $password; |
|
368 | } |
||
369 | |||
370 | /** |
||
371 | * This will ensure that a user is registered at the site. If you get someone registering twice for whatever reason, then this will make sure they are in, and you can advise them whether or not they already hold an account with you. If they are not a $new_user, then the name and password will not be saved (the email of course will remain the same). You don't want somebody registering themselves access into someone else's account. |
||
372 | * |
||
373 | * @param string $name The user's name. |
||
374 | * @param string $email The user's email. |
||
375 | * @param string $password The user's password. Do not encrypt! We do that for you. |
||
376 | * |
||
377 | * @return array An ``array((bool) $new_user, (int) $user_id)`` where $new_user is either true or false, and $user_id is either the new or the old id depending. |
||
378 | * |
||
379 | * ```php |
||
380 | * list($new_user, $user_id) = $auth->register('Joe Blow', '[email protected]', 'sekrit'); |
||
381 | * ``` |
||
382 | */ |
||
383 | 1 | public function register($name, $email, $password) |
|
384 | { |
||
385 | 1 | $new_user = ($user_id = $this->check($email)) ? false : true; |
|
386 | 1 | if ($new_user) { |
|
387 | 1 | $user_id = $this->db->insert('users', array( |
|
388 | 1 | 'name' => $name, |
|
389 | 1 | 'email' => $email, |
|
390 | 1 | 'password' => password_hash($password, $this->password['algo'], $this->password['options']), |
|
391 | 1 | 'admin' => 0, |
|
392 | 1 | 'approved' => 'Y', |
|
393 | 1 | 'registered' => date('Y-m-d H:i:s'), |
|
394 | 1 | 'last_activity' => 0, |
|
395 | 1 | )); |
|
396 | 1 | } |
|
397 | |||
398 | 1 | return array($new_user, $user_id); |
|
399 | } |
||
400 | |||
401 | /** |
||
402 | * Allows you to update a users account. |
||
403 | * |
||
404 | * @param int $user_id The id of the user you would like to update. |
||
405 | * @param array $user An associative array of fields you would like to update. The available fields are: |
||
406 | * |
||
407 | * - '**name**' => The users name. |
||
408 | * - '**email**' => The users email. If you are changing this, then make sure it is not already in use beforehand. |
||
409 | * - '**password**' => The new password. No encryption needed. |
||
410 | * - '**admin**' => An integer >= 0. |
||
411 | * - '**approved**' => '**Y**' (yes) or '**N**' (no). If you set this to '**N**' (no), they will be logged out immediately wherever they may be. |
||
412 | * - '**registered**' => |
||
413 | * - '**last_activity**' => |
||
414 | * |
||
415 | * ... and any other fields that may exist if you have customized the database to suit your needs. |
||
416 | * |
||
417 | * ```php |
||
418 | * if ($auth->update($user_id, array( |
||
419 | * 'approved' => 'N', // This will log them out and prevent them from ever signing in again. |
||
420 | * )); |
||
421 | * ``` |
||
422 | */ |
||
423 | 1 | public function update($user_id, array $user = array()) |
|
424 | { |
||
425 | 1 | $update = array(); |
|
426 | 1 | foreach ($user as $key => $value) { |
|
427 | switch ($key) { |
||
428 | 1 | case 'name': |
|
429 | 1 | $update[$key] = $value; |
|
430 | 1 | break; |
|
431 | 1 | case 'email': |
|
432 | 1 | if ($this->isEmail($value)) { |
|
433 | 1 | $update[$key] = $value; |
|
434 | 1 | } |
|
435 | 1 | break; |
|
436 | 1 | case 'password': |
|
437 | 1 | if (!empty($value)) { |
|
438 | 1 | $update[$key] = password_hash($value, $this->password['algo'], $this->password['options']); |
|
439 | 1 | } |
|
440 | 1 | break; |
|
441 | 1 | case 'admin': |
|
442 | 1 | $update[$key] = (is_numeric($value) && $value > 0) ? (int) $value : 0; |
|
443 | 1 | break; |
|
444 | 1 | case 'approved': |
|
445 | 1 | $update[$key] = (empty($value) || strtoupper($value) == 'N') ? 'N' : 'Y'; |
|
446 | 1 | break; |
|
447 | 1 | case 'registered': |
|
448 | 1 | if (is_numeric($value)) { |
|
449 | 1 | $update[$key] = date('Y-m-d H:i:s', (int) $value); |
|
450 | 1 | } |
|
451 | 1 | break; |
|
452 | 1 | case 'last_activity': |
|
453 | 1 | if (is_numeric($value)) { |
|
454 | 1 | $update[$key] = (int) $value; |
|
455 | 1 | } |
|
456 | 1 | break; |
|
457 | 1 | default: |
|
458 | 1 | $update[$key] = $value; |
|
459 | 1 | break; |
|
460 | 1 | } |
|
461 | 1 | } |
|
462 | 1 | if (!empty($update)) { |
|
463 | 1 | $this->db->update('users', 'id', array($user_id => $update)); |
|
464 | 1 | if ($this->isUser($user_id)) { |
|
465 | 1 | foreach (array('name', 'email', 'admin') as $value) { |
|
466 | 1 | if (isset($update[$value])) { |
|
467 | 1 | $this->user[$value] = $update[$value]; |
|
468 | 1 | } |
|
469 | 1 | } |
|
470 | 1 | } |
|
471 | 1 | if (isset($update['approved']) && $update['approved'] == 'N') { |
|
472 | 1 | $this->logout($user_id); |
|
473 | 1 | } |
|
474 | 1 | } |
|
475 | 1 | } |
|
476 | |||
477 | /** |
||
478 | * This will login a user to your site for a specified amount of time (of inactivity), and optionally log them out everywhere else. Session and cookie based. |
||
479 | * |
||
480 | * @param integer $user_id Of the user you want to login. |
||
481 | * @param integer $expires The number of days (if less than or equal to 730) or seconds (if greater than 730) of inactivity after which you would like to require the user to sign back into your site. |
||
482 | * @param false|mixed $single If you set this to true (or to anything besides false), then they will be logged out of every other session that may be currently active. Meaning if you sign in on a public computer, then realize you forgot to sign out, you can sign in again on any other computer and be signed out from all previous sessions if you use this feature. |
||
483 | * |
||
484 | * ```php |
||
485 | * $auth->login($user_id, 30, 'single'); // Sign in $user_id for 30 days here, and log them out everywhere else. |
||
486 | * ``` |
||
487 | */ |
||
488 | 4 | public function login($user_id, $expires = 7200, $single = false) |
|
489 | { |
||
490 | 4 | if (empty($user_id)) { |
|
491 | 1 | return; |
|
492 | } |
||
493 | 4 | $this->logout(($single !== false) ? $user_id : null); |
|
494 | 4 | if ($user = $this->db->row('SELECT id, name, email, admin FROM users WHERE id = ? AND approved = ?', array($user_id, 'Y'), 'assoc')) { |
|
495 | 4 | $this->session = array( |
|
496 | 4 | 'id' => '', |
|
497 | 4 | 'series' => $this->salt(), |
|
498 | 4 | 'token' => $this->salt(), |
|
499 | 4 | 'time' => time(), |
|
500 | 4 | 'user_agent' => trim(substr($this->page->request->headers->get('User-Agent'), 0, 255)), |
|
501 | ); |
||
502 | 4 | $relapse = ($expires <= 730) ? $expires * 24 * 60 * 60 : $expires; |
|
503 | 4 | $this->session['id'] = $this->db->insert('user_sessions', array( |
|
504 | 4 | 'user_id' => $user['id'], |
|
505 | 4 | 'adjourn' => $this->session['time'] + $relapse, |
|
506 | 4 | 'relapse' => $relapse, |
|
507 | 4 | 'last_activity' => $this->session['time'], |
|
508 | 4 | 'ip_address' => $this->page->request->getClientIp(), |
|
509 | 4 | 'user_agent' => $this->session['user_agent'], |
|
510 | 4 | 'series' => sha1($this->session['series']), |
|
511 | 4 | 'token' => sha1($this->session['token']), |
|
512 | 4 | 'login' => date('Y-m-d H:i:s', $this->session['time']), |
|
513 | 4 | )); |
|
514 | 4 | $this->db->update('users', 'id', array($user['id'] => array('last_activity' => $this->session['time']))); |
|
515 | 4 | $this->setCookie(implode(' ', array($this->session['id'], $this->session['series'], $this->session['token'])), $relapse); |
|
516 | 4 | $this->user = $user; |
|
517 | 4 | } |
|
518 | 4 | } |
|
519 | |||
520 | /** |
||
521 | * This will log a session authenticated user out of your site. |
||
522 | * |
||
523 | * @param integer $user_id If this is an integer, then $user_id will be logged out of all their sessions, everywhere. If null (or not given), then the current user will be logged out of the current session. |
||
524 | * |
||
525 | * ```php |
||
526 | * $auth->logout(); // Log out the current user. |
||
527 | * ``` |
||
528 | */ |
||
529 | 6 | public function logout($user_id = null) |
|
530 | { |
||
531 | 6 | if ($user_id) { |
|
0 ignored issues
–
show
The expression
$user_id of type integer|null is loosely compared to true ; this is ambiguous if the integer can be zero. You might want to explicitly use !== null instead.
In PHP, under loose comparison (like For 0 == false // true
0 == null // true
123 == false // false
123 == null // false
// It is often better to use strict comparison
0 === false // false
0 === null // false
![]() |
|||
532 | 5 | $this->db->exec('DELETE FROM user_sessions WHERE user_id = ? AND adjourn <= ?', array($user_id, time())); |
|
533 | 5 | if ($user_id == $this->isUser()) { |
|
534 | 1 | $this->logout(); |
|
535 | 1 | } |
|
536 | 6 | } elseif (isset($this->session['id'])) { |
|
537 | 2 | $this->setCookie(); |
|
538 | 2 | $this->db->exec('DELETE FROM user_sessions WHERE id = ? AND adjourn <= ?', array($this->session['id'], time())); |
|
539 | 2 | $this->session = array(); |
|
540 | 2 | $this->user = array(); |
|
541 | 2 | } |
|
542 | 6 | } |
|
543 | |||
544 | /** |
||
545 | * Get the number of active, session authenticated users at your site within the $duration given. |
||
546 | * |
||
547 | * @param integer $duration How far back (in seconds) you would like to go. The default is 600 seconds ie. 10 minutes. |
||
548 | * |
||
549 | * @return integer The total number of active users. If this is 1, then that's you! |
||
550 | * |
||
551 | * ```php |
||
552 | * $auth->count(86400); // within the last 24 hours |
||
553 | * ``` |
||
554 | */ |
||
555 | 1 | public function online($duration = 600) |
|
556 | { |
||
557 | 1 | return $this->db->value('SELECT COUNT(*) FROM users WHERE last_activity >= ?', array(time() - $duration)); |
|
558 | } |
||
559 | |||
560 | /** |
||
561 | * This will tell you if the person viewing the current page is a specific (optional) user, or not. This does not apply if the user is HTTP Basic Authenticated from an array or YAML file of users. |
||
562 | * |
||
563 | * @param integer $user_id If you want to verify that this is a specific user, then you may indicate the user's id here. |
||
564 | * |
||
565 | * @return false|integer False if they are not a signed in user, and if you included a $user_id then false if they are not that specific user. Otherwise this returns the id of the signed in user. |
||
566 | * |
||
567 | * ```php |
||
568 | * if ($user_id = $auth->isUser()) { |
||
569 | * // Now we may do something specifically for $user_id |
||
570 | * } |
||
571 | * |
||
572 | * if (!$auth->isUser($seller_id)) { |
||
573 | * $page->eject(); // not the real seller, get them out of here |
||
574 | * } |
||
575 | * |
||
576 | * if ($auth->isUser()) { |
||
577 | * // Display a logout link |
||
578 | * } |
||
579 | * ``` |
||
580 | */ |
||
581 | 7 | public function isUser($user_id = null) |
|
582 | { |
||
583 | 7 | if (!$user = $this->user('id')) { |
|
584 | 7 | return false; |
|
585 | } |
||
586 | 5 | if (empty($user_id)) { |
|
587 | 5 | return (!empty($user)) ? $user : false; // an id > 0 or false |
|
588 | } |
||
589 | |||
590 | 2 | return (!empty($user) && $user_id == $user) ? $user : false; |
|
591 | } |
||
592 | |||
593 | /** |
||
594 | * Allows you to determine if ``$this->isUser()`` submitted a password during the current session, or if we're relying on a remember-me cookie. |
||
595 | * |
||
596 | * @return false|integer The current user's id if they submitted a password during the current session, or false if not. |
||
597 | * |
||
598 | * ```php |
||
599 | * if ($user_id = $auth->isVerified()) { |
||
600 | * // Allow them to change their password, charge their credit card, etc. |
||
601 | * } |
||
602 | * ``` |
||
603 | */ |
||
604 | 1 | public function isVerified() |
|
605 | { |
||
606 | 1 | return (($user_id = $this->isUser()) && $user_id == $this->page->session->get('bootpress/verified')) ? $user_id : false; |
|
607 | } |
||
608 | |||
609 | /** |
||
610 | * This will tell you if the person viewing the current page has admin access greater than or equal to $level, or not. There is no need to check if ``$this->isUser()`` first when using this function, unless you also want the $user_id, or to make sure this is a specific admin user. HTTP Basic Authenticated users will always pass this test and returns (integer) 1, giving them super-admin privileges. |
||
611 | * |
||
612 | * @param integer $level The admin user must be greater than or equal to the level you indicate here. This method manages admin permissions as follows: |
||
613 | * |
||
614 | * 1. Is the end all and be all of admins, and can access anything. |
||
615 | * 2. Does not have level 1 access, but can access 2, 3, 4, 5, etc. |
||
616 | * 3. Cannot access level 1 or 2 admin pages, but can access 3, 4, 5, 6 ... you get the picture. |
||
617 | * |
||
618 | * @return bool False if they are not even a user in the first place, and false again if they don't have the level of access you desire. Otherwise it returns the level of access they have. |
||
619 | * |
||
620 | * ```php |
||
621 | * if ($auth->isAdmin(1) || $auth->isUser($seller)) { |
||
622 | * // Now you and the seller can edit their info |
||
623 | * } |
||
624 | * |
||
625 | * if ($level = $auth->isAdmin(2)) { |
||
626 | * // Level 1 and level 2 admins can access this |
||
627 | * if ($level == 1) { |
||
628 | * // Now we are tightening down the hatches |
||
629 | * } |
||
630 | * } |
||
631 | * ``` |
||
632 | */ |
||
633 | 3 | public function isAdmin($level = 1) |
|
634 | { |
||
635 | 3 | if ($this->basic) { |
|
0 ignored issues
–
show
The expression
$this->basic of type null|string is loosely compared to true ; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.
In PHP, under loose comparison (like For '' == false // true
'' == null // true
'ab' == false // false
'ab' == null // false
// It is often better to use strict comparison
'' === false // false
'' === null // false
![]() |
|||
636 | 1 | return 1; |
|
637 | 3 | } elseif (!$admin = $this->user('admin')) { |
|
638 | 1 | return false; |
|
639 | } |
||
640 | |||
641 | 2 | return (!empty($admin) && $admin <= $level) ? $admin : false; |
|
642 | } |
||
643 | |||
644 | /** |
||
645 | * Checks to see if the signed in user is included in any or all of the group(s) you specify. |
||
646 | * |
||
647 | * @param string|array $group The name of the group. To verify membership for the current user against |
||
648 | * @param string $check If '**all**' (default) then they must be in every group specified. If '**any**' then they must be in at least one of the groups specified. |
||
649 | * |
||
650 | * @return bool True or False. |
||
651 | * |
||
652 | * ```php |
||
653 | * if ($auth->inGroup(array('heaven', 'hell'), 'any')) { |
||
654 | * // Then this signed in user is dead. |
||
655 | * $auth->logout(); |
||
656 | * } |
||
657 | * ``` |
||
658 | */ |
||
659 | 2 | public function inGroup($group, $check = 'all') |
|
660 | { |
||
661 | 2 | if ($this->basic) { |
|
0 ignored issues
–
show
The expression
$this->basic of type null|string is loosely compared to true ; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.
In PHP, under loose comparison (like For '' == false // true
'' == null // true
'ab' == false // false
'ab' == null // false
// It is often better to use strict comparison
'' === false // false
'' === null // false
![]() |
|||
662 | 1 | return true; |
|
663 | } |
||
664 | 2 | return ($user_id = $this->isUser()) ? $this->userInGroup($user_id, $group, $check) : false; |
|
0 ignored issues
–
show
$user_id is of type array|string , but the function expects a integer .
It seems like the type of the argument is not accepted by the function/method which you are calling. In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug. We suggest to add an explicit type cast like in the following example: function acceptsInteger($int) { }
$x = '123'; // string "123"
// Instead of
acceptsInteger($x);
// we recommend to use
acceptsInteger((integer) $x);
![]() It seems like
$group defined by parameter $group on line 659 can also be of type array ; however, BootPress\Auth\Component::userInGroup() does only seem to accept string , maybe add an additional type check?
This check looks at variables that have been passed in as parameters and are passed out again to other methods. If the outgoing method call has stricter type requirements than the method itself, an issue is raised. An additional type check may prevent trouble. ![]() |
|||
665 | } |
||
666 | |||
667 | /** |
||
668 | * This will add $user_id(s) to the $group(s) you want to include them in. |
||
669 | * |
||
670 | * @param integer $user_id Of the user. To add multiple users, make this an ``array($user_id, ...)`` of users to add to the $group(s). |
||
671 | * @param string $group The name of the group you would like to include them in. To include in multiple groups, make this an ``array($group, ...)`` of groups to add the $user_id(s) to. |
||
672 | * |
||
673 | * ```php |
||
674 | * $auth->addToGroup($user_id, 'rothschild'); |
||
675 | * ``` |
||
676 | */ |
||
677 | 1 | public function addToGroup($user_id, $group) |
|
678 | { |
||
679 | 1 | $users = (array) $user_id; |
|
680 | 1 | $groups = (array) $this->groupId($group); |
|
681 | 1 | $this->removeFromGroup($users, $groups); |
|
0 ignored issues
–
show
$users is of type array , but the function expects a integer .
It seems like the type of the argument is not accepted by the function/method which you are calling. In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug. We suggest to add an explicit type cast like in the following example: function acceptsInteger($int) { }
$x = '123'; // string "123"
// Instead of
acceptsInteger($x);
// we recommend to use
acceptsInteger((integer) $x);
![]() $groups is of type array , but the function expects a string .
It seems like the type of the argument is not accepted by the function/method which you are calling. In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug. We suggest to add an explicit type cast like in the following example: function acceptsInteger($int) { }
$x = '123'; // string "123"
// Instead of
acceptsInteger($x);
// we recommend to use
acceptsInteger((integer) $x);
![]() |
|||
682 | 1 | $stmt = $this->db->insert('user_groups', array('user_id', 'group_id')); |
|
683 | 1 | foreach ($users as $user_id) { |
|
684 | 1 | foreach ($groups as $group_id) { |
|
685 | 1 | $this->db->insert($stmt, array($user_id, $group_id)); |
|
686 | 1 | } |
|
687 | 1 | } |
|
688 | 1 | $this->db->close($stmt); |
|
689 | 1 | } |
|
690 | |||
691 | /** |
||
692 | * This will remove $user_id(s) from the $group(s) they no longer belong in. |
||
693 | * |
||
694 | * @param integer $user_id Of the user. To remove multiple users, make this an ``array($user_id, ...)`` of users to remove from the $group(s). |
||
695 | * @param string $group The name of the group you would like to remove them from. To remove from multiple groups, make this an ``array($group, ...)`` of groups to remove the $user_id(s) from. |
||
696 | * |
||
697 | * ```php |
||
698 | * $auth->removeFromGroup($user_id, 'rothschild'); // $user_id should not be involved with them anyways |
||
699 | * ``` |
||
700 | */ |
||
701 | 1 | public function removeFromGroup($user_id, $group) |
|
702 | { |
||
703 | 1 | $this->db->exec(array( |
|
704 | 1 | 'DELETE FROM user_groups', |
|
705 | 1 | 'WHERE user_id IN ('.implode(', ', (array) $user_id).')', |
|
706 | 1 | 'AND group_id IN('.implode(', ', (array) $this->groupId($group)).')', |
|
707 | 1 | )); |
|
708 | 1 | } |
|
709 | |||
710 | /** |
||
711 | * This will retrieve all of the groups that $user_id(s) belong to. |
||
712 | * |
||
713 | * @param integer $user_id Of the user. If you want to retrieve the groups of multiple users at once, then make this an ``array($user_id, ...)`` of users. |
||
714 | * |
||
715 | * @return array A single ``array($group, ...)`` of groups if $user_id is an integer (single), or a multidimensional ``array($user_id => $groups, ...)`` for every $user_id in the order given. |
||
716 | * |
||
717 | * ```php |
||
718 | * $groups = $auth->getUsersGroups($user_id); |
||
719 | * ``` |
||
720 | */ |
||
721 | 4 | public function getUsersGroups($user_id) |
|
722 | { |
||
723 | 4 | $single = (is_array($user_id)) ? false : true; |
|
724 | 4 | $ids = ($single) ? array($user_id) : $user_id; |
|
725 | 4 | $users = array(); |
|
726 | 4 | foreach ($ids as $id) { |
|
0 ignored issues
–
show
The expression
$ids of type array|integer is not guaranteed to be traversable. How about adding an additional type check?
There are different options of fixing this problem.
![]() |
|||
727 | 4 | $users[$id] = array(); |
|
728 | 4 | } |
|
729 | 4 | foreach ($this->db->all(array( |
|
730 | 4 | 'SELECT u.user_id, g.name AS group_name', |
|
731 | 4 | 'FROM user_groups AS u', |
|
732 | 4 | 'INNER JOIN user_group_names AS g ON u.group_id = g.id', |
|
733 | 4 | 'WHERE u.user_id IN('.implode(', ', $ids).')', |
|
734 | 4 | 'ORDER BY g.name ASC', |
|
735 | 4 | ), '', 'assoc') as $row) { |
|
736 | 2 | $users[$row['user_id']][] = $row['group_name']; |
|
737 | 4 | } |
|
738 | |||
739 | 4 | return ($single) ? array_shift($users) : $users; |
|
740 | } |
||
741 | |||
742 | /** |
||
743 | * This will retrieve all of the user_id's that belong to the $group(s). |
||
744 | * |
||
745 | * @param string $group The name of the group. If you want to retrieve the user_id's of multiple groups at once, then make this an ``array($group, ...)`` of groups. |
||
746 | * |
||
747 | * @return array A single ``array($user_id, ...)`` of users if $groups is a string (single), or a multidimensional ``array($group => (array) $user_ids, ...)`` for every $group in the order given. |
||
748 | * |
||
749 | * ```php |
||
750 | * $users = $auth->getGroupsUsers('rothschild'); |
||
751 | * ``` |
||
752 | */ |
||
753 | 1 | public function getGroupsUsers($group) |
|
754 | { |
||
755 | 1 | $single = (is_array($group)) ? false : true; |
|
756 | 1 | $ids = ($single) ? array($group) : $group; |
|
757 | 1 | $groups = array(); |
|
758 | 1 | foreach ($ids as $id) { |
|
0 ignored issues
–
show
The expression
$ids of type array|string is not guaranteed to be traversable. How about adding an additional type check?
There are different options of fixing this problem.
![]() |
|||
759 | 1 | $groups[$id] = array(); |
|
760 | 1 | } |
|
761 | 1 | foreach ($this->db->all(array( |
|
762 | 1 | 'SELECT u.user_id, u.group_id, g.name AS group_name', |
|
763 | 1 | 'FROM user_groups AS u', |
|
764 | 1 | 'INNER JOIN user_group_names AS g ON u.group_id = g.id', |
|
765 | 1 | 'WHERE u.user_id > 0 AND u.group_id IN('.implode(', ', $this->groupId($ids)).')', |
|
766 | 1 | 'ORDER BY u.user_id, u.group_id ASC', |
|
767 | 1 | ), '', 'assoc') as $row) { |
|
768 | 1 | $key = (isset($groups[$row['group_id']])) ? $row['group_id'] : $row['group_name']; |
|
769 | 1 | $groups[$key][] = $row['user_id']; |
|
770 | 1 | } |
|
771 | |||
772 | 1 | return ($single) ? array_shift($groups) : $groups; |
|
773 | } |
||
774 | |||
775 | /** |
||
776 | * This will verify if $user_id is in '**any**' or '**all**' of the $group(s) specified. If you are checking for the current user of your page, then do not use this method. Use ``$this->inGroup()`` instead. |
||
777 | * |
||
778 | * @param integer $user_id Of the user whose $group(s) membership you want to verify. This cannot be an array. Sorry. |
||
779 | * @param string $group The name of the group. To verify $user_id against multiple groups then make this an ``array($group, ...)`` of groups. |
||
780 | * @param string $check If '**all**' (default) then they must be in every group specified. If '**any**' then they must be in at least one of the groups specified. |
||
781 | * |
||
782 | * @return array True or False, whether or not your conditions were met. |
||
783 | * |
||
784 | * ```php |
||
785 | * if ($auth->userInGroup($user_id, array('rothschild', 'white house', 'al-Qaeda'), 'any') { |
||
786 | * // Well then we've got quite the user on our hands. |
||
787 | * } |
||
788 | * ``` |
||
789 | */ |
||
790 | 2 | public function userInGroup($user_id, $group, $check = 'all') // or 'any' |
|
791 | { |
||
792 | 2 | $groups = implode(',', $this->getUsersGroups($user_id)); |
|
793 | 2 | if (empty($groups)) { |
|
794 | 1 | return false; |
|
795 | } |
||
796 | 2 | $check = (in_array(strtolower($check), array('all', 'and', '&&'))) ? 'all' : 'any'; |
|
797 | 2 | foreach ((array) $group as $in) { |
|
798 | 2 | if (mb_stripos(",{$groups},", ",{$in},") !== false) { |
|
799 | 2 | if ($check == 'any') { |
|
800 | 2 | return true; // there is no sense in checking any more beyond this |
|
801 | } |
||
802 | 2 | } elseif ($check == 'all') { |
|
803 | 2 | return false; // they are not in this group, so that is all we need to know |
|
804 | } |
||
805 | 2 | } |
|
806 | |||
807 | 1 | return ($check == 'all') ? true : false; |
|
808 | } |
||
809 | |||
810 | /** |
||
811 | * Retrieves a group's id. |
||
812 | * |
||
813 | * @param string|array $name Of the group. |
||
814 | * |
||
815 | * @return integer|array The group(s) id(s). |
||
816 | */ |
||
817 | 1 | private function groupId($name) |
|
818 | { |
||
819 | 1 | $single = (is_array($name)) ? false : true; |
|
820 | 1 | $groups = array(); |
|
821 | 1 | foreach ((array) $name as $group) { |
|
822 | 1 | if (empty($group)) { |
|
823 | 1 | $group_id = 0; |
|
824 | 1 | } elseif (is_numeric($group)) { |
|
825 | 1 | $group_id = $group; |
|
826 | 1 | } else { |
|
827 | 1 | $group_id = $this->db->value('SELECT id FROM user_group_names WHERE name = ?', $group); |
|
828 | 1 | if (empty($group_id)) { |
|
829 | 1 | $group_id = $this->db->insert('user_group_names', array('name' => $group)); |
|
830 | 1 | } |
|
831 | } |
||
832 | 1 | $groups[$group] = $group_id; |
|
833 | 1 | } |
|
834 | |||
835 | 1 | return ($single) ? array_shift($groups) : $groups; |
|
836 | } |
||
837 | |||
838 | /** |
||
839 | * Sets (or removes if the $value is empty) a cookie to verify the validity of a session. |
||
840 | * |
||
841 | * @param string $value Of the cookie. |
||
842 | * @param integer $expires How long (in seconds) the cookie should exist. |
||
843 | */ |
||
844 | 6 | private function setCookie($value = '', $expires = 0) |
|
845 | { |
||
846 | 6 | if (empty($value)) { |
|
847 | 6 | $this->page->session->remove('bootpress/cookie'); |
|
848 | 6 | $expires = 1; |
|
849 | 6 | } else { |
|
850 | 4 | $this->page->session->set('bootpress/cookie', $value); |
|
851 | 4 | $value = base64_encode($value); |
|
852 | 4 | if ($expires != 0) { |
|
853 | 4 | $expires += time(); |
|
854 | 4 | } |
|
855 | } |
||
856 | 6 | $match = session_get_cookie_params(); |
|
857 | 6 | setcookie('bootpress', $value, $expires, $match['path'], $match['domain'], $match['secure'], true); |
|
858 | 6 | } |
|
859 | |||
860 | /** |
||
861 | * Generates the series and tokens we use to compare sessions and cookies with. |
||
862 | * |
||
863 | * @return string A random, 22 character string. |
||
864 | */ |
||
865 | 4 | private function salt() |
|
866 | { |
||
867 | 4 | return substr(strtr(rtrim(base64_encode(random_bytes(16)), '='), '+', '.'), 0, 22); |
|
868 | } |
||
869 | } |
||
870 |