1 | <?php |
||
2 | |||
3 | namespace Elgg\Database; |
||
4 | |||
5 | use Elgg\Config as Conf; |
||
6 | use Elgg\Database; |
||
7 | use ElggUser; |
||
8 | use RegistrationException; |
||
9 | |||
10 | /** |
||
11 | * WARNING: API IN FLUX. DO NOT USE DIRECTLY. |
||
12 | * |
||
13 | * @access private |
||
14 | * |
||
15 | * @package Elgg.Core |
||
16 | * @subpackage Database |
||
17 | * @since 1.10.0 |
||
18 | */ |
||
19 | class UsersTable { |
||
20 | |||
21 | use \Elgg\TimeUsing; |
||
22 | |||
23 | /** |
||
24 | * @var Conf |
||
25 | */ |
||
26 | protected $config; |
||
27 | |||
28 | /** |
||
29 | * @var Database |
||
30 | */ |
||
31 | protected $db; |
||
32 | |||
33 | /** |
||
34 | * @var MetadataTable |
||
35 | */ |
||
36 | protected $metadata; |
||
37 | |||
38 | /** |
||
39 | * Constructor |
||
40 | * |
||
41 | * @param Conf $config Config |
||
42 | * @param Database $db Database |
||
43 | * @param MetadataTable $metadata Metadata table |
||
44 | */ |
||
45 | 4419 | public function __construct(Conf $config, Database $db, MetadataTable $metadata) { |
|
46 | 4419 | $this->config = $config; |
|
47 | 4419 | $this->db = $db; |
|
48 | 4419 | $this->metadata = $metadata; |
|
49 | 4419 | } |
|
50 | |||
51 | /** |
||
52 | * Get user by username |
||
53 | * |
||
54 | * @param string $username The user's username |
||
55 | * |
||
56 | * @return ElggUser|false Depending on success |
||
57 | */ |
||
58 | 459 | public function getByUsername($username) { |
|
59 | |||
60 | // Fixes #6052. Username is frequently sniffed from the path info, which, |
||
61 | // unlike $_GET, is not URL decoded. If the username was not URL encoded, |
||
62 | // this is harmless. |
||
63 | 459 | $username = rawurldecode($username); |
|
64 | |||
65 | 459 | if (!$username) { |
|
66 | return false; |
||
67 | } |
||
68 | |||
69 | 459 | $entity =_elgg_services()->dataCache->usernames->load($username); |
|
70 | 459 | if ($entity instanceof ElggUser) { |
|
71 | 8 | return $entity; |
|
72 | } |
||
73 | |||
74 | 459 | $users = elgg_get_entities([ |
|
75 | 459 | 'types' => 'user', |
|
76 | 'metadata_name_value_pairs' => [ |
||
77 | [ |
||
78 | 459 | 'name' => 'username', |
|
79 | 459 | 'value' => $username, |
|
80 | ], |
||
81 | ], |
||
82 | 459 | 'limit' => 1, |
|
83 | ]); |
||
84 | |||
85 | 459 | return $users ? $users[0] : false; |
|
86 | } |
||
87 | |||
88 | /** |
||
89 | * Get an array of users from an email address |
||
90 | * |
||
91 | * @param string $email Email address |
||
92 | * @return array |
||
93 | */ |
||
94 | 162 | public function getByEmail($email) { |
|
95 | 162 | if (!$email) { |
|
96 | return []; |
||
97 | } |
||
98 | |||
99 | 162 | $users = elgg_get_entities([ |
|
100 | 162 | 'types' => 'user', |
|
101 | 'metadata_name_value_pairs' => [ |
||
102 | [ |
||
103 | 162 | 'name' => 'email', |
|
104 | 162 | 'value' => $email, |
|
105 | ], |
||
106 | ], |
||
107 | 162 | 'limit' => 1, |
|
108 | ]); |
||
109 | |||
110 | 162 | return $users ? : []; |
|
0 ignored issues
–
show
Bug
Best Practice
introduced
by
Loading history...
|
|||
111 | } |
||
112 | |||
113 | /** |
||
114 | * Return users (or the number of them) who have been active within a recent period. |
||
115 | * |
||
116 | * @param array $options Array of options with keys: |
||
117 | * |
||
118 | * seconds (int) => Length of period (default 600 = 10min) |
||
119 | * limit (int) => Limit (default 10) |
||
120 | * offset (int) => Offset (default 0) |
||
121 | * count (bool) => Return a count instead of users? (default false) |
||
122 | * |
||
123 | * @return \ElggUser[]|int |
||
124 | */ |
||
125 | 1 | public function findActive(array $options = []) { |
|
126 | |||
127 | 1 | $options = array_merge([ |
|
128 | 1 | 'seconds' => 600, |
|
129 | 1 | 'limit' => $this->config->default_limit, |
|
130 | 1 | ], $options); |
|
131 | |||
132 | // cast options we're sending to hook |
||
133 | 1 | foreach (['seconds', 'limit', 'offset'] as $key) { |
|
134 | 1 | $options[$key] = (int) $options[$key]; |
|
135 | } |
||
136 | 1 | $options['count'] = (bool) $options['count']; |
|
137 | |||
138 | // allow plugins to override |
||
139 | $params = [ |
||
140 | 1 | 'seconds' => $options['seconds'], |
|
141 | 1 | 'limit' => $options['limit'], |
|
142 | 1 | 'offset' => $options['offset'], |
|
143 | 1 | 'count' => $options['count'], |
|
144 | 1 | 'options' => $options, |
|
145 | ]; |
||
146 | 1 | $data = _elgg_services()->hooks->trigger('find_active_users', 'system', $params, null); |
|
147 | // check null because the handler could legitimately return falsey values. |
||
148 | 1 | if ($data !== null) { |
|
149 | return $data; |
||
150 | } |
||
151 | |||
152 | 1 | $time = $this->getCurrentTime()->getTimestamp() - $options['seconds']; |
|
153 | 1 | return elgg_get_entities([ |
|
0 ignored issues
–
show
The expression
return elgg_get_entities... 'e.last_action desc')) could also return false which is incompatible with the documented return type ElggUser[]|integer . Did you maybe forget to handle an error condition?
If the returned type also contains false, it is an indicator that maybe an error condition leading to the specific return statement remains unhandled.
Loading history...
|
|||
154 | 1 | 'type' => 'user', |
|
155 | 1 | 'limit' => $options['limit'], |
|
156 | 1 | 'offset' => $options['offset'], |
|
157 | 1 | 'count' => $options['count'], |
|
158 | 1 | 'wheres' => ["e.last_action >= {$time}"], |
|
159 | 1 | 'order_by' => "e.last_action desc", |
|
160 | ]); |
||
161 | } |
||
162 | |||
163 | /** |
||
164 | * Registers a user, returning false if the username already exists |
||
165 | * |
||
166 | * @param string $username The username of the new user |
||
167 | * @param string $password The password |
||
168 | * @param string $name The user's display name |
||
169 | * @param string $email The user's email address |
||
170 | * @param bool $allow_multiple_emails Allow the same email address to be |
||
171 | * registered multiple times? |
||
172 | * @param string $subtype Subtype of the user entity |
||
173 | * |
||
174 | * @return int|false The new user's GUID; false on failure |
||
175 | * @throws RegistrationException |
||
176 | */ |
||
177 | 162 | public function register($username, $password, $name, $email, $allow_multiple_emails = false, $subtype = null) { |
|
178 | |||
179 | // no need to trim password |
||
180 | 162 | $username = trim($username); |
|
181 | 162 | $name = trim(strip_tags($name)); |
|
182 | 162 | $email = trim($email); |
|
183 | |||
184 | // A little sanity checking |
||
185 | 162 | if (empty($username) || empty($password) || empty($name) || empty($email)) { |
|
186 | return false; |
||
187 | } |
||
188 | |||
189 | // Make sure a user with conflicting details hasn't registered and been disabled |
||
190 | 162 | $access_status = access_get_show_hidden_status(); |
|
191 | 162 | access_show_hidden_entities(true); |
|
192 | |||
193 | 162 | if (!validate_email_address($email)) { |
|
194 | throw new RegistrationException(_elgg_services()->translator->translate('registration:emailnotvalid')); |
||
195 | } |
||
196 | |||
197 | 162 | if (!validate_password($password)) { |
|
198 | throw new RegistrationException(_elgg_services()->translator->translate('registration:passwordnotvalid')); |
||
199 | } |
||
200 | |||
201 | 162 | if (!validate_username($username)) { |
|
202 | throw new RegistrationException(_elgg_services()->translator->translate('registration:usernamenotvalid')); |
||
203 | } |
||
204 | |||
205 | 162 | if (get_user_by_username($username)) { |
|
206 | throw new RegistrationException(_elgg_services()->translator->translate('registration:userexists')); |
||
207 | } |
||
208 | |||
209 | 162 | if ((!$allow_multiple_emails) && (get_user_by_email($email))) { |
|
210 | throw new RegistrationException(_elgg_services()->translator->translate('registration:dupeemail')); |
||
211 | } |
||
212 | |||
213 | 162 | access_show_hidden_entities($access_status); |
|
214 | |||
215 | // Create user |
||
216 | 162 | $constructor = ElggUser::class; |
|
217 | 162 | if (isset($subtype)) { |
|
218 | 160 | $class = elgg_get_entity_class('user', $subtype); |
|
219 | 160 | if ($class && class_exists($class) && is_subclass_of($class, ElggUser::class)) { |
|
220 | $constructor = $class; |
||
221 | } |
||
222 | } |
||
223 | |||
224 | 162 | $user = new $constructor(); |
|
225 | 162 | if (isset($subtype)) { |
|
226 | 160 | $user->subtype = $subtype; |
|
227 | } |
||
228 | 162 | $user->username = $username; |
|
229 | 162 | $user->email = $email; |
|
230 | 162 | $user->name = $name; |
|
231 | 162 | $user->access_id = ACCESS_PUBLIC; |
|
232 | 162 | $user->owner_guid = 0; // Users aren't owned by anyone, even if they are admin created. |
|
233 | 162 | $user->container_guid = 0; // Users aren't contained by anyone, even if they are admin created. |
|
234 | 162 | $user->language = _elgg_services()->translator->getCurrentLanguage(); |
|
235 | 162 | if ($user->save() === false) { |
|
236 | return false; |
||
237 | } |
||
238 | |||
239 | // doing this after save to prevent metadata save notices on unwritable metadata password_hash |
||
240 | 162 | $user->setPassword($password); |
|
241 | |||
242 | // Turn on email notifications by default |
||
243 | 162 | $user->setNotificationSetting('email', true); |
|
244 | |||
245 | 162 | return $user->getGUID(); |
|
246 | } |
||
247 | |||
248 | /** |
||
249 | * Generates a unique invite code for a user |
||
250 | * |
||
251 | * @param string $username The username of the user sending the invitation |
||
252 | * |
||
253 | * @return string Invite code |
||
254 | * @see validateInviteCode |
||
255 | */ |
||
256 | public function generateInviteCode($username) { |
||
257 | $time = $this->getCurrentTime()->getTimestamp(); |
||
258 | return "$time." . _elgg_services()->hmac->getHmac([(int) $time, $username])->getToken(); |
||
259 | } |
||
260 | |||
261 | /** |
||
262 | * Validate a user's invite code |
||
263 | * |
||
264 | * @param string $username The username |
||
265 | * @param string $code The invite code |
||
266 | * |
||
267 | * @return bool |
||
268 | * @see generateInviteCode |
||
269 | */ |
||
270 | public function validateInviteCode($username, $code) { |
||
271 | // validate the format of the token created by ->generateInviteCode() |
||
272 | if (!preg_match('~^(\d+)\.([a-zA-Z0-9\-_]+)$~', $code, $m)) { |
||
273 | return false; |
||
274 | } |
||
275 | $time = $m[1]; |
||
276 | $mac = $m[2]; |
||
277 | |||
278 | return _elgg_services()->hmac->getHmac([(int) $time, $username])->matchesToken($mac); |
||
279 | } |
||
280 | } |
||
281 |