1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
/** |
4
|
|
|
* This file contains some useful functions for members and membergroups. |
5
|
|
|
* |
6
|
|
|
* @name ElkArte Forum |
7
|
|
|
* @copyright ElkArte Forum contributors |
8
|
|
|
* @license BSD http://opensource.org/licenses/BSD-3-Clause |
9
|
|
|
* |
10
|
|
|
* This file contains code covered by: |
11
|
|
|
* copyright: 2011 Simple Machines (http://www.simplemachines.org) |
12
|
|
|
* license: BSD, See included LICENSE.TXT for terms and conditions. |
13
|
|
|
* |
14
|
|
|
* @version 1.1 Release Candidate 1 |
15
|
|
|
* |
16
|
|
|
*/ |
17
|
|
|
|
18
|
|
|
/** |
19
|
|
|
* Delete one or more members. |
20
|
|
|
* |
21
|
|
|
* What it does: |
22
|
|
|
* |
23
|
|
|
* - Requires profile_remove_own or profile_remove_any permission for |
24
|
|
|
* respectively removing your own account or any account. |
25
|
|
|
* - Non-admins cannot delete admins. |
26
|
|
|
* |
27
|
|
|
* What id does |
28
|
|
|
* - Changes author of messages, topics and polls to guest authors. |
29
|
|
|
* - Removes all log entries concerning the deleted members, except the |
30
|
|
|
* error logs, ban logs and moderation logs. |
31
|
|
|
* - Removes these members' personal messages (only the inbox) |
32
|
|
|
* - Removes avatars, ban entries, theme settings, moderator positions, poll votes, |
33
|
|
|
* likes, mentions, notifications |
34
|
|
|
* - Removes custom field data associated with them |
35
|
|
|
* - Updates member statistics afterwards. |
36
|
|
|
* |
37
|
|
|
* @package Members |
38
|
|
|
* @param int[]|int $users |
39
|
|
|
* @param bool $check_not_admin = false |
40
|
|
|
* @throws Elk_Exception |
41
|
|
|
*/ |
42
|
|
|
function deleteMembers($users, $check_not_admin = false) |
43
|
|
|
{ |
44
|
|
|
global $modSettings, $user_info; |
45
|
|
|
|
46
|
|
|
$db = database(); |
47
|
|
|
|
48
|
|
|
// Try give us a while to sort this out... |
49
|
|
|
detectServer()->setTimeLimit(600); |
50
|
|
|
|
51
|
|
|
// Try to get some more memory. |
52
|
|
|
detectServer()->setMemoryLimit('128M'); |
53
|
|
|
|
54
|
|
|
// If it's not an array, make it so! |
55
|
|
|
if (!is_array($users)) |
56
|
|
|
$users = array($users); |
57
|
|
|
else |
58
|
|
|
$users = array_unique($users); |
59
|
|
|
|
60
|
|
|
// Make sure there's no void user in here. |
61
|
|
|
$users = array_diff($users, array(0)); |
62
|
|
|
|
63
|
|
|
// How many are they deleting? |
64
|
|
|
if (empty($users)) |
65
|
|
|
return; |
66
|
|
|
elseif (count($users) == 1) |
67
|
|
|
{ |
68
|
|
|
list ($user) = $users; |
69
|
|
|
|
70
|
|
|
if ($user == $user_info['id']) |
71
|
|
|
isAllowedTo('profile_remove_own'); |
72
|
|
|
else |
73
|
|
|
isAllowedTo('profile_remove_any'); |
74
|
|
|
} |
75
|
|
|
else |
76
|
|
|
{ |
77
|
|
|
foreach ($users as $k => $v) |
78
|
|
|
$users[$k] = (int) $v; |
79
|
|
|
|
80
|
|
|
// Deleting more than one? You can't have more than one account... |
81
|
|
|
isAllowedTo('profile_remove_any'); |
82
|
|
|
} |
83
|
|
|
|
84
|
|
|
// Get their names for logging purposes. |
85
|
|
|
$request = $db->query('', ' |
86
|
|
|
SELECT id_member, member_name, email_address, CASE WHEN id_group = {int:admin_group} OR FIND_IN_SET({int:admin_group}, additional_groups) != 0 THEN 1 ELSE 0 END AS is_admin |
87
|
|
|
FROM {db_prefix}members |
88
|
|
|
WHERE id_member IN ({array_int:user_list}) |
89
|
|
|
LIMIT ' . count($users), |
90
|
|
|
array( |
91
|
|
|
'user_list' => $users, |
92
|
|
|
'admin_group' => 1, |
93
|
|
|
) |
94
|
|
|
); |
95
|
|
|
$admins = array(); |
96
|
|
|
$emails = array(); |
97
|
|
|
$user_log_details = array(); |
98
|
|
View Code Duplication |
while ($row = $db->fetch_assoc($request)) |
99
|
|
|
{ |
100
|
|
|
if ($row['is_admin']) |
101
|
|
|
$admins[] = $row['id_member']; |
102
|
|
|
$user_log_details[$row['id_member']] = array($row['id_member'], $row['member_name']); |
103
|
|
|
$emails[] = $row['email_address']; |
104
|
|
|
} |
105
|
|
|
$db->free_result($request); |
106
|
|
|
|
107
|
|
|
if (empty($user_log_details)) |
108
|
|
|
return; |
109
|
|
|
|
110
|
|
|
// Make sure they aren't trying to delete administrators if they aren't one. But don't bother checking if it's just themselves. |
111
|
|
|
if (!empty($admins) && ($check_not_admin || (!allowedTo('admin_forum') && (count($users) != 1 || $users[0] != $user_info['id'])))) |
112
|
|
|
{ |
113
|
|
|
$users = array_diff($users, $admins); |
114
|
|
|
foreach ($admins as $id) |
115
|
|
|
unset($user_log_details[$id]); |
116
|
|
|
} |
117
|
|
|
|
118
|
|
|
// No one left? |
119
|
|
|
if (empty($users)) |
120
|
|
|
return; |
121
|
|
|
|
122
|
|
|
// Log the action - regardless of who is deleting it. |
123
|
|
|
$log_changes = array(); |
124
|
|
|
foreach ($user_log_details as $user) |
125
|
|
|
{ |
126
|
|
|
$log_changes[] = array( |
127
|
|
|
'action' => 'delete_member', |
128
|
|
|
'log_type' => 'admin', |
129
|
|
|
'extra' => array( |
130
|
|
|
'member' => $user[0], |
131
|
|
|
'name' => $user[1], |
132
|
|
|
'member_acted' => $user_info['name'], |
133
|
|
|
), |
134
|
|
|
); |
135
|
|
|
|
136
|
|
|
// Remove any cached data if enabled. |
137
|
|
|
Cache::instance()->remove('user_settings-' . $user[0]); |
138
|
|
|
} |
139
|
|
|
|
140
|
|
|
// Make these peoples' posts guest posts. |
141
|
|
|
$db->query('', ' |
142
|
|
|
UPDATE {db_prefix}messages |
143
|
|
|
SET id_member = {int:guest_id}' . (!empty($modSettings['deleteMembersRemovesEmail']) ? ', |
144
|
|
|
poster_email = {string:blank_email}' : '') . ' |
145
|
|
|
WHERE id_member IN ({array_int:users})', |
146
|
|
|
array( |
147
|
|
|
'guest_id' => 0, |
148
|
|
|
'blank_email' => '', |
149
|
|
|
'users' => $users, |
150
|
|
|
) |
151
|
|
|
); |
152
|
|
|
$db->query('', ' |
153
|
|
|
UPDATE {db_prefix}polls |
154
|
|
|
SET id_member = {int:guest_id} |
155
|
|
|
WHERE id_member IN ({array_int:users})', |
156
|
|
|
array( |
157
|
|
|
'guest_id' => 0, |
158
|
|
|
'users' => $users, |
159
|
|
|
) |
160
|
|
|
); |
161
|
|
|
|
162
|
|
|
// Make these peoples' posts guest first posts and last posts. |
163
|
|
|
$db->query('', ' |
164
|
|
|
UPDATE {db_prefix}topics |
165
|
|
|
SET id_member_started = {int:guest_id} |
166
|
|
|
WHERE id_member_started IN ({array_int:users})', |
167
|
|
|
array( |
168
|
|
|
'guest_id' => 0, |
169
|
|
|
'users' => $users, |
170
|
|
|
) |
171
|
|
|
); |
172
|
|
|
$db->query('', ' |
173
|
|
|
UPDATE {db_prefix}topics |
174
|
|
|
SET id_member_updated = {int:guest_id} |
175
|
|
|
WHERE id_member_updated IN ({array_int:users})', |
176
|
|
|
array( |
177
|
|
|
'guest_id' => 0, |
178
|
|
|
'users' => $users, |
179
|
|
|
) |
180
|
|
|
); |
181
|
|
|
|
182
|
|
|
$db->query('', ' |
183
|
|
|
UPDATE {db_prefix}log_actions |
184
|
|
|
SET id_member = {int:guest_id} |
185
|
|
|
WHERE id_member IN ({array_int:users})', |
186
|
|
|
array( |
187
|
|
|
'guest_id' => 0, |
188
|
|
|
'users' => $users, |
189
|
|
|
) |
190
|
|
|
); |
191
|
|
|
|
192
|
|
|
$db->query('', ' |
193
|
|
|
UPDATE {db_prefix}log_banned |
194
|
|
|
SET id_member = {int:guest_id} |
195
|
|
|
WHERE id_member IN ({array_int:users})', |
196
|
|
|
array( |
197
|
|
|
'guest_id' => 0, |
198
|
|
|
'users' => $users, |
199
|
|
|
) |
200
|
|
|
); |
201
|
|
|
|
202
|
|
|
$db->query('', ' |
203
|
|
|
UPDATE {db_prefix}log_errors |
204
|
|
|
SET id_member = {int:guest_id} |
205
|
|
|
WHERE id_member IN ({array_int:users})', |
206
|
|
|
array( |
207
|
|
|
'guest_id' => 0, |
208
|
|
|
'users' => $users, |
209
|
|
|
) |
210
|
|
|
); |
211
|
|
|
|
212
|
|
|
// Delete the member. |
213
|
|
|
$db->query('', ' |
214
|
|
|
DELETE FROM {db_prefix}members |
215
|
|
|
WHERE id_member IN ({array_int:users})', |
216
|
|
|
array( |
217
|
|
|
'users' => $users, |
218
|
|
|
) |
219
|
|
|
); |
220
|
|
|
|
221
|
|
|
// Delete any likes... |
222
|
|
|
$db->query('', ' |
223
|
|
|
DELETE FROM {db_prefix}message_likes |
224
|
|
|
WHERE id_member IN ({array_int:users})', |
225
|
|
|
array( |
226
|
|
|
'users' => $users, |
227
|
|
|
) |
228
|
|
|
); |
229
|
|
|
|
230
|
|
|
// Delete any custom field data... |
231
|
|
|
$db->query('', ' |
232
|
|
|
DELETE FROM {db_prefix}custom_fields_data |
233
|
|
|
WHERE id_member IN ({array_int:users})', |
234
|
|
|
array( |
235
|
|
|
'users' => $users, |
236
|
|
|
) |
237
|
|
|
); |
238
|
|
|
|
239
|
|
|
// Delete any post by email keys... |
240
|
|
|
$db->query('', ' |
241
|
|
|
DELETE FROM {db_prefix}postby_emails |
242
|
|
|
WHERE email_to IN ({array_string:emails})', |
243
|
|
|
array( |
244
|
|
|
'emails' => $emails, |
245
|
|
|
) |
246
|
|
|
); |
247
|
|
|
|
248
|
|
|
// Delete the logs... |
249
|
|
|
$db->query('', ' |
250
|
|
|
DELETE FROM {db_prefix}log_actions |
251
|
|
|
WHERE id_log = {int:log_type} |
252
|
|
|
AND id_member IN ({array_int:users})', |
253
|
|
|
array( |
254
|
|
|
'log_type' => 2, |
255
|
|
|
'users' => $users, |
256
|
|
|
) |
257
|
|
|
); |
258
|
|
|
$db->query('', ' |
259
|
|
|
DELETE FROM {db_prefix}log_boards |
260
|
|
|
WHERE id_member IN ({array_int:users})', |
261
|
|
|
array( |
262
|
|
|
'users' => $users, |
263
|
|
|
) |
264
|
|
|
); |
265
|
|
|
$db->query('', ' |
266
|
|
|
DELETE FROM {db_prefix}log_comments |
267
|
|
|
WHERE id_recipient IN ({array_int:users}) |
268
|
|
|
AND comment_type = {string:warntpl}', |
269
|
|
|
array( |
270
|
|
|
'users' => $users, |
271
|
|
|
'warntpl' => 'warntpl', |
272
|
|
|
) |
273
|
|
|
); |
274
|
|
|
$db->query('', ' |
275
|
|
|
DELETE FROM {db_prefix}log_group_requests |
276
|
|
|
WHERE id_member IN ({array_int:users})', |
277
|
|
|
array( |
278
|
|
|
'users' => $users, |
279
|
|
|
) |
280
|
|
|
); |
281
|
|
|
$db->query('', ' |
282
|
|
|
DELETE FROM {db_prefix}log_karma |
283
|
|
|
WHERE id_target IN ({array_int:users}) |
284
|
|
|
OR id_executor IN ({array_int:users})', |
285
|
|
|
array( |
286
|
|
|
'users' => $users, |
287
|
|
|
) |
288
|
|
|
); |
289
|
|
|
$db->query('', ' |
290
|
|
|
DELETE FROM {db_prefix}log_mark_read |
291
|
|
|
WHERE id_member IN ({array_int:users})', |
292
|
|
|
array( |
293
|
|
|
'users' => $users, |
294
|
|
|
) |
295
|
|
|
); |
296
|
|
|
$db->query('', ' |
297
|
|
|
DELETE FROM {db_prefix}log_notify |
298
|
|
|
WHERE id_member IN ({array_int:users})', |
299
|
|
|
array( |
300
|
|
|
'users' => $users, |
301
|
|
|
) |
302
|
|
|
); |
303
|
|
|
$db->query('', ' |
304
|
|
|
DELETE FROM {db_prefix}log_online |
305
|
|
|
WHERE id_member IN ({array_int:users})', |
306
|
|
|
array( |
307
|
|
|
'users' => $users, |
308
|
|
|
) |
309
|
|
|
); |
310
|
|
|
$db->query('', ' |
311
|
|
|
DELETE FROM {db_prefix}log_subscribed |
312
|
|
|
WHERE id_member IN ({array_int:users})', |
313
|
|
|
array( |
314
|
|
|
'users' => $users, |
315
|
|
|
) |
316
|
|
|
); |
317
|
|
|
$db->query('', ' |
318
|
|
|
DELETE FROM {db_prefix}log_topics |
319
|
|
|
WHERE id_member IN ({array_int:users})', |
320
|
|
|
array( |
321
|
|
|
'users' => $users, |
322
|
|
|
) |
323
|
|
|
); |
324
|
|
|
$db->query('', ' |
325
|
|
|
DELETE FROM {db_prefix}collapsed_categories |
326
|
|
|
WHERE id_member IN ({array_int:users})', |
327
|
|
|
array( |
328
|
|
|
'users' => $users, |
329
|
|
|
) |
330
|
|
|
); |
331
|
|
|
|
332
|
|
|
// Make their votes appear as guest votes - at least it keeps the totals right. |
333
|
|
|
// @todo Consider adding back in cookie protection. |
334
|
|
|
$db->query('', ' |
335
|
|
|
UPDATE {db_prefix}log_polls |
336
|
|
|
SET id_member = {int:guest_id} |
337
|
|
|
WHERE id_member IN ({array_int:users})', |
338
|
|
|
array( |
339
|
|
|
'guest_id' => 0, |
340
|
|
|
'users' => $users, |
341
|
|
|
) |
342
|
|
|
); |
343
|
|
|
|
344
|
|
|
// Remove the mentions |
345
|
|
|
$db->query('', ' |
346
|
|
|
DELETE FROM {db_prefix}log_mentions |
347
|
|
|
WHERE id_member IN ({array_int:users})', |
348
|
|
|
array( |
349
|
|
|
'users' => $users, |
350
|
|
|
) |
351
|
|
|
); |
352
|
|
|
// And null all those that were added by him |
353
|
|
|
$db->query('', ' |
354
|
|
|
UPDATE {db_prefix}log_mentions |
355
|
|
|
SET id_member_from = {int:zero} |
356
|
|
|
WHERE id_member_from IN ({array_int:users})', |
357
|
|
|
array( |
358
|
|
|
'zero' => 0, |
359
|
|
|
'users' => $users, |
360
|
|
|
) |
361
|
|
|
); |
362
|
|
|
|
363
|
|
|
// Delete personal messages. |
364
|
|
|
require_once(SUBSDIR . '/PersonalMessage.subs.php'); |
365
|
|
|
deleteMessages(null, null, $users); |
366
|
|
|
|
367
|
|
|
$db->query('', ' |
368
|
|
|
UPDATE {db_prefix}personal_messages |
369
|
|
|
SET id_member_from = {int:guest_id} |
370
|
|
|
WHERE id_member_from IN ({array_int:users})', |
371
|
|
|
array( |
372
|
|
|
'guest_id' => 0, |
373
|
|
|
'users' => $users, |
374
|
|
|
) |
375
|
|
|
); |
376
|
|
|
|
377
|
|
|
// They no longer exist, so we don't know who it was sent to. |
378
|
|
|
$db->query('', ' |
379
|
|
|
DELETE FROM {db_prefix}pm_recipients |
380
|
|
|
WHERE id_member IN ({array_int:users})', |
381
|
|
|
array( |
382
|
|
|
'users' => $users, |
383
|
|
|
) |
384
|
|
|
); |
385
|
|
|
|
386
|
|
|
// Delete avatar. |
387
|
|
|
require_once(SUBSDIR . '/ManageAttachments.subs.php'); |
388
|
|
|
removeAttachments(array('id_member' => $users)); |
389
|
|
|
|
390
|
|
|
// It's over, no more moderation for you. |
391
|
|
|
$db->query('', ' |
392
|
|
|
DELETE FROM {db_prefix}moderators |
393
|
|
|
WHERE id_member IN ({array_int:users})', |
394
|
|
|
array( |
395
|
|
|
'users' => $users, |
396
|
|
|
) |
397
|
|
|
); |
398
|
|
|
$db->query('', ' |
399
|
|
|
DELETE FROM {db_prefix}group_moderators |
400
|
|
|
WHERE id_member IN ({array_int:users})', |
401
|
|
|
array( |
402
|
|
|
'users' => $users, |
403
|
|
|
) |
404
|
|
|
); |
405
|
|
|
|
406
|
|
|
// If you don't exist we can't ban you. |
407
|
|
|
$db->query('', ' |
408
|
|
|
DELETE FROM {db_prefix}ban_items |
409
|
|
|
WHERE id_member IN ({array_int:users})', |
410
|
|
|
array( |
411
|
|
|
'users' => $users, |
412
|
|
|
) |
413
|
|
|
); |
414
|
|
|
|
415
|
|
|
// Remove individual theme settings. |
416
|
|
|
$db->query('', ' |
417
|
|
|
DELETE FROM {db_prefix}themes |
418
|
|
|
WHERE id_member IN ({array_int:users})', |
419
|
|
|
array( |
420
|
|
|
'users' => $users, |
421
|
|
|
) |
422
|
|
|
); |
423
|
|
|
|
424
|
|
|
// These users are nobody's buddy nomore. |
425
|
|
|
$db->fetchQueryCallback(' |
426
|
|
|
SELECT id_member, pm_ignore_list, buddy_list |
427
|
|
|
FROM {db_prefix}members |
428
|
|
|
WHERE FIND_IN_SET({raw:pm_ignore_list}, pm_ignore_list) != 0 OR FIND_IN_SET({raw:buddy_list}, buddy_list) != 0', |
429
|
|
|
array( |
430
|
|
|
'pm_ignore_list' => implode(', pm_ignore_list) != 0 OR FIND_IN_SET(', $users), |
431
|
|
|
'buddy_list' => implode(', buddy_list) != 0 OR FIND_IN_SET(', $users), |
432
|
|
|
), |
433
|
|
|
function ($row) use ($users) |
434
|
|
|
{ |
435
|
|
|
updateMemberData($row['id_member'], array( |
436
|
|
|
'pm_ignore_list' => implode(',', array_diff(explode(',', $row['pm_ignore_list']), $users)), |
437
|
|
|
'buddy_list' => implode(',', array_diff(explode(',', $row['buddy_list']), $users)) |
438
|
|
|
)); |
439
|
|
|
} |
440
|
|
|
); |
441
|
|
|
|
442
|
|
|
// Make sure no member's birthday is still sticking in the calendar... |
443
|
|
|
updateSettings(array( |
444
|
|
|
'calendar_updated' => time(), |
445
|
|
|
)); |
446
|
|
|
|
447
|
|
|
// Integration rocks! |
448
|
|
|
call_integration_hook('integrate_delete_members', array($users)); |
449
|
|
|
|
450
|
|
|
updateMemberStats(); |
451
|
|
|
|
452
|
|
|
logActions($log_changes); |
453
|
|
|
} |
454
|
|
|
|
455
|
|
|
/** |
456
|
|
|
* Registers a member to the forum. |
457
|
|
|
* |
458
|
|
|
* What it does: |
459
|
|
|
* |
460
|
|
|
* - Allows two types of interface: 'guest' and 'admin'. The first |
461
|
|
|
* - includes hammering protection, the latter can perform the registration silently. |
462
|
|
|
* - The strings used in the options array are assumed to be escaped. |
463
|
|
|
* - Allows to perform several checks on the input, e.g. reserved names. |
464
|
|
|
* - The function will adjust member statistics. |
465
|
|
|
* - If an error is detected will fatal error on all errors unless return_errors is true. |
466
|
|
|
* |
467
|
|
|
* @package Members |
468
|
|
|
* @uses Auth.subs.php |
469
|
|
|
* @uses Mail.subs.php |
470
|
|
|
* |
471
|
|
|
* @param mixed[] $regOptions |
472
|
|
|
* @param string $ErrorContext |
473
|
|
|
* |
474
|
|
|
* @return int the ID of the newly created member |
475
|
|
|
* @throws Elk_Exception no_theme |
476
|
|
|
*/ |
477
|
|
|
function registerMember(&$regOptions, $ErrorContext = 'register') |
478
|
|
|
{ |
479
|
1 |
|
global $scripturl, $txt; |
480
|
|
|
|
481
|
1 |
|
$db = database(); |
482
|
|
|
|
483
|
1 |
|
loadLanguage('Login'); |
484
|
|
|
|
485
|
|
|
// We'll need some external functions. |
486
|
1 |
|
require_once(SUBSDIR . '/Auth.subs.php'); |
487
|
1 |
|
require_once(SUBSDIR . '/Mail.subs.php'); |
488
|
|
|
|
489
|
|
|
// Put any errors in here. |
490
|
1 |
|
$reg_errors = ElkArte\Errors\ErrorContext::context($ErrorContext, 0); |
491
|
|
|
|
492
|
|
|
// What method of authorization are we going to use? |
493
|
1 |
|
if (empty($regOptions['auth_method']) || !in_array($regOptions['auth_method'], array('password', 'openid'))) |
494
|
1 |
|
{ |
495
|
|
|
if (!empty($regOptions['openid'])) |
496
|
|
|
$regOptions['auth_method'] = 'openid'; |
497
|
|
|
else |
498
|
|
|
$regOptions['auth_method'] = 'password'; |
499
|
|
|
} |
500
|
|
|
|
501
|
|
|
// Spaces and other odd characters are evil... |
502
|
1 |
|
$regOptions['username'] = trim(preg_replace('~[\t\n\r \x0B\0\x{A0}\x{AD}\x{2000}-\x{200F}\x{201F}\x{202F}\x{3000}\x{FEFF}]+~u', ' ', $regOptions['username'])); |
503
|
|
|
|
504
|
|
|
// Valid emails only |
505
|
1 |
|
if (!Data_Validator::is_valid($regOptions, array('email' => 'valid_email|required|max_length[255]'), array('email' => 'trim'))) |
506
|
1 |
|
$reg_errors->addError('bad_email'); |
507
|
|
|
|
508
|
1 |
|
validateUsername(0, $regOptions['username'], $ErrorContext, !empty($regOptions['check_reserved_name'])); |
509
|
|
|
|
510
|
|
|
// Generate a validation code if it's supposed to be emailed. |
511
|
1 |
|
$validation_code = $regOptions['require'] === 'activation' ? generateValidationCode(14) : ''; |
512
|
|
|
|
513
|
|
|
// Does the first password match the second? |
514
|
1 |
|
if ($regOptions['password'] != $regOptions['password_check'] && $regOptions['auth_method'] == 'password') |
515
|
1 |
|
$reg_errors->addError('passwords_dont_match'); |
516
|
|
|
|
517
|
|
|
// That's kind of easy to guess... |
518
|
1 |
|
if ($regOptions['password'] == '') |
519
|
1 |
|
{ |
520
|
|
|
if ($regOptions['auth_method'] == 'password') |
521
|
|
|
$reg_errors->addError('no_password'); |
522
|
|
|
else |
523
|
|
|
$regOptions['password'] = sha1(mt_rand()); |
524
|
|
|
} |
525
|
|
|
|
526
|
|
|
// Now perform hard password validation as required. |
527
|
1 |
|
if (!empty($regOptions['check_password_strength']) && $regOptions['password'] != '') |
528
|
1 |
|
{ |
529
|
1 |
|
$passwordError = validatePassword($regOptions['password'], $regOptions['username'], array($regOptions['email'])); |
530
|
|
|
|
531
|
|
|
// Password isn't legal? |
532
|
1 |
|
if ($passwordError !== null) |
533
|
1 |
|
$reg_errors->addError('profile_error_password_' . $passwordError); |
534
|
1 |
|
} |
535
|
|
|
|
536
|
|
|
// @todo move to controller |
537
|
|
|
// You may not be allowed to register this email. |
538
|
1 |
|
if (!empty($regOptions['check_email_ban'])) |
539
|
1 |
|
isBannedEmail($regOptions['email'], 'cannot_register', $txt['ban_register_prohibited']); |
540
|
|
|
|
541
|
|
|
// Check if the email address is in use. |
542
|
1 |
|
if (userByEmail($regOptions['email'], $regOptions['username'])) |
543
|
1 |
|
{ |
544
|
|
|
$reg_errors->addError(array('email_in_use', array(htmlspecialchars($regOptions['email'], ENT_COMPAT, 'UTF-8')))); |
545
|
|
|
} |
546
|
|
|
|
547
|
|
|
// Perhaps someone else wants to check this user |
548
|
1 |
|
call_integration_hook('integrate_register_check', array(&$regOptions, &$reg_errors)); |
549
|
|
|
|
550
|
|
|
// If there's any errors left return them at once! |
551
|
1 |
|
if ($reg_errors->hasErrors()) |
552
|
1 |
|
return false; |
553
|
|
|
|
554
|
|
|
$reservedVars = array( |
555
|
1 |
|
'actual_theme_url', |
556
|
1 |
|
'actual_images_url', |
557
|
1 |
|
'base_theme_dir', |
558
|
1 |
|
'base_theme_url', |
559
|
1 |
|
'default_images_url', |
560
|
1 |
|
'default_theme_dir', |
561
|
1 |
|
'default_theme_url', |
562
|
1 |
|
'default_template', |
563
|
1 |
|
'images_url', |
564
|
1 |
|
'number_recent_posts', |
565
|
1 |
|
'smiley_sets_default', |
566
|
1 |
|
'theme_dir', |
567
|
1 |
|
'theme_id', |
568
|
1 |
|
'theme_layers', |
569
|
1 |
|
'theme_templates', |
570
|
1 |
|
'theme_url', |
571
|
1 |
|
); |
572
|
|
|
|
573
|
|
|
// Can't change reserved vars. |
574
|
1 |
|
if (isset($regOptions['theme_vars']) && count(array_intersect(array_keys($regOptions['theme_vars']), $reservedVars)) != 0) |
575
|
1 |
|
throw new Elk_Exception('no_theme'); |
576
|
|
|
|
577
|
1 |
|
$tokenizer = new Token_Hash(); |
578
|
|
|
|
579
|
|
|
// @since 1.0.7 - This is necessary because validateLoginPassword |
580
|
|
|
// uses a pass-by-ref and would convert to hash $regOptions['password'] |
581
|
|
|
// making it impossible to send the reminder email and even integrate |
582
|
|
|
// the registration |
583
|
1 |
|
$password = $regOptions['password']; |
584
|
|
|
|
585
|
|
|
// Some of these might be overwritten. (the lower ones that are in the arrays below.) |
586
|
1 |
|
$regOptions['register_vars'] = array( |
587
|
1 |
|
'member_name' => $regOptions['username'], |
588
|
1 |
|
'email_address' => $regOptions['email'], |
589
|
1 |
|
'passwd' => validateLoginPassword($password, '', $regOptions['username'], true), |
590
|
1 |
|
'password_salt' => $tokenizer->generate_hash(4), |
591
|
1 |
|
'posts' => 0, |
592
|
1 |
|
'date_registered' => !empty($regOptions['time']) ? $regOptions['time'] : time(), |
593
|
1 |
|
'member_ip' => $regOptions['interface'] == 'admin' ? '127.0.0.1' : $regOptions['ip'], |
594
|
1 |
|
'member_ip2' => $regOptions['interface'] == 'admin' ? '127.0.0.1' : $regOptions['ip2'], |
595
|
1 |
|
'validation_code' => substr(hash('sha256', $validation_code), 0, 10), |
596
|
1 |
|
'real_name' => !empty($regOptions['real_name']) ? $regOptions['real_name'] : $regOptions['username'], |
597
|
1 |
|
'pm_email_notify' => 1, |
598
|
1 |
|
'id_theme' => 0, |
599
|
1 |
|
'id_post_group' => 4, |
600
|
1 |
|
'lngfile' => '', |
601
|
1 |
|
'buddy_list' => '', |
602
|
1 |
|
'pm_ignore_list' => '', |
603
|
1 |
|
'message_labels' => '', |
604
|
1 |
|
'website_title' => '', |
605
|
1 |
|
'website_url' => '', |
606
|
1 |
|
'time_format' => '', |
607
|
1 |
|
'signature' => '', |
608
|
1 |
|
'avatar' => '', |
609
|
1 |
|
'usertitle' => '', |
610
|
1 |
|
'secret_question' => '', |
611
|
1 |
|
'secret_answer' => '', |
612
|
1 |
|
'additional_groups' => '', |
613
|
1 |
|
'ignore_boards' => '', |
614
|
1 |
|
'smiley_set' => '', |
615
|
1 |
|
'openid_uri' => (!empty($regOptions['openid']) ? $regOptions['openid'] : ''), |
616
|
1 |
|
'notify_announcements' => (!empty($regOptions['notify_announcements']) ? 1 : 0), |
617
|
|
|
); |
618
|
|
|
|
619
|
|
|
// Setup the activation status on this new account so it is correct - firstly is it an under age account? |
620
|
1 |
|
if ($regOptions['require'] == 'coppa') |
621
|
1 |
|
{ |
622
|
|
|
$regOptions['register_vars']['is_activated'] = 5; |
623
|
|
|
// @todo This should be changed. To what should be it be changed?? |
624
|
|
|
$regOptions['register_vars']['validation_code'] = ''; |
625
|
|
|
} |
626
|
|
|
// Maybe it can be activated right away? |
627
|
1 |
|
elseif ($regOptions['require'] == 'nothing') |
628
|
1 |
|
$regOptions['register_vars']['is_activated'] = 1; |
629
|
|
|
// Maybe it must be activated by email? |
630
|
|
|
elseif ($regOptions['require'] == 'activation') |
631
|
|
|
$regOptions['register_vars']['is_activated'] = 0; |
632
|
|
|
// Otherwise it must be awaiting approval! |
633
|
|
|
else |
634
|
|
|
$regOptions['register_vars']['is_activated'] = 3; |
635
|
|
|
|
636
|
1 |
|
if (isset($regOptions['memberGroup'])) |
637
|
1 |
|
{ |
638
|
1 |
|
require_once(SUBSDIR . '/Membergroups.subs.php'); |
639
|
|
|
|
640
|
|
|
// Make sure the id_group will be valid, if this is an administrator. |
641
|
1 |
|
$regOptions['register_vars']['id_group'] = $regOptions['memberGroup'] == 1 && !allowedTo('admin_forum') ? 0 : $regOptions['memberGroup']; |
642
|
|
|
|
643
|
|
|
// Check if this group is assignable. |
644
|
1 |
|
$unassignableGroups = getUnassignableGroups(allowedTo('admin_forum')); |
645
|
|
|
|
646
|
1 |
|
if (in_array($regOptions['register_vars']['id_group'], $unassignableGroups)) |
647
|
1 |
|
$regOptions['register_vars']['id_group'] = 0; |
648
|
1 |
|
} |
649
|
|
|
|
650
|
|
|
// Integrate optional member settings to be set. |
651
|
1 |
|
if (!empty($regOptions['extra_register_vars'])) |
652
|
1 |
|
foreach ($regOptions['extra_register_vars'] as $var => $value) |
653
|
|
|
$regOptions['register_vars'][$var] = $value; |
654
|
|
|
|
655
|
|
|
// Integrate optional user theme options to be set. |
656
|
1 |
|
$theme_vars = array(); |
657
|
1 |
|
if (!empty($regOptions['theme_vars'])) |
658
|
1 |
|
foreach ($regOptions['theme_vars'] as $var => $value) |
659
|
|
|
$theme_vars[$var] = $value; |
660
|
|
|
|
661
|
|
|
// Right, now let's prepare for insertion. |
662
|
|
|
$knownInts = array( |
663
|
1 |
|
'date_registered', 'posts', 'id_group', 'last_login', 'personal_messages', 'unread_messages', 'notifications', |
664
|
1 |
|
'new_pm', 'pm_prefs', 'hide_email', 'show_online', 'pm_email_notify', 'karma_good', 'karma_bad', |
665
|
1 |
|
'notify_announcements', 'notify_send_body', 'notify_regularity', 'notify_types', |
666
|
1 |
|
'id_theme', 'is_activated', 'id_msg_last_visit', 'id_post_group', 'total_time_logged_in', 'warning', |
667
|
1 |
|
); |
668
|
|
|
$knownFloats = array( |
669
|
1 |
|
'time_offset', |
670
|
1 |
|
); |
671
|
|
|
|
672
|
|
|
// Call an optional function to validate the users' input. |
673
|
1 |
|
call_integration_hook('integrate_register', array(&$regOptions, &$theme_vars, &$knownInts, &$knownFloats)); |
674
|
|
|
|
675
|
1 |
|
$column_names = array(); |
676
|
1 |
|
$values = array(); |
677
|
1 |
|
foreach ($regOptions['register_vars'] as $var => $val) |
678
|
|
|
{ |
679
|
1 |
|
$type = 'string'; |
680
|
1 |
View Code Duplication |
if (in_array($var, $knownInts)) |
681
|
1 |
|
$type = 'int'; |
682
|
1 |
|
elseif (in_array($var, $knownFloats)) |
683
|
|
|
$type = 'float'; |
684
|
1 |
|
elseif ($var == 'birthdate') |
685
|
|
|
$type = 'date'; |
686
|
|
|
|
687
|
1 |
|
$column_names[$var] = $type; |
688
|
1 |
|
$values[$var] = $val; |
689
|
1 |
|
} |
690
|
|
|
|
691
|
|
|
// Register them into the database. |
692
|
1 |
|
$db->insert('', |
693
|
1 |
|
'{db_prefix}members', |
694
|
1 |
|
$column_names, |
695
|
1 |
|
$values, |
696
|
1 |
|
array('id_member') |
697
|
1 |
|
); |
698
|
1 |
|
$memberID = $db->insert_id('{db_prefix}members', 'id_member'); |
699
|
|
|
|
700
|
|
|
// Update the number of members and latest member's info - and pass the name, but remove the 's. |
701
|
1 |
|
if ($regOptions['register_vars']['is_activated'] == 1) |
702
|
1 |
|
updateMemberStats($memberID, $regOptions['register_vars']['real_name']); |
703
|
|
|
else |
704
|
|
|
updateMemberStats(); |
705
|
|
|
|
706
|
|
|
// @todo there's got to be a method that does this |
707
|
|
|
// Theme variables too? |
708
|
1 |
|
if (!empty($theme_vars)) |
709
|
1 |
|
{ |
710
|
|
|
$inserts = array(); |
711
|
|
|
foreach ($theme_vars as $var => $val) |
712
|
|
|
$inserts[] = array($memberID, $var, $val); |
713
|
|
|
$db->insert('insert', |
714
|
|
|
'{db_prefix}themes', |
715
|
|
|
array('id_member' => 'int', 'variable' => 'string-255', 'value' => 'string-65534'), |
716
|
|
|
$inserts, |
717
|
|
|
array('id_member', 'variable') |
718
|
|
|
); |
719
|
|
|
} |
720
|
|
|
|
721
|
|
|
// If it's enabled, increase the registrations for today. |
722
|
1 |
|
trackStats(array('registers' => '+')); |
723
|
|
|
|
724
|
|
|
// @todo emails should be sent from the controller, with a new method. |
725
|
|
|
|
726
|
|
|
// Don't worry about what the emails might want to replace. Just give them everything and let them sort it out. |
727
|
|
|
$replacements = array( |
728
|
1 |
|
'REALNAME' => $regOptions['register_vars']['real_name'], |
729
|
1 |
|
'USERNAME' => $regOptions['username'], |
730
|
1 |
|
'PASSWORD' => $regOptions['password'], |
731
|
1 |
|
'FORGOTPASSWORDLINK' => $scripturl . '?action=reminder', |
732
|
1 |
|
'ACTIVATIONLINK' => $scripturl . '?action=register;sa=activate;u=' . $memberID . ';code=' . $validation_code, |
733
|
1 |
|
'ACTIVATIONLINKWITHOUTCODE' => $scripturl . '?action=register;sa=activate;u=' . $memberID, |
734
|
1 |
|
'ACTIVATIONCODE' => $validation_code, |
735
|
1 |
|
'OPENID' => !empty($regOptions['openid']) ? $regOptions['openid'] : '', |
736
|
1 |
|
'COPPALINK' => $scripturl . '?action=register;sa=coppa;u=' . $memberID, |
737
|
1 |
|
); |
738
|
|
|
|
739
|
|
|
// Administrative registrations are a bit different... |
740
|
1 |
|
if ($regOptions['interface'] == 'admin') |
741
|
1 |
|
{ |
742
|
|
|
if ($regOptions['require'] == 'activation') |
743
|
|
|
$email_message = 'admin_register_activate'; |
744
|
|
|
elseif (!empty($regOptions['send_welcome_email'])) |
745
|
|
|
$email_message = 'admin_register_immediate'; |
746
|
|
|
|
747
|
|
|
if (isset($email_message)) |
748
|
|
|
{ |
749
|
|
|
$emaildata = loadEmailTemplate($email_message, $replacements); |
750
|
|
|
|
751
|
|
|
sendmail($regOptions['email'], $emaildata['subject'], $emaildata['body'], null, null, false, 0); |
752
|
|
|
} |
753
|
|
|
} |
754
|
|
|
else |
755
|
|
|
{ |
756
|
|
|
// Can post straight away - welcome them to your fantastic community... |
757
|
1 |
|
if ($regOptions['require'] == 'nothing') |
758
|
1 |
|
{ |
759
|
1 |
|
if (!empty($regOptions['send_welcome_email'])) |
760
|
1 |
|
{ |
761
|
|
|
$replacements = array( |
762
|
|
|
'REALNAME' => $regOptions['register_vars']['real_name'], |
763
|
|
|
'USERNAME' => $regOptions['username'], |
764
|
|
|
'PASSWORD' => $regOptions['password'], |
765
|
|
|
'FORGOTPASSWORDLINK' => $scripturl . '?action=reminder', |
766
|
|
|
'OPENID' => !empty($regOptions['openid']) ? $regOptions['openid'] : '', |
767
|
|
|
); |
768
|
|
|
$emaildata = loadEmailTemplate('register_' . ($regOptions['auth_method'] == 'openid' ? 'openid_' : '') . 'immediate', $replacements); |
769
|
|
|
sendmail($regOptions['email'], $emaildata['subject'], $emaildata['body'], null, null, false, 0); |
770
|
|
|
} |
771
|
|
|
|
772
|
|
|
// Send admin their notification. |
773
|
1 |
|
require_once(SUBSDIR . '/Notification.subs.php'); |
774
|
1 |
|
sendAdminNotifications('standard', $memberID, $regOptions['username']); |
775
|
1 |
|
} |
776
|
|
|
// Need to activate their account - or fall under COPPA. |
777
|
|
|
elseif ($regOptions['require'] == 'activation' || $regOptions['require'] == 'coppa') |
778
|
|
|
{ |
779
|
|
|
|
780
|
|
|
$emaildata = loadEmailTemplate('register_' . ($regOptions['auth_method'] == 'openid' ? 'openid_' : '') . ($regOptions['require'] == 'activation' ? 'activate' : 'coppa'), $replacements); |
781
|
|
|
|
782
|
|
|
sendmail($regOptions['email'], $emaildata['subject'], $emaildata['body'], null, null, false, 0); |
783
|
|
|
} |
784
|
|
|
// Must be awaiting approval. |
785
|
|
|
else |
786
|
|
|
{ |
787
|
|
|
$replacements = array( |
788
|
|
|
'REALNAME' => $regOptions['register_vars']['real_name'], |
789
|
|
|
'USERNAME' => $regOptions['username'], |
790
|
|
|
'PASSWORD' => $regOptions['password'], |
791
|
|
|
'FORGOTPASSWORDLINK' => $scripturl . '?action=reminder', |
792
|
|
|
'OPENID' => !empty($regOptions['openid']) ? $regOptions['openid'] : '', |
793
|
|
|
); |
794
|
|
|
|
795
|
|
|
$emaildata = loadEmailTemplate('register_' . ($regOptions['auth_method'] == 'openid' ? 'openid_' : '') . 'pending', $replacements); |
796
|
|
|
|
797
|
|
|
sendmail($regOptions['email'], $emaildata['subject'], $emaildata['body'], null, null, false, 0); |
798
|
|
|
|
799
|
|
|
// Admin gets informed here... |
800
|
|
|
require_once(SUBSDIR . '/Notification.subs.php'); |
801
|
|
|
sendAdminNotifications('approval', $memberID, $regOptions['username']); |
802
|
|
|
} |
803
|
|
|
|
804
|
|
|
// Okay, they're for sure registered... make sure the session is aware of this for security. (Just married :P!) |
805
|
1 |
|
$_SESSION['just_registered'] = 1; |
806
|
|
|
} |
807
|
|
|
|
808
|
|
|
// If they are for sure registered, let other people to know about it |
809
|
1 |
|
call_integration_hook('integrate_register_after', array($regOptions, $memberID)); |
810
|
|
|
|
811
|
1 |
|
return $memberID; |
812
|
|
|
} |
813
|
|
|
|
814
|
|
|
/** |
815
|
|
|
* Check if a name is in the reserved words list. (name, current member id, name/username?.) |
816
|
|
|
* |
817
|
|
|
* - checks if name is a reserved name or username. |
818
|
|
|
* - if is_name is false, the name is assumed to be a username. |
819
|
|
|
* - the id_member variable is used to ignore duplicate matches with the current member. |
820
|
|
|
* |
821
|
|
|
* @package Members |
822
|
|
|
* |
823
|
|
|
* @param string $name |
824
|
|
|
* @param int $current_ID_MEMBER |
825
|
|
|
* @param bool $is_name |
826
|
|
|
* @param bool $fatal |
827
|
|
|
* |
828
|
|
|
* @return bool |
829
|
|
|
* @throws Elk_Exception username_reserved, name_censored |
830
|
|
|
*/ |
831
|
|
|
function isReservedName($name, $current_ID_MEMBER = 0, $is_name = true, $fatal = true) |
832
|
|
|
{ |
833
|
1 |
|
global $modSettings; |
834
|
|
|
|
835
|
1 |
|
$db = database(); |
836
|
|
|
|
837
|
1 |
|
$name = preg_replace_callback('~(&#(\d{1,7}|x[0-9a-fA-F]{1,6});)~', 'replaceEntities__callback', $name); |
838
|
1 |
|
$checkName = Util::strtolower($name); |
839
|
|
|
|
840
|
|
|
// Administrators are never restricted ;). |
841
|
1 |
|
if (!allowedTo('admin_forum') && ((!empty($modSettings['reserveName']) && $is_name) || !empty($modSettings['reserveUser']) && !$is_name)) |
842
|
1 |
|
{ |
843
|
1 |
|
$reservedNames = explode("\n", $modSettings['reserveNames']); |
844
|
|
|
// Case sensitive check? |
845
|
1 |
|
$checkMe = empty($modSettings['reserveCase']) ? $checkName : $name; |
846
|
|
|
|
847
|
|
|
// Check each name in the list... |
848
|
1 |
|
foreach ($reservedNames as $reserved) |
849
|
|
|
{ |
850
|
1 |
|
if ($reserved == '') |
851
|
1 |
|
continue; |
852
|
|
|
|
853
|
|
|
// The admin might've used entities too, level the playing field. |
854
|
1 |
|
$reservedCheck = preg_replace_callback('~(&#(\d{1,7}|x[0-9a-fA-F]{1,6});)~', 'replaceEntities__callback', $reserved); |
855
|
|
|
|
856
|
|
|
// Case sensitive name? |
857
|
1 |
|
if (empty($modSettings['reserveCase'])) |
858
|
1 |
|
$reservedCheck = Util::strtolower($reservedCheck); |
859
|
|
|
|
860
|
|
|
// If it's not just entire word, check for it in there somewhere... |
861
|
1 |
|
if ($checkMe == $reservedCheck || (Util::strpos($checkMe, $reservedCheck) !== false && empty($modSettings['reserveWord']))) |
862
|
1 |
|
if ($fatal) |
863
|
|
|
throw new Elk_Exception('username_reserved', 'password', array($reserved)); |
864
|
|
|
else |
865
|
|
|
return true; |
866
|
1 |
|
} |
867
|
|
|
|
868
|
1 |
|
$censor_name = $name; |
869
|
1 |
|
if (censor($censor_name) != $name) |
870
|
1 |
|
if ($fatal) |
871
|
|
|
throw new Elk_Exception('name_censored', 'password', array($name)); |
872
|
|
|
else |
873
|
|
|
return true; |
874
|
1 |
|
} |
875
|
|
|
|
876
|
|
|
// Characters we just shouldn't allow, regardless. |
877
|
1 |
|
foreach (array('*') as $char) |
878
|
1 |
|
if (strpos($checkName, $char) !== false) |
879
|
1 |
|
if ($fatal) |
880
|
|
|
throw new Elk_Exception('username_reserved', 'password', array($char)); |
881
|
|
|
else |
882
|
|
|
return true; |
883
|
|
|
|
884
|
|
|
// Get rid of any SQL parts of the reserved name... |
885
|
1 |
|
$checkName = strtr($name, array('_' => '\\_', '%' => '\\%')); |
886
|
|
|
|
887
|
|
|
// Make sure they don't want someone else's name. |
888
|
1 |
|
$request = $db->query('', ' |
889
|
|
|
SELECT id_member |
890
|
|
|
FROM {db_prefix}members |
891
|
1 |
|
WHERE ' . (empty($current_ID_MEMBER) ? '' : 'id_member != {int:current_member} |
892
|
1 |
|
AND ') . '({raw:real_name} LIKE {string:check_name} OR {raw:member_name} LIKE {string:check_name}) |
893
|
1 |
|
LIMIT 1', |
894
|
|
|
array( |
895
|
1 |
|
'real_name' => defined('DB_CASE_SENSITIVE') ? 'LOWER(real_name)' : 'real_name', |
896
|
1 |
|
'member_name' => defined('DB_CASE_SENSITIVE') ? 'LOWER(member_name)' : 'member_name', |
897
|
1 |
|
'current_member' => $current_ID_MEMBER, |
898
|
1 |
|
'check_name' => $checkName, |
899
|
|
|
) |
900
|
1 |
|
); |
901
|
1 |
|
if ($db->num_rows($request) > 0) |
902
|
1 |
|
{ |
903
|
|
|
$db->free_result($request); |
904
|
|
|
return true; |
905
|
|
|
} |
906
|
|
|
|
907
|
|
|
// Does name case insensitive match a member group name? |
908
|
1 |
|
$request = $db->query('', ' |
909
|
|
|
SELECT id_group |
910
|
|
|
FROM {db_prefix}membergroups |
911
|
|
|
WHERE {raw:group_name} LIKE {string:check_name} |
912
|
1 |
|
LIMIT 1', |
913
|
|
|
array( |
914
|
1 |
|
'group_name' => defined('DB_CASE_SENSITIVE') ? 'LOWER(group_name)' : 'group_name', |
915
|
1 |
|
'check_name' => $checkName, |
916
|
|
|
) |
917
|
1 |
|
); |
918
|
1 |
|
if ($db->num_rows($request) > 0) |
919
|
1 |
|
{ |
920
|
|
|
$db->free_result($request); |
921
|
|
|
return true; |
922
|
|
|
} |
923
|
|
|
|
924
|
|
|
// Okay, they passed. |
925
|
1 |
|
return false; |
926
|
|
|
} |
927
|
|
|
|
928
|
|
|
/** |
929
|
|
|
* Retrieves a list of membergroups that are allowed to do the given |
930
|
|
|
* permission. (on the given board) |
931
|
|
|
* |
932
|
|
|
* - If board_id is not null, a board permission is assumed. |
933
|
|
|
* - The function takes different permission settings into account. |
934
|
|
|
* |
935
|
|
|
* @package Members |
936
|
|
|
* |
937
|
|
|
* @param string $permission |
938
|
|
|
* @param integer|null $board_id = null |
939
|
|
|
* |
940
|
|
|
* @return array containing an array for the allowed membergroup ID's |
941
|
|
|
* and an array for the denied membergroup ID's. |
942
|
|
|
* @throws Elk_Exception no_board |
943
|
|
|
*/ |
944
|
|
|
function groupsAllowedTo($permission, $board_id = null) |
945
|
|
|
{ |
946
|
|
|
global $board_info; |
947
|
|
|
|
948
|
|
|
$db = database(); |
949
|
|
|
|
950
|
|
|
// Admins are allowed to do anything. |
951
|
|
|
$member_groups = array( |
952
|
|
|
'allowed' => array(1), |
953
|
|
|
'denied' => array(), |
954
|
|
|
); |
955
|
|
|
|
956
|
|
|
// Assume we're dealing with regular permissions (like profile_view_own). |
957
|
|
|
if ($board_id === null) |
958
|
|
|
{ |
959
|
|
|
$request = $db->query('', ' |
960
|
|
|
SELECT id_group, add_deny |
961
|
|
|
FROM {db_prefix}permissions |
962
|
|
|
WHERE permission = {string:permission}', |
963
|
|
|
array( |
964
|
|
|
'permission' => $permission, |
965
|
|
|
) |
966
|
|
|
); |
967
|
|
View Code Duplication |
while ($row = $db->fetch_assoc($request)) |
968
|
|
|
$member_groups[$row['add_deny'] === '1' ? 'allowed' : 'denied'][] = $row['id_group']; |
969
|
|
|
$db->free_result($request); |
970
|
|
|
} |
971
|
|
|
|
972
|
|
|
// Otherwise it's time to look at the board. |
973
|
|
|
else |
974
|
|
|
{ |
975
|
|
|
// First get the profile of the given board. |
976
|
|
|
if (isset($board_info['id']) && $board_info['id'] == $board_id) |
977
|
|
|
$profile_id = $board_info['profile']; |
978
|
|
|
elseif ($board_id !== 0) |
979
|
|
|
{ |
980
|
|
|
require_once(SUBSDIR . '/Boards.subs.php'); |
981
|
|
|
$board_data = fetchBoardsInfo(array('boards' => $board_id), array('selects' => 'permissions')); |
982
|
|
|
|
983
|
|
|
if (empty($board_data)) |
984
|
|
|
throw new Elk_Exception('no_board'); |
985
|
|
|
$profile_id = $board_data[$board_id]['id_profile']; |
986
|
|
|
} |
987
|
|
|
else |
988
|
|
|
$profile_id = 1; |
989
|
|
|
|
990
|
|
|
$request = $db->query('', ' |
991
|
|
|
SELECT bp.id_group, bp.add_deny |
992
|
|
|
FROM {db_prefix}board_permissions AS bp |
993
|
|
|
WHERE bp.permission = {string:permission} |
994
|
|
|
AND bp.id_profile = {int:profile_id}', |
995
|
|
|
array( |
996
|
|
|
'profile_id' => $profile_id, |
997
|
|
|
'permission' => $permission, |
998
|
|
|
) |
999
|
|
|
); |
1000
|
|
View Code Duplication |
while ($row = $db->fetch_assoc($request)) |
1001
|
|
|
$member_groups[$row['add_deny'] === '1' ? 'allowed' : 'denied'][] = $row['id_group']; |
1002
|
|
|
$db->free_result($request); |
1003
|
|
|
} |
1004
|
|
|
|
1005
|
|
|
// Denied is never allowed. |
1006
|
|
|
$member_groups['allowed'] = array_diff($member_groups['allowed'], $member_groups['denied']); |
1007
|
|
|
|
1008
|
|
|
return $member_groups; |
1009
|
|
|
} |
1010
|
|
|
|
1011
|
|
|
/** |
1012
|
|
|
* Retrieves a list of members that have a given permission (on a given board). |
1013
|
|
|
* |
1014
|
|
|
* - If board_id is not null, a board permission is assumed. |
1015
|
|
|
* - Takes different permission settings into account. |
1016
|
|
|
* - Takes possible moderators (on board 'board_id') into account. |
1017
|
|
|
* |
1018
|
|
|
* @package Members |
1019
|
|
|
* @param string $permission |
1020
|
|
|
* @param integer|null $board_id = null |
1021
|
|
|
* |
1022
|
|
|
* @return int[] an array containing member ID's. |
1023
|
|
|
* @throws Elk_Exception |
1024
|
|
|
*/ |
1025
|
|
|
function membersAllowedTo($permission, $board_id = null) |
1026
|
|
|
{ |
1027
|
|
|
$db = database(); |
1028
|
|
|
|
1029
|
|
|
$member_groups = groupsAllowedTo($permission, $board_id); |
1030
|
|
|
|
1031
|
|
|
$include_moderators = in_array(3, $member_groups['allowed']) && $board_id !== null; |
1032
|
|
|
$member_groups['allowed'] = array_diff($member_groups['allowed'], array(3)); |
1033
|
|
|
|
1034
|
|
|
$exclude_moderators = in_array(3, $member_groups['denied']) && $board_id !== null; |
1035
|
|
|
$member_groups['denied'] = array_diff($member_groups['denied'], array(3)); |
1036
|
|
|
|
1037
|
|
|
return $db->fetchQueryCallback(' |
1038
|
|
|
SELECT mem.id_member |
1039
|
|
|
FROM {db_prefix}members AS mem' . ($include_moderators || $exclude_moderators ? ' |
1040
|
|
|
LEFT JOIN {db_prefix}moderators AS mods ON (mods.id_member = mem.id_member AND mods.id_board = {int:board_id})' : '') . ' |
1041
|
|
|
WHERE (' . ($include_moderators ? 'mods.id_member IS NOT NULL OR ' : '') . 'mem.id_group IN ({array_int:member_groups_allowed}) OR FIND_IN_SET({raw:member_group_allowed_implode}, mem.additional_groups) != 0 OR mem.id_post_group IN ({array_int:member_groups_allowed}))' . (empty($member_groups['denied']) ? '' : ' |
1042
|
|
|
AND NOT (' . ($exclude_moderators ? 'mods.id_member IS NOT NULL OR ' : '') . 'mem.id_group IN ({array_int:member_groups_denied}) OR FIND_IN_SET({raw:member_group_denied_implode}, mem.additional_groups) != 0 OR mem.id_post_group IN ({array_int:member_groups_denied}))'), |
1043
|
|
|
array( |
1044
|
|
|
'member_groups_allowed' => $member_groups['allowed'], |
1045
|
|
|
'member_groups_denied' => $member_groups['denied'], |
1046
|
|
|
'board_id' => $board_id, |
1047
|
|
|
'member_group_allowed_implode' => implode(', mem.additional_groups) != 0 OR FIND_IN_SET(', $member_groups['allowed']), |
1048
|
|
|
'member_group_denied_implode' => implode(', mem.additional_groups) != 0 OR FIND_IN_SET(', $member_groups['denied']), |
1049
|
|
|
), |
1050
|
|
|
function ($row) |
1051
|
|
|
{ |
1052
|
|
|
return $row['id_member']; |
1053
|
|
|
} |
1054
|
|
|
); |
1055
|
|
|
} |
1056
|
|
|
|
1057
|
|
|
/** |
1058
|
|
|
* This function is used to re-associate members with relevant posts. |
1059
|
|
|
* |
1060
|
|
|
* - Re-attribute guest posts to a specified member. |
1061
|
|
|
* - Does not check for any permissions. |
1062
|
|
|
* - If add_to_post_count is set, the member's post count is increased. |
1063
|
|
|
* |
1064
|
|
|
* @package Members |
1065
|
|
|
* |
1066
|
|
|
* @param int $memID |
1067
|
|
|
* @param bool|false|string $email = false |
1068
|
|
|
* @param bool|false|string $membername = false |
1069
|
|
|
* @param bool $post_count = false |
1070
|
|
|
*/ |
1071
|
|
|
function reattributePosts($memID, $email = false, $membername = false, $post_count = false) |
1072
|
|
|
{ |
1073
|
|
|
$db = database(); |
1074
|
|
|
|
1075
|
|
|
// Firstly, if email and username aren't passed find out the members email address and name. |
1076
|
|
|
if ($email === false && $membername === false) |
1077
|
|
|
{ |
1078
|
|
|
require_once(SUBSDIR . '/Members.subs.php'); |
1079
|
|
|
$result = getBasicMemberData($memID); |
1080
|
|
|
$email = $result['email_address']; |
1081
|
|
|
$membername = $result['member_name']; |
1082
|
|
|
} |
1083
|
|
|
|
1084
|
|
|
// If they want the post count restored then we need to do some research. |
1085
|
|
|
if ($post_count) |
1086
|
|
|
{ |
1087
|
|
|
$request = $db->query('', ' |
1088
|
|
|
SELECT COUNT(*) |
1089
|
|
|
FROM {db_prefix}messages AS m |
1090
|
|
|
INNER JOIN {db_prefix}boards AS b ON (b.id_board = m.id_board AND b.count_posts = {int:count_posts}) |
1091
|
|
|
WHERE m.id_member = {int:guest_id} |
1092
|
|
|
AND m.approved = {int:is_approved} |
1093
|
|
|
AND m.icon != {string:recycled_icon}' . (empty($email) ? '' : ' |
1094
|
|
|
AND m.poster_email = {string:email_address}') . (empty($membername) ? '' : ' |
1095
|
|
|
AND m.poster_name = {string:member_name}'), |
1096
|
|
|
array( |
1097
|
|
|
'count_posts' => 0, |
1098
|
|
|
'guest_id' => 0, |
1099
|
|
|
'email_address' => $email, |
1100
|
|
|
'member_name' => $membername, |
1101
|
|
|
'is_approved' => 1, |
1102
|
|
|
'recycled_icon' => 'recycled', |
1103
|
|
|
) |
1104
|
|
|
); |
1105
|
|
|
list ($messageCount) = $db->fetch_row($request); |
1106
|
|
|
$db->free_result($request); |
1107
|
|
|
|
1108
|
|
|
updateMemberData($memID, array('posts' => 'posts + ' . $messageCount)); |
1109
|
|
|
} |
1110
|
|
|
|
1111
|
|
|
$query_parts = array(); |
1112
|
|
|
if (!empty($email)) |
1113
|
|
|
$query_parts[] = 'poster_email = {string:email_address}'; |
1114
|
|
|
if (!empty($membername)) |
1115
|
|
|
$query_parts[] = 'poster_name = {string:member_name}'; |
1116
|
|
|
$query = implode(' AND ', $query_parts); |
1117
|
|
|
|
1118
|
|
|
// Finally, update the posts themselves! |
1119
|
|
|
$db->query('', ' |
1120
|
|
|
UPDATE {db_prefix}messages |
1121
|
|
|
SET id_member = {int:memID} |
1122
|
|
|
WHERE ' . $query, |
1123
|
|
|
array( |
1124
|
|
|
'memID' => $memID, |
1125
|
|
|
'email_address' => $email, |
1126
|
|
|
'member_name' => $membername, |
1127
|
|
|
) |
1128
|
|
|
); |
1129
|
|
|
|
1130
|
|
|
// ...and the topics too! |
1131
|
|
|
$db->query('', ' |
1132
|
|
|
UPDATE {db_prefix}topics as t, {db_prefix}messages as m |
1133
|
|
|
SET t.id_member_started = {int:memID} |
1134
|
|
|
WHERE m.id_member = {int:memID} |
1135
|
|
|
AND t.id_first_msg = m.id_msg', |
1136
|
|
|
array( |
1137
|
|
|
'memID' => $memID, |
1138
|
|
|
) |
1139
|
|
|
); |
1140
|
|
|
|
1141
|
|
|
// Allow mods with their own post tables to re-attribute posts as well :) |
1142
|
|
|
call_integration_hook('integrate_reattribute_posts', array($memID, $email, $membername, $post_count)); |
1143
|
|
|
} |
1144
|
|
|
|
1145
|
|
|
/** |
1146
|
|
|
* Gets a listing of members, Callback for createList(). |
1147
|
|
|
* |
1148
|
|
|
* @package Members |
1149
|
|
|
* @param int $start The item to start with (for pagination purposes) |
1150
|
|
|
* @param int $items_per_page The number of items to show per page |
1151
|
|
|
* @param string $sort A string indicating how to sort the results |
1152
|
|
|
* @param string $where |
1153
|
|
|
* @param mixed[] $where_params |
1154
|
|
|
* @param boolean $get_duplicates |
1155
|
|
|
*/ |
1156
|
|
|
function list_getMembers($start, $items_per_page, $sort, $where, $where_params = array(), $get_duplicates = false) |
1157
|
|
|
{ |
1158
|
|
|
$db = database(); |
1159
|
|
|
|
1160
|
|
|
$members = $db->fetchQuery(' |
1161
|
|
|
SELECT |
1162
|
|
|
mem.id_member, mem.member_name, mem.real_name, mem.email_address, mem.member_ip, mem.member_ip2, mem.last_login, |
1163
|
|
|
mem.posts, mem.is_activated, mem.date_registered, mem.id_group, mem.additional_groups, mg.group_name |
1164
|
|
|
FROM {db_prefix}members AS mem |
1165
|
|
|
LEFT JOIN {db_prefix}membergroups AS mg ON (mg.id_group = mem.id_group) |
1166
|
|
|
WHERE ' . ($where == '1' ? '1=1' : $where) . ' |
1167
|
|
|
ORDER BY {raw:sort} |
1168
|
|
|
LIMIT {int:start}, {int:per_page}', |
1169
|
|
|
array_merge($where_params, array( |
1170
|
|
|
'sort' => $sort, |
1171
|
|
|
'start' => $start, |
1172
|
|
|
'per_page' => $items_per_page, |
1173
|
|
|
)) |
1174
|
|
|
); |
1175
|
|
|
|
1176
|
|
|
// If we want duplicates pass the members array off. |
1177
|
|
|
if ($get_duplicates) |
1178
|
|
|
populateDuplicateMembers($members); |
1179
|
|
|
|
1180
|
|
|
return $members; |
1181
|
|
|
} |
1182
|
|
|
|
1183
|
|
|
/** |
1184
|
|
|
* Gets the number of members, Callback for createList(). |
1185
|
|
|
* |
1186
|
|
|
* @package Members |
1187
|
|
|
* @param string $where |
1188
|
|
|
* @param mixed[] $where_params |
1189
|
|
|
*/ |
1190
|
|
|
function list_getNumMembers($where, $where_params = array()) |
1191
|
|
|
{ |
1192
|
|
|
global $modSettings; |
1193
|
|
|
|
1194
|
|
|
$db = database(); |
1195
|
|
|
|
1196
|
|
|
// We know how many members there are in total. |
1197
|
|
|
if (empty($where) || $where == '1=1') |
1198
|
|
|
$num_members = $modSettings['totalMembers']; |
1199
|
|
|
|
1200
|
|
|
// The database knows the amount when there are extra conditions. |
1201
|
|
|
else |
1202
|
|
|
{ |
1203
|
|
|
$request = $db->query('', ' |
1204
|
|
|
SELECT COUNT(*) |
1205
|
|
|
FROM {db_prefix}members AS mem |
1206
|
|
|
WHERE ' . $where, |
1207
|
|
|
array_merge($where_params, array( |
1208
|
|
|
)) |
1209
|
|
|
); |
1210
|
|
|
list ($num_members) = $db->fetch_row($request); |
1211
|
|
|
$db->free_result($request); |
1212
|
|
|
} |
1213
|
|
|
|
1214
|
|
|
return $num_members; |
1215
|
|
|
} |
1216
|
|
|
|
1217
|
|
|
/** |
1218
|
|
|
* Find potential duplicate registration members based on the same IP address |
1219
|
|
|
* |
1220
|
|
|
* @package Members |
1221
|
|
|
* @param mixed[] $members |
1222
|
|
|
*/ |
1223
|
|
|
function populateDuplicateMembers(&$members) |
1224
|
|
|
{ |
1225
|
|
|
$db = database(); |
1226
|
|
|
|
1227
|
|
|
// This will hold all the ip addresses. |
1228
|
|
|
$ips = array(); |
1229
|
|
|
foreach ($members as $key => $member) |
1230
|
|
|
{ |
1231
|
|
|
// Create the duplicate_members element. |
1232
|
|
|
$members[$key]['duplicate_members'] = array(); |
1233
|
|
|
|
1234
|
|
|
// Store the IPs. |
1235
|
|
|
if (!empty($member['member_ip'])) |
1236
|
|
|
$ips[] = $member['member_ip']; |
1237
|
|
|
if (!empty($member['member_ip2'])) |
1238
|
|
|
$ips[] = $member['member_ip2']; |
1239
|
|
|
} |
1240
|
|
|
|
1241
|
|
|
$ips = array_unique($ips); |
1242
|
|
|
|
1243
|
|
|
if (empty($ips)) |
1244
|
|
|
return false; |
1245
|
|
|
|
1246
|
|
|
// Fetch all members with this IP address, we'll filter out the current ones in a sec. |
1247
|
|
|
$potential_dupes = membersByIP($ips, 'exact', true); |
1248
|
|
|
|
1249
|
|
|
$duplicate_members = array(); |
1250
|
|
|
$duplicate_ids = array(); |
1251
|
|
|
foreach ($potential_dupes as $row) |
1252
|
|
|
{ |
1253
|
|
|
//$duplicate_ids[] = $row['id_member']; |
1254
|
|
|
|
1255
|
|
|
$member_context = array( |
1256
|
|
|
'id' => $row['id_member'], |
1257
|
|
|
'name' => $row['member_name'], |
1258
|
|
|
'email' => $row['email_address'], |
1259
|
|
|
'is_banned' => $row['is_activated'] > 10, |
1260
|
|
|
'ip' => $row['member_ip'], |
1261
|
|
|
'ip2' => $row['member_ip2'], |
1262
|
|
|
); |
1263
|
|
|
|
1264
|
|
|
if (in_array($row['member_ip'], $ips)) |
1265
|
|
|
$duplicate_members[$row['member_ip']][] = $member_context; |
1266
|
|
|
if ($row['member_ip'] != $row['member_ip2'] && in_array($row['member_ip2'], $ips)) |
1267
|
|
|
$duplicate_members[$row['member_ip2']][] = $member_context; |
1268
|
|
|
} |
1269
|
|
|
|
1270
|
|
|
// Also try to get a list of messages using these ips. |
1271
|
|
|
$request = $db->query('', ' |
1272
|
|
|
SELECT |
1273
|
|
|
m.poster_ip, mem.id_member, mem.member_name, mem.email_address, mem.is_activated |
1274
|
|
|
FROM {db_prefix}messages AS m |
1275
|
|
|
INNER JOIN {db_prefix}members AS mem ON (mem.id_member = m.id_member) |
1276
|
|
|
WHERE m.id_member != 0 |
1277
|
|
|
' . (!empty($duplicate_ids) ? 'AND m.id_member NOT IN ({array_int:duplicate_ids})' : '') . ' |
1278
|
|
|
AND m.poster_ip IN ({array_string:ips})', |
1279
|
|
|
array( |
1280
|
|
|
'duplicate_ids' => $duplicate_ids, |
1281
|
|
|
'ips' => $ips, |
1282
|
|
|
) |
1283
|
|
|
); |
1284
|
|
|
|
1285
|
|
|
$had_ips = array(); |
1286
|
|
|
while ($row = $db->fetch_assoc($request)) |
1287
|
|
|
{ |
1288
|
|
|
// Don't collect lots of the same. |
1289
|
|
|
if (isset($had_ips[$row['poster_ip']]) && in_array($row['id_member'], $had_ips[$row['poster_ip']])) |
1290
|
|
|
continue; |
1291
|
|
|
$had_ips[$row['poster_ip']][] = $row['id_member']; |
1292
|
|
|
|
1293
|
|
|
$duplicate_members[$row['poster_ip']][] = array( |
1294
|
|
|
'id' => $row['id_member'], |
1295
|
|
|
'name' => $row['member_name'], |
1296
|
|
|
'email' => $row['email_address'], |
1297
|
|
|
'is_banned' => $row['is_activated'] > 10, |
1298
|
|
|
'ip' => $row['poster_ip'], |
1299
|
|
|
'ip2' => $row['poster_ip'], |
1300
|
|
|
); |
1301
|
|
|
} |
1302
|
|
|
$db->free_result($request); |
1303
|
|
|
|
1304
|
|
|
// Now we have all the duplicate members, stick them with their respective member in the list. |
1305
|
|
|
if (!empty($duplicate_members)) |
1306
|
|
|
{ |
1307
|
|
|
foreach ($members as $key => $member) |
1308
|
|
|
{ |
1309
|
|
|
if (isset($duplicate_members[$member['member_ip']])) |
1310
|
|
|
$members[$key]['duplicate_members'] = $duplicate_members[$member['member_ip']]; |
1311
|
|
|
if ($member['member_ip'] != $member['member_ip2'] && isset($duplicate_members[$member['member_ip2']])) |
1312
|
|
|
$members[$key]['duplicate_members'] = array_merge($member['duplicate_members'], $duplicate_members[$member['member_ip2']]); |
1313
|
|
|
|
1314
|
|
|
// Check we don't have lots of the same member. |
1315
|
|
|
$member_track = array($member['id_member']); |
1316
|
|
|
foreach ($members[$key]['duplicate_members'] as $duplicate_id_member => $duplicate_member) |
1317
|
|
|
{ |
1318
|
|
|
if (in_array($duplicate_member['id'], $member_track)) |
1319
|
|
|
{ |
1320
|
|
|
unset($members[$key]['duplicate_members'][$duplicate_id_member]); |
1321
|
|
|
continue; |
1322
|
|
|
} |
1323
|
|
|
|
1324
|
|
|
$member_track[] = $duplicate_member['id']; |
1325
|
|
|
} |
1326
|
|
|
} |
1327
|
|
|
} |
1328
|
|
|
} |
1329
|
|
|
|
1330
|
|
|
/** |
1331
|
|
|
* Find members with a given IP (first, second, exact or "relaxed") |
1332
|
|
|
* |
1333
|
|
|
* @package Members |
1334
|
|
|
* @param string|string[] $ip1 An IP or an array of IPs |
1335
|
|
|
* @param string $match (optional, default 'exact') if the match should be exact |
1336
|
|
|
* of "relaxed" (using LIKE) |
1337
|
|
|
* @param bool $ip2 (optional, default false) If the query should check IP2 as well |
1338
|
|
|
*/ |
1339
|
|
|
function membersByIP($ip1, $match = 'exact', $ip2 = false) |
1340
|
|
|
{ |
1341
|
1 |
|
$db = database(); |
1342
|
|
|
|
1343
|
1 |
|
$ip_params = array('ips' => array()); |
1344
|
1 |
|
$ip_query = array(); |
1345
|
1 |
|
foreach (array($ip1, $ip2) as $id => $ip) |
1346
|
|
|
{ |
1347
|
1 |
|
if ($ip === false) |
1348
|
1 |
|
continue; |
1349
|
|
|
|
1350
|
1 |
|
if ($match === 'exact') |
1351
|
1 |
|
$ip_params['ips'] = array_merge($ip_params['ips'], (array) $ip); |
1352
|
|
|
else |
1353
|
|
|
{ |
1354
|
1 |
|
$ip = (array) $ip; |
1355
|
1 |
|
foreach ($ip as $id_var => $ip_var) |
1356
|
|
|
{ |
1357
|
1 |
|
$ip_var = str_replace('*', '%', $ip_var); |
1358
|
1 |
|
$ip_query[] = strpos($ip_var, '%') === false ? '= {string:ip_address_' . $id . '_' . $id_var . '}' : 'LIKE {string:ip_address_' . $id . '_' . $id_var . '}'; |
1359
|
1 |
|
$ip_params['ip_address_' . $id . '_' . $id_var] = $ip_var; |
1360
|
1 |
|
} |
1361
|
|
|
} |
1362
|
1 |
|
} |
1363
|
|
|
|
1364
|
1 |
|
if ($match === 'exact') |
1365
|
1 |
|
{ |
1366
|
1 |
|
$where = 'member_ip IN ({array_string:ips})'; |
1367
|
1 |
|
if ($ip2 !== false) |
1368
|
1 |
|
$where .= ' |
1369
|
1 |
|
OR member_ip2 IN ({array_string:ips})'; |
1370
|
1 |
|
} |
1371
|
|
|
else |
1372
|
|
|
{ |
1373
|
1 |
|
$where = 'member_ip ' . implode(' OR member_ip', $ip_query); |
1374
|
1 |
|
if ($ip2 !== false) |
1375
|
1 |
|
$where .= ' |
1376
|
|
|
OR member_ip2 ' . implode(' OR member_ip', $ip_query); |
1377
|
|
|
} |
1378
|
|
|
|
1379
|
1 |
|
return $db->fetchQuery(' |
1380
|
|
|
SELECT |
1381
|
|
|
id_member, member_name, email_address, member_ip, member_ip2, is_activated |
1382
|
|
|
FROM {db_prefix}members |
1383
|
1 |
|
WHERE ' . $where, |
1384
|
|
|
$ip_params |
1385
|
1 |
|
); |
1386
|
|
|
} |
1387
|
|
|
|
1388
|
|
|
/** |
1389
|
|
|
* Find out if there is another admin than the given user. |
1390
|
|
|
* |
1391
|
|
|
* @package Members |
1392
|
|
|
* @param int $memberID ID of the member, to compare with. |
1393
|
|
|
*/ |
1394
|
|
View Code Duplication |
function isAnotherAdmin($memberID) |
|
|
|
|
1395
|
|
|
{ |
1396
|
|
|
$db = database(); |
1397
|
|
|
|
1398
|
|
|
$request = $db->query('', ' |
1399
|
|
|
SELECT id_member |
1400
|
|
|
FROM {db_prefix}members |
1401
|
|
|
WHERE (id_group = {int:admin_group} OR FIND_IN_SET({int:admin_group}, additional_groups) != 0) |
1402
|
|
|
AND id_member != {int:selected_member} |
1403
|
|
|
LIMIT 1', |
1404
|
|
|
array( |
1405
|
|
|
'admin_group' => 1, |
1406
|
|
|
'selected_member' => $memberID, |
1407
|
|
|
) |
1408
|
|
|
); |
1409
|
|
|
list ($another) = $db->fetch_row($request); |
1410
|
|
|
$db->free_result($request); |
1411
|
|
|
|
1412
|
|
|
return $another; |
1413
|
|
|
} |
1414
|
|
|
|
1415
|
|
|
/** |
1416
|
|
|
* This function retrieves a list of member ids based on a set of conditions |
1417
|
|
|
* |
1418
|
|
|
* @package Members |
1419
|
|
|
* @param mixed[]|string $query see prepareMembersByQuery |
1420
|
|
|
* @param mixed[] $query_params see prepareMembersByQuery |
1421
|
|
|
* @param bool $details if true returns additional member details (name, email, ip, etc.) |
1422
|
|
|
* false will only return an array of member id's that match the conditions |
1423
|
|
|
* @param bool $only_active see prepareMembersByQuery |
1424
|
|
|
*/ |
1425
|
|
|
function membersBy($query, $query_params, $details = false, $only_active = true) |
1426
|
|
|
{ |
1427
|
|
|
$db = database(); |
1428
|
|
|
|
1429
|
|
|
$query_where = prepareMembersByQuery($query, $query_params, $only_active); |
1430
|
|
|
|
1431
|
|
|
// Lets see who we can find that meets the built up conditions |
1432
|
|
|
$members = array(); |
1433
|
|
|
$request = $db->query('', ' |
1434
|
|
|
SELECT id_member' . ($details ? ', member_name, real_name, email_address, member_ip, date_registered, last_login, |
1435
|
|
|
hide_email, posts, is_activated, real_name' : '') . ' |
1436
|
|
|
FROM {db_prefix}members |
1437
|
|
|
WHERE ' . $query_where . (isset($query_params['start']) ? ' |
1438
|
|
|
LIMIT {int:start}, {int:limit}' : '') . (!empty($query_params['order']) ? ' |
1439
|
|
|
ORDER BY {raw:order}' : ''), |
1440
|
|
|
$query_params |
1441
|
|
|
); |
1442
|
|
|
|
1443
|
|
|
// Return all the details for each member found |
1444
|
|
|
if ($details) |
1445
|
|
|
{ |
1446
|
|
|
while ($row = $db->fetch_assoc($request)) |
1447
|
|
|
$members[$row['id_member']] = $row; |
1448
|
|
|
} |
1449
|
|
|
// Or just a int[] of found member id's |
1450
|
|
|
else |
1451
|
|
|
{ |
1452
|
|
|
while ($row = $db->fetch_assoc($request)) |
1453
|
|
|
$members[] = $row['id_member']; |
1454
|
|
|
} |
1455
|
|
|
$db->free_result($request); |
1456
|
|
|
|
1457
|
|
|
return $members; |
1458
|
|
|
} |
1459
|
|
|
|
1460
|
|
|
/** |
1461
|
|
|
* Counts the number of members based on conditions |
1462
|
|
|
* |
1463
|
|
|
* @package Members |
1464
|
|
|
* @param string[]|string $query see prepareMembersByQuery |
1465
|
|
|
* @param mixed[] $query_params see prepareMembersByQuery |
1466
|
|
|
* @param boolean $only_active see prepareMembersByQuery |
1467
|
|
|
*/ |
1468
|
|
|
function countMembersBy($query, $query_params, $only_active = true) |
1469
|
|
|
{ |
1470
|
|
|
$db = database(); |
1471
|
|
|
|
1472
|
|
|
$query_where = prepareMembersByQuery($query, $query_params, $only_active); |
1473
|
|
|
|
1474
|
|
|
$request = $db->query('', ' |
1475
|
|
|
SELECT COUNT(*) |
1476
|
|
|
FROM {db_prefix}members |
1477
|
|
|
WHERE ' . $query_where, |
1478
|
|
|
$query_params |
1479
|
|
|
); |
1480
|
|
|
|
1481
|
|
|
list ($num_members) = $db->fetch_row($request); |
1482
|
|
|
$db->free_result($request); |
1483
|
|
|
|
1484
|
|
|
return $num_members; |
1485
|
|
|
} |
1486
|
|
|
|
1487
|
|
|
/** |
1488
|
|
|
* Builds the WHERE clause for the functions countMembersBy and membersBy |
1489
|
|
|
* |
1490
|
|
|
* @package Members |
1491
|
|
|
* @param mixed[]|string $query can be an array of "type" of conditions, |
1492
|
|
|
* or a string used as raw query |
1493
|
|
|
* or a string that represents one of the built-in conditions |
1494
|
|
|
* like member_names, not_in_group, etc |
1495
|
|
|
* @param mixed[] $query_params is an array containing the parameters passed to the query |
1496
|
|
|
* 'start' and 'limit' used in LIMIT |
1497
|
|
|
* 'order' used raw in ORDER BY |
1498
|
|
|
* others passed as query params |
1499
|
|
|
* @param bool $only_active only fetch active members |
1500
|
|
|
*/ |
1501
|
|
|
function prepareMembersByQuery($query, &$query_params, $only_active = true) |
1502
|
|
|
{ |
1503
|
|
|
$allowed_conditions = array( |
1504
|
|
|
'member_ids' => 'id_member IN ({array_int:member_ids})', |
1505
|
|
|
'member_names' => function (&$members) |
1506
|
|
|
{ |
1507
|
|
|
$mem_query = array(); |
1508
|
|
|
|
1509
|
|
|
foreach ($members['member_names'] as $key => $param) |
1510
|
|
|
{ |
1511
|
|
|
$mem_query[] = (defined('DB_CASE_SENSITIVE') ? 'LOWER(real_name)' : 'real_name') . ' LIKE {string:member_names_' . $key . '}'; |
1512
|
|
|
$members['member_names_' . $key] = defined('DB_CASE_SENSITIVE') ? strtolower($param) : $param; |
1513
|
|
|
} |
1514
|
|
|
return implode("\n\t\t\tOR ", $mem_query); |
1515
|
|
|
}, |
1516
|
|
|
'not_in_group' => '(id_group != {int:not_in_group} AND FIND_IN_SET({int:not_in_group}, additional_groups) = 0)', |
1517
|
|
|
'in_group' => '(id_group = {int:in_group} OR FIND_IN_SET({int:in_group}, additional_groups) != 0)', |
1518
|
|
|
'in_group_primary' => 'id_group = {int:in_group_primary}', |
1519
|
|
|
'in_post_group' => 'id_post_group = {int:in_post_group}', |
1520
|
|
|
'in_group_no_add' => '(id_group = {int:in_group_no_add} AND FIND_IN_SET({int:in_group_no_add}, additional_groups) = 0)', |
1521
|
|
|
); |
1522
|
|
|
|
1523
|
|
|
// Are there multiple parts to this query |
1524
|
|
|
if (is_array($query)) |
1525
|
|
|
{ |
1526
|
|
|
$query_parts = array('or' => array(), 'and' => array()); |
1527
|
|
|
foreach ($query as $type => $query_conditions) |
1528
|
|
|
{ |
1529
|
|
|
if (is_array($query_conditions)) |
1530
|
|
|
{ |
1531
|
|
|
foreach ($query_conditions as $condition => $query_condition) |
1532
|
|
|
{ |
1533
|
|
|
if ($query_condition == 'member_names') |
1534
|
|
|
$query_parts[$condition === 'or' ? 'or' : 'and'][] = $allowed_conditions[$query_condition]($query_params); |
1535
|
|
|
else |
1536
|
|
|
$query_parts[$condition === 'or' ? 'or' : 'and'][] = isset($allowed_conditions[$query_condition]) ? $allowed_conditions[$query_condition] : $query_condition; |
1537
|
|
|
} |
1538
|
|
|
} |
1539
|
|
|
elseif ($query == 'member_names') |
1540
|
|
|
$query_parts[$condition === 'or' ? 'or' : 'and'][] = $allowed_conditions[$query]($query_params); |
|
|
|
|
1541
|
|
|
else |
1542
|
|
|
$query_parts['and'][] = isset($allowed_conditions[$query]) ? $allowed_conditions[$query] : $query; |
1543
|
|
|
} |
1544
|
|
|
|
1545
|
|
|
if (!empty($query_parts['or'])) |
1546
|
|
|
$query_parts['and'][] = implode("\n\t\t\tOR ", $query_parts['or']); |
1547
|
|
|
|
1548
|
|
|
$query_where = implode("\n\t\t\tAND ", $query_parts['and']); |
1549
|
|
|
} |
1550
|
|
|
// Is it one of our predefined querys like member_ids, member_names, etc |
1551
|
|
|
elseif (isset($allowed_conditions[$query])) |
1552
|
|
|
{ |
1553
|
|
|
if ($query == 'member_names') |
1554
|
|
|
$query_where = $allowed_conditions[$query]($query_params); |
1555
|
|
|
else |
1556
|
|
|
$query_where = $allowed_conditions[$query]; |
1557
|
|
|
} |
1558
|
|
|
// Something else, be careful ;) |
1559
|
|
|
else |
1560
|
|
|
$query_where = $query; |
1561
|
|
|
|
1562
|
|
|
// Lazy loading, our favorite |
1563
|
|
|
if (empty($query_where)) |
1564
|
|
|
return false; |
1565
|
|
|
|
1566
|
|
|
// Only want active members |
1567
|
|
|
if ($only_active) |
1568
|
|
|
{ |
1569
|
|
|
$query_where .= ' |
1570
|
|
|
AND is_activated = {int:is_activated}'; |
1571
|
|
|
$query_params['is_activated'] = 1; |
1572
|
|
|
} |
1573
|
|
|
|
1574
|
|
|
return $query_where; |
1575
|
|
|
} |
1576
|
|
|
|
1577
|
|
|
/** |
1578
|
|
|
* Retrieve administrators of the site. |
1579
|
|
|
* |
1580
|
|
|
* - The function returns basic information: name, language file. |
1581
|
|
|
* - It is used in personal messages reporting. |
1582
|
|
|
* |
1583
|
|
|
* @package Members |
1584
|
|
|
* @param int $id_admin = 0 if requested, only data about a specific admin is retrieved |
1585
|
|
|
*/ |
1586
|
|
|
function admins($id_admin = 0) |
1587
|
|
|
{ |
1588
|
|
|
$db = database(); |
1589
|
|
|
|
1590
|
|
|
// Now let's get out and loop through the admins. |
1591
|
|
|
$request = $db->query('', ' |
1592
|
|
|
SELECT id_member, real_name, lngfile |
1593
|
|
|
FROM {db_prefix}members |
1594
|
|
|
WHERE (id_group = {int:admin_group} OR FIND_IN_SET({int:admin_group}, additional_groups) != 0) |
1595
|
|
|
' . (empty($id_admin) ? '' : 'AND id_member = {int:specific_admin}') . ' |
1596
|
|
|
ORDER BY real_name, lngfile', |
1597
|
|
|
array( |
1598
|
|
|
'admin_group' => 1, |
1599
|
|
|
'specific_admin' => isset($id_admin) ? (int) $id_admin : 0, |
1600
|
|
|
) |
1601
|
|
|
); |
1602
|
|
|
|
1603
|
|
|
$admins = array(); |
1604
|
|
|
while ($row = $db->fetch_assoc($request)) |
1605
|
|
|
$admins[$row['id_member']] = array($row['real_name'], $row['lngfile']); |
1606
|
|
|
$db->free_result($request); |
1607
|
|
|
|
1608
|
|
|
return $admins; |
1609
|
|
|
} |
1610
|
|
|
|
1611
|
|
|
/** |
1612
|
|
|
* Get the last known id_member |
1613
|
|
|
* @return int |
1614
|
|
|
*/ |
1615
|
|
View Code Duplication |
function maxMemberID() |
|
|
|
|
1616
|
|
|
{ |
1617
|
|
|
$db = database(); |
1618
|
|
|
|
1619
|
|
|
$request = $db->query('', ' |
1620
|
|
|
SELECT MAX(id_member) |
1621
|
|
|
FROM {db_prefix}members', |
1622
|
|
|
array( |
1623
|
|
|
) |
1624
|
|
|
); |
1625
|
|
|
list ($max_id) = $db->fetch_row($request); |
1626
|
|
|
$db->free_result($request); |
1627
|
|
|
|
1628
|
|
|
return $max_id; |
1629
|
|
|
} |
1630
|
|
|
|
1631
|
|
|
/** |
1632
|
|
|
* Load some basic member information |
1633
|
|
|
* |
1634
|
|
|
* @package Members |
1635
|
|
|
* @param int[]|int $member_ids an array of member IDs or a single ID |
1636
|
|
|
* @param mixed[] $options an array of possible little alternatives, can be: |
1637
|
|
|
* - 'add_guest' (bool) to add a guest user to the returned array |
1638
|
|
|
* - 'limit' int if set overrides the default query limit |
1639
|
|
|
* - 'sort' (string) a column to sort the results |
1640
|
|
|
* - 'moderation' (bool) includes member_ip, id_group, additional_groups, last_login |
1641
|
|
|
* - 'authentication' (bool) includes secret_answer, secret_question, openid_uri, |
1642
|
|
|
* is_activated, validation_code, passwd_flood |
1643
|
|
|
* - 'preferences' (bool) includes lngfile, mod_prefs, notify_types, signature |
1644
|
|
|
* @return array |
1645
|
|
|
*/ |
1646
|
|
|
function getBasicMemberData($member_ids, $options = array()) |
1647
|
|
|
{ |
1648
|
3 |
|
global $txt, $language; |
1649
|
|
|
|
1650
|
3 |
|
$db = database(); |
1651
|
|
|
|
1652
|
3 |
|
$members = array(); |
1653
|
|
|
|
1654
|
3 |
|
if (empty($member_ids)) |
1655
|
3 |
|
return false; |
1656
|
|
|
|
1657
|
3 |
|
if (!is_array($member_ids)) |
1658
|
3 |
|
{ |
1659
|
1 |
|
$single = true; |
1660
|
1 |
|
$member_ids = array($member_ids); |
1661
|
1 |
|
} |
1662
|
|
|
|
1663
|
3 |
|
if (!empty($options['add_guest'])) |
1664
|
3 |
|
{ |
1665
|
|
|
$single = false; |
1666
|
|
|
// This is a guest... |
1667
|
|
|
$members[0] = array( |
1668
|
|
|
'id_member' => 0, |
1669
|
|
|
'member_name' => '', |
1670
|
|
|
'real_name' => $txt['guest_title'], |
1671
|
|
|
'email_address' => '', |
1672
|
|
|
); |
1673
|
|
|
} |
1674
|
|
|
|
1675
|
|
|
// Get some additional member info... |
1676
|
3 |
|
$request = $db->query('', ' |
1677
|
3 |
|
SELECT id_member, member_name, real_name, email_address, hide_email, posts, id_theme' . (!empty($options['moderation']) ? ', |
1678
|
3 |
|
member_ip, id_group, additional_groups, last_login, id_post_group' : '') . (!empty($options['authentication']) ? ', |
1679
|
3 |
|
secret_answer, secret_question, openid_uri, is_activated, validation_code, passwd_flood' : '') . (!empty($options['preferences']) ? ', |
1680
|
3 |
|
lngfile, mod_prefs, notify_types, signature' : '') . ' |
1681
|
|
|
FROM {db_prefix}members |
1682
|
|
|
WHERE id_member IN ({array_int:member_list}) |
1683
|
3 |
|
' . (isset($options['sort']) ? ' |
1684
|
3 |
|
ORDER BY {raw:sort}' : '') . ' |
1685
|
3 |
|
LIMIT {int:limit}', |
1686
|
|
|
array( |
1687
|
3 |
|
'member_list' => $member_ids, |
1688
|
3 |
|
'limit' => isset($options['limit']) ? $options['limit'] : count($member_ids), |
1689
|
3 |
|
'sort' => isset($options['sort']) ? $options['sort'] : '', |
1690
|
|
|
) |
1691
|
3 |
|
); |
1692
|
3 |
|
while ($row = $db->fetch_assoc($request)) |
1693
|
|
|
{ |
1694
|
3 |
|
if (empty($row['lngfile'])) |
1695
|
3 |
|
$row['lngfile'] = $language; |
1696
|
|
|
|
1697
|
3 |
|
if (!empty($single)) |
1698
|
3 |
|
$members = $row; |
1699
|
|
|
else |
1700
|
2 |
|
$members[$row['id_member']] = $row; |
1701
|
3 |
|
} |
1702
|
3 |
|
$db->free_result($request); |
1703
|
|
|
|
1704
|
3 |
|
return $members; |
1705
|
|
|
} |
1706
|
|
|
|
1707
|
|
|
/** |
1708
|
|
|
* Counts all inactive members |
1709
|
|
|
* |
1710
|
|
|
* @package Members |
1711
|
|
|
* @return array $inactive_members |
1712
|
|
|
*/ |
1713
|
|
|
function countInactiveMembers() |
1714
|
|
|
{ |
1715
|
|
|
$db = database(); |
1716
|
|
|
|
1717
|
|
|
$inactive_members = array(); |
1718
|
|
|
|
1719
|
|
|
$request = $db->query('', ' |
1720
|
|
|
SELECT COUNT(*) AS total_members, is_activated |
1721
|
|
|
FROM {db_prefix}members |
1722
|
|
|
WHERE is_activated != {int:is_activated} |
1723
|
|
|
GROUP BY is_activated', |
1724
|
|
|
array( |
1725
|
|
|
'is_activated' => 1, |
1726
|
|
|
) |
1727
|
|
|
); |
1728
|
|
|
|
1729
|
|
|
while ($row = $db->fetch_assoc($request)) |
1730
|
|
|
$inactive_members[$row['is_activated']] = $row['total_members']; |
1731
|
|
|
$db->free_result($request); |
1732
|
|
|
|
1733
|
|
|
return $inactive_members; |
1734
|
|
|
} |
1735
|
|
|
|
1736
|
|
|
/** |
1737
|
|
|
* Get the member's id and group |
1738
|
|
|
* |
1739
|
|
|
* @package Members |
1740
|
|
|
* @param string $name |
1741
|
|
|
* @param bool $flexible if true searches for both real_name and member_name (default false) |
1742
|
|
|
* @return integer |
1743
|
|
|
*/ |
1744
|
|
|
function getMemberByName($name, $flexible = false) |
1745
|
|
|
{ |
1746
|
|
|
$db = database(); |
1747
|
|
|
|
1748
|
|
|
$request = $db->query('', ' |
1749
|
|
|
SELECT id_member, id_group |
1750
|
|
|
FROM {db_prefix}members |
1751
|
|
|
WHERE {raw:real_name} LIKE {string:name}' . ($flexible ? ' |
1752
|
|
|
OR {raw:member_name} LIKE {string:name}' : '') . ' |
1753
|
|
|
LIMIT 1', |
1754
|
|
|
array( |
1755
|
|
|
'name' => Util::strtolower($name), |
1756
|
|
|
'real_name' => defined('DB_CASE_SENSITIVE') ? 'LOWER(real_name)' : 'real_name', |
1757
|
|
|
'member_name' => defined('DB_CASE_SENSITIVE') ? 'LOWER(member_name)' : 'member_name', |
1758
|
|
|
) |
1759
|
|
|
); |
1760
|
|
|
if ($db->num_rows($request) == 0) |
1761
|
|
|
return false; |
1762
|
|
|
$member = $db->fetch_assoc($request); |
1763
|
|
|
$db->free_result($request); |
1764
|
|
|
|
1765
|
|
|
return $member; |
1766
|
|
|
} |
1767
|
|
|
|
1768
|
|
|
/** |
1769
|
|
|
* Finds a member from the database using supplied string as real_name |
1770
|
|
|
* |
1771
|
|
|
* - Optionally will only search/find the member in a buddy list |
1772
|
|
|
* |
1773
|
|
|
* @package Members |
1774
|
|
|
* @param string $search string to search real_name for like finds |
1775
|
|
|
* @param int[]|null $buddies |
1776
|
|
|
*/ |
1777
|
|
|
function getMember($search, $buddies = array()) |
1778
|
|
|
{ |
1779
|
|
|
$db = database(); |
1780
|
|
|
|
1781
|
|
|
$xml_data = array( |
1782
|
|
|
'items' => array( |
1783
|
|
|
'identifier' => 'item', |
1784
|
|
|
'children' => array(), |
1785
|
|
|
), |
1786
|
|
|
); |
1787
|
|
|
// Find the member. |
1788
|
|
|
$xml_data['items']['children'] = $db->fetchQueryCallback(' |
1789
|
|
|
SELECT id_member, real_name |
1790
|
|
|
FROM {db_prefix}members |
1791
|
|
|
WHERE {raw:real_name} LIKE {string:search}' . (!empty($buddies) ? ' |
1792
|
|
|
AND id_member IN ({array_int:buddy_list})' : '') . ' |
1793
|
|
|
AND is_activated IN ({array_int:activation_status}) |
1794
|
|
|
ORDER BY LENGTH(real_name), real_name |
1795
|
|
|
LIMIT {int:limit}', |
1796
|
|
|
array( |
1797
|
|
|
'real_name' => defined('DB_CASE_SENSITIVE') ? 'LOWER(real_name)' : 'real_name', |
1798
|
|
|
'buddy_list' => $buddies, |
1799
|
|
|
'search' => Util::strtolower($search), |
1800
|
|
|
'activation_status' => array(1, 12), |
1801
|
|
|
'limit' => Util::strlen($search) <= 2 ? 100 : 200, |
1802
|
|
|
), |
1803
|
|
|
function ($row) |
1804
|
|
|
{ |
1805
|
|
|
$row['real_name'] = strtr($row['real_name'], array('&' => '&', '<' => '<', '>' => '>', '"' => '"')); |
1806
|
|
|
|
1807
|
|
|
return array( |
1808
|
|
|
'attributes' => array( |
1809
|
|
|
'id' => $row['id_member'], |
1810
|
|
|
), |
1811
|
|
|
'value' => $row['real_name'], |
1812
|
|
|
); |
1813
|
|
|
} |
1814
|
|
|
); |
1815
|
|
|
|
1816
|
|
|
return $xml_data; |
1817
|
|
|
} |
1818
|
|
|
|
1819
|
|
|
/** |
1820
|
|
|
* Retrieves MemberData based on conditions |
1821
|
|
|
* |
1822
|
|
|
* @package Members |
1823
|
|
|
* @param mixed[] $conditions associative array holding the conditions for the WHERE clause of the query. |
1824
|
|
|
* Possible keys: |
1825
|
|
|
* - activated_status (boolean) must be present |
1826
|
|
|
* - time_before (integer) |
1827
|
|
|
* - members (array of integers) |
1828
|
|
|
* - member_greater (integer) a member id, it will be used to filter only members with id_member greater than this |
1829
|
|
|
* - group_list (array) array of group IDs |
1830
|
|
|
* - notify_announcements (integer) |
1831
|
|
|
* - order_by (string) |
1832
|
|
|
* - limit (int) |
1833
|
|
|
* @return array |
1834
|
|
|
*/ |
1835
|
|
|
function retrieveMemberData($conditions) |
1836
|
|
|
{ |
1837
|
|
|
global $modSettings, $language; |
1838
|
|
|
|
1839
|
|
|
// We badly need this |
1840
|
|
|
assert(isset($conditions['activated_status'])); |
1841
|
|
|
|
1842
|
|
|
$db = database(); |
1843
|
|
|
|
1844
|
|
|
$available_conditions = array( |
1845
|
|
|
'time_before' => ' |
1846
|
|
|
AND date_registered < {int:time_before}', |
1847
|
|
|
'members' => ' |
1848
|
|
|
AND id_member IN ({array_int:members})', |
1849
|
|
|
'member_greater' => ' |
1850
|
|
|
AND id_member > {int:member_greater}', |
1851
|
|
|
'member_greater_equal' => ' |
1852
|
|
|
AND id_member >= {int:member_greater_equal}', |
1853
|
|
|
'member_lesser' => ' |
1854
|
|
|
AND id_member < {int:member_lesser}', |
1855
|
|
|
'member_lesser_equal' => ' |
1856
|
|
|
AND id_member <= {int:member_lesser_equal}', |
1857
|
|
|
'group_list' => ' |
1858
|
|
|
AND (id_group IN ({array_int:group_list}) OR id_post_group IN ({array_int:group_list}) OR FIND_IN_SET({raw:additional_group_list}, additional_groups) != 0)', |
1859
|
|
|
'notify_announcements' => ' |
1860
|
|
|
AND notify_announcements = {int:notify_announcements}' |
1861
|
|
|
); |
1862
|
|
|
|
1863
|
|
|
$query_cond = array(); |
1864
|
|
|
foreach ($conditions as $key => $dummy) |
1865
|
|
|
if (isset($available_conditions[$key])) |
1866
|
|
|
$query_cond[] = $available_conditions[$key]; |
1867
|
|
|
|
1868
|
|
|
if (isset($conditions['group_list'])) |
1869
|
|
|
$conditions['additional_group_list'] = implode(', additional_groups) != 0 OR FIND_IN_SET(', $conditions['group_list']); |
1870
|
|
|
|
1871
|
|
|
$data = array(); |
1872
|
|
|
|
1873
|
|
|
if (!isset($conditions['order_by'])) |
1874
|
|
|
$conditions['order_by'] = 'lngfile'; |
1875
|
|
|
|
1876
|
|
|
$limit = (isset($conditions['limit'])) ? ' |
1877
|
|
|
LIMIT {int:limit}' : ''; |
1878
|
|
|
|
1879
|
|
|
// Get information on each of the members, things that are important to us, like email address... |
1880
|
|
|
$request = $db->query('', ' |
1881
|
|
|
SELECT id_member, member_name, real_name, email_address, validation_code, lngfile |
1882
|
|
|
FROM {db_prefix}members |
1883
|
|
|
WHERE is_activated = {int:activated_status}' . implode('', $query_cond) . ' |
1884
|
|
|
ORDER BY {raw:order_by}' . $limit, |
1885
|
|
|
$conditions |
1886
|
|
|
); |
1887
|
|
|
|
1888
|
|
|
$data['member_count'] = $db->num_rows($request); |
1889
|
|
|
|
1890
|
|
|
if ($data['member_count'] == 0) |
1891
|
|
|
return $data; |
1892
|
|
|
|
1893
|
|
|
// Fill the info array. |
1894
|
|
|
while ($row = $db->fetch_assoc($request)) |
1895
|
|
|
{ |
1896
|
|
|
$data['members'][] = $row['id_member']; |
1897
|
|
|
$data['member_info'][] = array( |
1898
|
|
|
'id' => $row['id_member'], |
1899
|
|
|
'username' => $row['member_name'], |
1900
|
|
|
'name' => $row['real_name'], |
1901
|
|
|
'email' => $row['email_address'], |
1902
|
|
|
'language' => empty($row['lngfile']) || empty($modSettings['userLanguage']) ? $language : $row['lngfile'], |
1903
|
|
|
'code' => $row['validation_code'] |
1904
|
|
|
); |
1905
|
|
|
} |
1906
|
|
|
$db->free_result($request); |
1907
|
|
|
|
1908
|
|
|
return $data; |
1909
|
|
|
} |
1910
|
|
|
|
1911
|
|
|
/** |
1912
|
|
|
* Activate members |
1913
|
|
|
* |
1914
|
|
|
* @package Members |
1915
|
|
|
* @param mixed[] $conditions associative array holding the conditions for the WHERE clause of the query. |
1916
|
|
|
* Possible keys: |
1917
|
|
|
* - activated_status (boolean) must be present |
1918
|
|
|
* - time_before (integer) |
1919
|
|
|
* - members (array of integers) |
1920
|
|
|
*/ |
1921
|
|
|
function approveMembers($conditions) |
1922
|
|
|
{ |
1923
|
|
|
$db = database(); |
1924
|
|
|
|
1925
|
|
|
// This shall be present |
1926
|
|
|
assert(isset($conditions['activated_status'])); |
1927
|
|
|
|
1928
|
|
|
$available_conditions = array( |
1929
|
|
|
'time_before' => ' |
1930
|
|
|
AND date_registered < {int:time_before}', |
1931
|
|
|
'members' => ' |
1932
|
|
|
AND id_member IN ({array_int:members})', |
1933
|
|
|
); |
1934
|
|
|
|
1935
|
|
|
// @todo maybe an hook here? |
1936
|
|
|
$query_cond = array(); |
1937
|
|
|
$query = false; |
1938
|
|
|
foreach ($conditions as $key => $dummy) |
1939
|
|
|
{ |
1940
|
|
|
if (isset($available_conditions[$key])) |
1941
|
|
|
{ |
1942
|
|
|
if ($key === 'time_before') |
1943
|
|
|
$query = true; |
1944
|
|
|
$query_cond[] = $available_conditions[$key]; |
1945
|
|
|
} |
1946
|
|
|
} |
1947
|
|
|
|
1948
|
|
|
if ($query) |
1949
|
|
|
{ |
1950
|
|
|
$data = retrieveMemberData($conditions); |
1951
|
|
|
$members_id = array(); |
1952
|
|
|
foreach ($data['member_info'] as $member) |
1953
|
|
|
$members_id[] = $member['username']; |
1954
|
|
|
} |
1955
|
|
|
else |
1956
|
|
|
{ |
1957
|
|
|
$members_id = $conditions['members']; |
1958
|
|
|
} |
1959
|
|
|
|
1960
|
|
|
$conditions['is_activated'] = $conditions['activated_status'] >= 10 ? 11 : 1; |
1961
|
|
|
$conditions['blank_string'] = ''; |
1962
|
|
|
|
1963
|
|
|
// Approve/activate this member. |
1964
|
|
|
$db->query('', ' |
1965
|
|
|
UPDATE {db_prefix}members |
1966
|
|
|
SET validation_code = {string:blank_string}, is_activated = {int:is_activated} |
1967
|
|
|
WHERE is_activated = {int:activated_status}' . implode('', $query_cond), |
1968
|
|
|
$conditions |
1969
|
|
|
); |
1970
|
|
|
|
1971
|
|
|
// Let the integration know that they've been activated! |
1972
|
|
|
foreach ($members_id as $member_id) |
1973
|
|
|
call_integration_hook('integrate_activate', array($member_id, $conditions['activated_status'], $conditions['is_activated'])); |
1974
|
|
|
|
1975
|
|
|
return $conditions['is_activated']; |
1976
|
|
|
} |
1977
|
|
|
|
1978
|
|
|
/** |
1979
|
|
|
* Set these members for activation |
1980
|
|
|
* |
1981
|
|
|
* @package Members |
1982
|
|
|
* @param mixed[] $conditions associative array holding the conditions for the WHERE clause of the query. |
1983
|
|
|
* Possible keys: |
1984
|
|
|
* - selected_member (integer) must be present |
1985
|
|
|
* - activated_status (boolean) must be present |
1986
|
|
|
* - validation_code (string) must be present |
1987
|
|
|
* - members (array of integers) |
1988
|
|
|
* - time_before (integer) |
1989
|
|
|
*/ |
1990
|
|
|
function enforceReactivation($conditions) |
1991
|
|
|
{ |
1992
|
|
|
$db = database(); |
1993
|
|
|
|
1994
|
|
|
// We need all of these |
1995
|
|
|
assert(isset($conditions['activated_status'])); |
1996
|
|
|
assert(isset($conditions['selected_member'])); |
1997
|
|
|
assert(isset($conditions['validation_code'])); |
1998
|
|
|
|
1999
|
|
|
$conditions['validation_code'] = substr(hash('sha256', $conditions['validation_code']), 0, 10); |
2000
|
|
|
|
2001
|
|
|
$available_conditions = array( |
2002
|
|
|
'time_before' => ' |
2003
|
|
|
AND date_registered < {int:time_before}', |
2004
|
|
|
'members' => ' |
2005
|
|
|
AND id_member IN ({array_int:members})', |
2006
|
|
|
); |
2007
|
|
|
|
2008
|
|
|
$query_cond = array(); |
2009
|
|
|
foreach ($conditions as $key => $dummy) |
2010
|
|
|
$query_cond[] = $available_conditions[$key]; |
2011
|
|
|
|
2012
|
|
|
$conditions['not_activated'] = 0; |
2013
|
|
|
|
2014
|
|
|
$db->query('', ' |
2015
|
|
|
UPDATE {db_prefix}members |
2016
|
|
|
SET validation_code = {string:validation_code}, is_activated = {int:not_activated} |
2017
|
|
|
WHERE is_activated = {int:activated_status} |
2018
|
|
|
' . implode('', $query_cond) . ' |
2019
|
|
|
AND id_member = {int:selected_member}', |
2020
|
|
|
$conditions |
2021
|
|
|
); |
2022
|
|
|
} |
2023
|
|
|
|
2024
|
|
|
/** |
2025
|
|
|
* Count members of a given group |
2026
|
|
|
* |
2027
|
|
|
* @package Members |
2028
|
|
|
* @param int $id_group |
2029
|
|
|
* @return int |
2030
|
|
|
*/ |
2031
|
|
View Code Duplication |
function countMembersInGroup($id_group = 0) |
|
|
|
|
2032
|
|
|
{ |
2033
|
|
|
$db = database(); |
2034
|
|
|
|
2035
|
|
|
// Determine the number of ungrouped members. |
2036
|
|
|
$request = $db->query('', ' |
2037
|
|
|
SELECT COUNT(*) |
2038
|
|
|
FROM {db_prefix}members |
2039
|
|
|
WHERE id_group = {int:group}', |
2040
|
|
|
array( |
2041
|
|
|
'group' => $id_group, |
2042
|
|
|
) |
2043
|
|
|
); |
2044
|
|
|
list ($num_members) = $db->fetch_row($request); |
2045
|
|
|
$db->free_result($request); |
2046
|
|
|
|
2047
|
|
|
return $num_members; |
2048
|
|
|
} |
2049
|
|
|
|
2050
|
|
|
/** |
2051
|
|
|
* Get the total amount of members online. |
2052
|
|
|
* |
2053
|
|
|
* @package Members |
2054
|
|
|
* @param string[] $conditions |
2055
|
|
|
* @return int |
2056
|
|
|
*/ |
2057
|
|
View Code Duplication |
function countMembersOnline($conditions) |
|
|
|
|
2058
|
|
|
{ |
2059
|
|
|
$db = database(); |
2060
|
|
|
|
2061
|
|
|
$request = $db->query('', ' |
2062
|
|
|
SELECT COUNT(*) |
2063
|
|
|
FROM {db_prefix}log_online AS lo |
2064
|
|
|
LEFT JOIN {db_prefix}members AS mem ON (lo.id_member = mem.id_member)' . (!empty($conditions) ? ' |
2065
|
|
|
WHERE ' . implode(' AND ', $conditions) : ''), |
2066
|
|
|
array( |
2067
|
|
|
) |
2068
|
|
|
); |
2069
|
|
|
list ($totalMembers) = $db->fetch_row($request); |
2070
|
|
|
$db->free_result($request); |
2071
|
|
|
|
2072
|
|
|
return $totalMembers; |
2073
|
|
|
} |
2074
|
|
|
|
2075
|
|
|
/** |
2076
|
|
|
* Look for people online, provided they don't mind if you see they are. |
2077
|
|
|
* |
2078
|
|
|
* @package Members |
2079
|
|
|
* @param string[] $conditions |
2080
|
|
|
* @param string $sort_method |
2081
|
|
|
* @param string $sort_direction |
2082
|
|
|
* @param int $start |
2083
|
|
|
* @return array |
2084
|
|
|
*/ |
2085
|
|
|
function onlineMembers($conditions, $sort_method, $sort_direction, $start) |
2086
|
|
|
{ |
2087
|
|
|
global $modSettings; |
2088
|
|
|
|
2089
|
|
|
$db = database(); |
2090
|
|
|
|
2091
|
|
|
return $db->fetchQuery(' |
2092
|
|
|
SELECT |
2093
|
|
|
lo.log_time, lo.id_member, lo.url, lo.ip, mem.real_name, |
2094
|
|
|
lo.session, mg.online_color, COALESCE(mem.show_online, 1) AS show_online, |
2095
|
|
|
lo.id_spider |
2096
|
|
|
FROM {db_prefix}log_online AS lo |
2097
|
|
|
LEFT JOIN {db_prefix}members AS mem ON (lo.id_member = mem.id_member) |
2098
|
|
|
LEFT JOIN {db_prefix}membergroups AS mg ON (mg.id_group = CASE WHEN mem.id_group = {int:regular_member} THEN mem.id_post_group ELSE mem.id_group END)' . (!empty($conditions) ? ' |
2099
|
|
|
WHERE ' . implode(' AND ', $conditions) : '') . ' |
2100
|
|
|
ORDER BY {raw:sort_method} {raw:sort_direction} |
2101
|
|
|
LIMIT {int:offset}, {int:limit}', |
2102
|
|
|
array( |
2103
|
|
|
'regular_member' => 0, |
2104
|
|
|
'sort_method' => $sort_method, |
2105
|
|
|
'sort_direction' => $sort_direction == 'up' ? 'ASC' : 'DESC', |
2106
|
|
|
'offset' => $start, |
2107
|
|
|
'limit' => $modSettings['defaultMaxMembers'], |
2108
|
|
|
) |
2109
|
|
|
); |
2110
|
|
|
} |
2111
|
|
|
|
2112
|
|
|
/** |
2113
|
|
|
* Check if the OpenID URI is already registered for an existing member |
2114
|
|
|
* |
2115
|
|
|
* @package Members |
2116
|
|
|
* @param string $url |
2117
|
|
|
* @return array |
2118
|
|
|
*/ |
2119
|
|
|
function memberExists($url) |
2120
|
|
|
{ |
2121
|
|
|
$db = database(); |
2122
|
|
|
|
2123
|
|
|
$request = $db->query('', ' |
2124
|
|
|
SELECT mem.id_member, mem.member_name |
2125
|
|
|
FROM {db_prefix}members AS mem |
2126
|
|
|
WHERE mem.openid_uri = {string:openid_uri}', |
2127
|
|
|
array( |
2128
|
|
|
'openid_uri' => $url, |
2129
|
|
|
) |
2130
|
|
|
); |
2131
|
|
|
$member = $db->fetch_assoc($request); |
2132
|
|
|
$db->free_result($request); |
2133
|
|
|
|
2134
|
|
|
return $member; |
2135
|
|
|
} |
2136
|
|
|
|
2137
|
|
|
/** |
2138
|
|
|
* Find the most recent members |
2139
|
|
|
* |
2140
|
|
|
* @package Members |
2141
|
|
|
* @param int $limit |
2142
|
|
|
*/ |
2143
|
|
|
function recentMembers($limit) |
2144
|
|
|
{ |
2145
|
|
|
$db = database(); |
2146
|
|
|
|
2147
|
|
|
// Find the most recent members. |
2148
|
|
|
return $db->fetchQuery(' |
2149
|
|
|
SELECT id_member, member_name, real_name, date_registered, last_login |
2150
|
|
|
FROM {db_prefix}members |
2151
|
|
|
ORDER BY id_member DESC |
2152
|
|
|
LIMIT {int:limit}', |
2153
|
|
|
array( |
2154
|
|
|
'limit' => $limit, |
2155
|
|
|
) |
2156
|
|
|
); |
2157
|
|
|
} |
2158
|
|
|
|
2159
|
|
|
/** |
2160
|
|
|
* Assign membergroups to members. |
2161
|
|
|
* |
2162
|
|
|
* @package Members |
2163
|
|
|
* @param int $member |
2164
|
|
|
* @param int $primary_group |
2165
|
|
|
* @param int[] $additional_groups |
2166
|
|
|
*/ |
2167
|
|
|
function assignGroupsToMember($member, $primary_group, $additional_groups) |
2168
|
|
|
{ |
2169
|
|
|
updateMemberData($member, array('id_group' => $primary_group, 'additional_groups' => implode(',', $additional_groups))); |
2170
|
|
|
} |
2171
|
|
|
|
2172
|
|
|
/** |
2173
|
|
|
* Get a list of members from a membergroups request. |
2174
|
|
|
* |
2175
|
|
|
* @package Members |
2176
|
|
|
* @param int[] $groups |
2177
|
|
|
* @param string $where |
2178
|
|
|
* @param boolean $change_groups = false |
2179
|
|
|
* @return mixed |
2180
|
|
|
*/ |
2181
|
|
|
function getConcernedMembers($groups, $where, $change_groups = false) |
2182
|
|
|
{ |
2183
|
|
|
global $modSettings, $language; |
2184
|
|
|
|
2185
|
|
|
$db = database(); |
2186
|
|
|
|
2187
|
|
|
// Get the details of all the members concerned... |
2188
|
|
|
$request = $db->query('', ' |
2189
|
|
|
SELECT lgr.id_request, lgr.id_member, lgr.id_group, mem.email_address, mem.id_group AS primary_group, |
2190
|
|
|
mem.additional_groups AS additional_groups, mem.lngfile, mem.member_name, mem.notify_types, |
2191
|
|
|
mg.hidden, mg.group_name |
2192
|
|
|
FROM {db_prefix}log_group_requests AS lgr |
2193
|
|
|
INNER JOIN {db_prefix}members AS mem ON (mem.id_member = lgr.id_member) |
2194
|
|
|
INNER JOIN {db_prefix}membergroups AS mg ON (mg.id_group = lgr.id_group) |
2195
|
|
|
WHERE ' . $where . ' |
2196
|
|
|
AND lgr.id_request IN ({array_int:request_list}) |
2197
|
|
|
ORDER BY mem.lngfile', |
2198
|
|
|
array( |
2199
|
|
|
'request_list' => $groups, |
2200
|
|
|
) |
2201
|
|
|
); |
2202
|
|
|
|
2203
|
|
|
$email_details = array(); |
2204
|
|
|
$group_changes = array(); |
2205
|
|
|
|
2206
|
|
|
while ($row = $db->fetch_assoc($request)) |
2207
|
|
|
{ |
2208
|
|
|
$row['lngfile'] = empty($row['lngfile']) || empty($modSettings['userLanguage']) ? $language : $row['lngfile']; |
2209
|
|
|
|
2210
|
|
|
// If we are approving work out what their new group is. |
2211
|
|
|
if ($change_groups) |
2212
|
|
|
{ |
2213
|
|
|
// For people with more than one request at once. |
2214
|
|
|
if (isset($group_changes[$row['id_member']])) |
2215
|
|
|
{ |
2216
|
|
|
$row['additional_groups'] = $group_changes[$row['id_member']]['add']; |
2217
|
|
|
$row['primary_group'] = $group_changes[$row['id_member']]['primary']; |
2218
|
|
|
} |
2219
|
|
|
else |
2220
|
|
|
$row['additional_groups'] = explode(',', $row['additional_groups']); |
2221
|
|
|
// Don't have it already? |
2222
|
|
|
if ($row['primary_group'] == $row['id_group'] || in_array($row['id_group'], $row['additional_groups'])) |
2223
|
|
|
continue; |
2224
|
|
|
// Should it become their primary? |
2225
|
|
|
if ($row['primary_group'] == 0 && $row['hidden'] == 0) |
2226
|
|
|
$row['primary_group'] = $row['id_group']; |
2227
|
|
|
else |
2228
|
|
|
$row['additional_groups'][] = $row['id_group']; |
2229
|
|
|
|
2230
|
|
|
// Add them to the group master list. |
2231
|
|
|
$group_changes[$row['id_member']] = array( |
2232
|
|
|
'primary' => $row['primary_group'], |
2233
|
|
|
'add' => $row['additional_groups'], |
2234
|
|
|
); |
2235
|
|
|
} |
2236
|
|
|
|
2237
|
|
|
// Add required information to email them. |
2238
|
|
|
if ($row['notify_types'] != 4) |
2239
|
|
|
$email_details[] = array( |
2240
|
|
|
'rid' => $row['id_request'], |
2241
|
|
|
'member_id' => $row['id_member'], |
2242
|
|
|
'member_name' => $row['member_name'], |
2243
|
|
|
'group_id' => $row['id_group'], |
2244
|
|
|
'group_name' => $row['group_name'], |
2245
|
|
|
'email' => $row['email_address'], |
2246
|
|
|
'language' => $row['lngfile'], |
2247
|
|
|
); |
2248
|
|
|
} |
2249
|
|
|
$db->free_result($request); |
2250
|
|
|
|
2251
|
|
|
$output = array( |
2252
|
|
|
'email_details' => $email_details, |
2253
|
|
|
'group_changes' => $group_changes |
2254
|
|
|
); |
2255
|
|
|
|
2256
|
|
|
return $output; |
2257
|
|
|
} |
2258
|
|
|
|
2259
|
|
|
/** |
2260
|
|
|
* Determine if the current user ($user_info) can contact another user ($who) |
2261
|
|
|
* |
2262
|
|
|
* @package Members |
2263
|
|
|
* @param int $who The id of the user to contact |
2264
|
|
|
*/ |
2265
|
|
|
function canContact($who) |
2266
|
|
|
{ |
2267
|
|
|
global $user_info; |
2268
|
|
|
|
2269
|
|
|
$db = database(); |
2270
|
|
|
|
2271
|
|
|
$request = $db->query('', ' |
2272
|
|
|
SELECT receive_from, buddy_list, pm_ignore_list |
2273
|
|
|
FROM {db_prefix}members |
2274
|
|
|
WHERE id_member = {int:member}', |
2275
|
|
|
array( |
2276
|
|
|
'member' => $who, |
2277
|
|
|
) |
2278
|
|
|
); |
2279
|
|
|
list ($receive_from, $buddies, $ignore) = $db->fetch_row($request); |
2280
|
|
|
$db->free_result($request); |
2281
|
|
|
|
2282
|
|
|
$buddy_list = array_map('intval', explode(',', $buddies)); |
2283
|
|
|
$ignore_list = array_map('intval', explode(',', $ignore)); |
2284
|
|
|
|
2285
|
|
|
// 0 = all members |
2286
|
|
|
if ($receive_from == 0) |
2287
|
|
|
return true; |
2288
|
|
|
// 1 = all except ignore |
2289
|
|
|
elseif ($receive_from == 1) |
2290
|
|
|
return !(!empty($ignore_list) && in_array($user_info['id'], $ignore_list)); |
2291
|
|
|
// 2 = buddies and admin |
2292
|
|
|
elseif ($receive_from == 2) |
2293
|
|
|
return ($user_info['is_admin'] || (!empty($buddy_list) && in_array($user_info['id'], $buddy_list))); |
2294
|
|
|
// 3 = admin only |
2295
|
|
|
else |
2296
|
|
|
return (bool) $user_info['is_admin']; |
2297
|
|
|
} |
2298
|
|
|
|
2299
|
|
|
/** |
2300
|
|
|
* This function updates the latest member, the total membercount, and the |
2301
|
|
|
* number of unapproved members. |
2302
|
|
|
* |
2303
|
|
|
* - It also only counts approved members when approval is on, |
2304
|
|
|
* but is much more efficient with it off. |
2305
|
|
|
* |
2306
|
|
|
* @package Members |
2307
|
|
|
* @param integer|null $id_member = null If not an integer reload from the database |
2308
|
|
|
* @param string|null $real_name = null |
2309
|
|
|
*/ |
2310
|
|
|
function updateMemberStats($id_member = null, $real_name = null) |
2311
|
|
|
{ |
2312
|
1 |
|
global $modSettings; |
2313
|
|
|
|
2314
|
1 |
|
$db = database(); |
2315
|
|
|
|
2316
|
|
|
$changes = array( |
2317
|
1 |
|
'memberlist_updated' => time(), |
2318
|
1 |
|
); |
2319
|
|
|
|
2320
|
|
|
// #1 latest member ID, #2 the real name for a new registration. |
2321
|
1 |
|
if (is_int($id_member)) |
2322
|
1 |
|
{ |
2323
|
|
|
$changes['latestMember'] = $id_member; |
2324
|
|
|
$changes['latestRealName'] = $real_name; |
2325
|
|
|
|
2326
|
|
|
updateSettings(array('totalMembers' => true), true); |
2327
|
|
|
} |
2328
|
|
|
// We need to calculate the totals. |
2329
|
|
|
else |
2330
|
|
|
{ |
2331
|
|
|
// Update the latest activated member (highest id_member) and count. |
2332
|
1 |
|
$request = $db->query('', ' |
2333
|
|
|
SELECT COUNT(*), MAX(id_member) |
2334
|
|
|
FROM {db_prefix}members |
2335
|
1 |
|
WHERE is_activated = {int:is_activated}', |
2336
|
|
|
array( |
2337
|
1 |
|
'is_activated' => 1, |
2338
|
|
|
) |
2339
|
1 |
|
); |
2340
|
1 |
|
list ($changes['totalMembers'], $changes['latestMember']) = $db->fetch_row($request); |
2341
|
1 |
|
$db->free_result($request); |
2342
|
|
|
|
2343
|
|
|
// Get the latest activated member's display name. |
2344
|
1 |
|
$request = getBasicMemberData((int) $changes['latestMember']); |
2345
|
1 |
|
$changes['latestRealName'] = $request['real_name']; |
2346
|
|
|
|
2347
|
|
|
// Are we using registration approval? |
2348
|
1 |
|
if ((!empty($modSettings['registration_method']) && $modSettings['registration_method'] == 2) || !empty($modSettings['approveAccountDeletion'])) |
2349
|
1 |
|
{ |
2350
|
|
|
// Update the amount of members awaiting approval - ignoring COPPA accounts, as you can't approve them until you get permission. |
2351
|
|
|
$request = $db->query('', ' |
2352
|
|
|
SELECT COUNT(*) |
2353
|
|
|
FROM {db_prefix}members |
2354
|
|
|
WHERE is_activated IN ({array_int:activation_status})', |
2355
|
|
|
array( |
2356
|
|
|
'activation_status' => array(3, 4), |
2357
|
|
|
) |
2358
|
|
|
); |
2359
|
|
|
list ($changes['unapprovedMembers']) = $db->fetch_row($request); |
2360
|
|
|
$db->free_result($request); |
2361
|
|
|
} |
2362
|
|
|
} |
2363
|
|
|
|
2364
|
1 |
|
updateSettings($changes); |
2365
|
1 |
|
} |
2366
|
|
|
|
2367
|
|
|
/** |
2368
|
|
|
* Builds the 'query_see_board' element for a certain member |
2369
|
|
|
* |
2370
|
|
|
* @package Members |
2371
|
|
|
* @param integer $id_member a valid member id |
2372
|
|
|
* @return string Query string |
2373
|
|
|
*/ |
2374
|
|
|
function memberQuerySeeBoard($id_member) |
2375
|
|
|
{ |
2376
|
|
|
global $modSettings; |
2377
|
|
|
|
2378
|
|
|
$member = getBasicMemberData($id_member, array('moderation' => true)); |
2379
|
|
|
if (empty($member)) |
2380
|
|
|
{ |
2381
|
|
|
return '0=1'; |
2382
|
|
|
} |
2383
|
|
|
|
2384
|
|
View Code Duplication |
if (empty($member['additional_groups'])) |
2385
|
|
|
{ |
2386
|
|
|
$groups = array($member['id_group'], $member['id_post_group']); |
2387
|
|
|
} |
2388
|
|
|
else |
2389
|
|
|
{ |
2390
|
|
|
$groups = array_merge( |
2391
|
|
|
array($member['id_group'], $member['id_post_group']), |
2392
|
|
|
explode(',', $member['additional_groups']) |
2393
|
|
|
); |
2394
|
|
|
} |
2395
|
|
|
|
2396
|
|
|
foreach ($groups as $k => $v) |
2397
|
|
|
{ |
2398
|
|
|
$groups[$k] = (int) $v; |
2399
|
|
|
} |
2400
|
|
|
$groups = array_unique($groups); |
2401
|
|
|
|
2402
|
|
|
if (in_array(1, $groups)) |
2403
|
|
|
{ |
2404
|
|
|
return '1=1'; |
2405
|
|
|
} |
2406
|
|
|
else |
2407
|
|
|
{ |
2408
|
|
|
require_once(SUBSDIR . '/Boards.subs.php'); |
2409
|
|
|
|
2410
|
|
|
$boards_mod = boardsModerated($id_member); |
2411
|
|
|
$mod_query = empty($boards_mod) ? '' : ' OR b.id_board IN (' . implode(',', $boards_mod) . ')'; |
2412
|
|
|
|
2413
|
|
|
return '((FIND_IN_SET(' . implode(', b.member_groups) != 0 OR FIND_IN_SET(', $groups) . ', b.member_groups) != 0)' . (!empty($modSettings['deny_boards_access']) ? ' AND (FIND_IN_SET(' . implode(', b.deny_member_groups) = 0 AND FIND_IN_SET(', $groups) . ', b.deny_member_groups) = 0)' : '') . $mod_query . ')'; |
2414
|
|
|
} |
2415
|
|
|
} |
2416
|
|
|
|
2417
|
|
|
/** |
2418
|
|
|
* Updates the columns in the members table. |
2419
|
|
|
* |
2420
|
|
|
* What it does: |
2421
|
|
|
* |
2422
|
|
|
* - Assumes the data has been htmlspecialchar'd, no sanitation is performed on the data. |
2423
|
|
|
* - This function should be used whenever member data needs to be updated in place of an UPDATE query. |
2424
|
|
|
* - $data is an associative array of the columns to be updated and their respective values. |
2425
|
|
|
* any string values updated should be quoted and slashed. |
2426
|
|
|
* - The value of any column can be '+' or '-', which mean 'increment' and decrement, respectively. |
2427
|
|
|
* - If the member's post number is updated, updates their post groups. |
2428
|
|
|
* |
2429
|
|
|
* @param int[]|int $members An array of member ids |
2430
|
|
|
* @param mixed[] $data An associative array of the columns to be updated and their respective values. |
2431
|
|
|
*/ |
2432
|
|
|
function updateMemberData($members, $data) |
2433
|
|
|
{ |
2434
|
9 |
|
global $modSettings, $user_info; |
2435
|
|
|
|
2436
|
9 |
|
$db = database(); |
2437
|
|
|
|
2438
|
9 |
|
$parameters = array(); |
2439
|
9 |
|
if (is_array($members)) |
2440
|
9 |
|
{ |
2441
|
|
|
$condition = 'id_member IN ({array_int:members})'; |
2442
|
|
|
$parameters['members'] = $members; |
2443
|
|
|
} |
2444
|
9 |
|
elseif ($members === null) |
2445
|
|
|
$condition = '1=1'; |
2446
|
|
|
else |
2447
|
|
|
{ |
2448
|
9 |
|
$condition = 'id_member = {int:member}'; |
2449
|
9 |
|
$parameters['member'] = $members; |
2450
|
|
|
} |
2451
|
|
|
|
2452
|
|
|
// Everything is assumed to be a string unless it's in the below. |
2453
|
|
|
$knownInts = array( |
2454
|
9 |
|
'date_registered', 'posts', 'id_group', 'last_login', 'personal_messages', 'unread_messages', 'mentions', |
2455
|
9 |
|
'new_pm', 'pm_prefs', 'hide_email', 'show_online', 'pm_email_notify', 'receive_from', 'karma_good', 'karma_bad', |
2456
|
9 |
|
'notify_announcements', 'notify_send_body', 'notify_regularity', 'notify_types', |
2457
|
9 |
|
'id_theme', 'is_activated', 'id_msg_last_visit', 'id_post_group', 'total_time_logged_in', 'warning', 'likes_given', |
2458
|
9 |
|
'likes_received', 'enable_otp', 'otp_used' |
2459
|
9 |
|
); |
2460
|
|
|
$knownFloats = array( |
2461
|
9 |
|
'time_offset', |
2462
|
9 |
|
); |
2463
|
|
|
|
2464
|
9 |
|
if (!empty($modSettings['integrate_change_member_data'])) |
2465
|
9 |
|
{ |
2466
|
|
|
// Only a few member variables are really interesting for integration. |
2467
|
|
|
$integration_vars = array( |
2468
|
|
|
'member_name', |
2469
|
|
|
'real_name', |
2470
|
|
|
'email_address', |
2471
|
|
|
'id_group', |
2472
|
|
|
'birthdate', |
2473
|
|
|
'website_title', |
2474
|
|
|
'website_url', |
2475
|
|
|
'hide_email', |
2476
|
|
|
'time_format', |
2477
|
|
|
'time_offset', |
2478
|
|
|
'avatar', |
2479
|
|
|
'lngfile', |
2480
|
|
|
); |
2481
|
|
|
$vars_to_integrate = array_intersect($integration_vars, array_keys($data)); |
2482
|
|
|
|
2483
|
|
|
// Only proceed if there are any variables left to call the integration function. |
2484
|
|
|
if (count($vars_to_integrate) != 0) |
2485
|
|
|
{ |
2486
|
|
|
// Fetch a list of member_names if necessary |
2487
|
|
|
if ((!is_array($members) && $members === $user_info['id']) || (is_array($members) && count($members) == 1 && in_array($user_info['id'], $members))) |
2488
|
|
|
$member_names = array($user_info['username']); |
2489
|
|
|
else |
2490
|
|
|
{ |
2491
|
|
|
$member_names = $db->fetchQueryCallback(' |
2492
|
|
|
SELECT member_name |
2493
|
|
|
FROM {db_prefix}members |
2494
|
|
|
WHERE ' . $condition, |
2495
|
|
|
$parameters, |
2496
|
|
|
function ($row) |
2497
|
|
|
{ |
2498
|
|
|
return $row['member_name']; |
2499
|
|
|
} |
2500
|
|
|
); |
2501
|
|
|
} |
2502
|
|
|
|
2503
|
|
|
if (!empty($member_names)) |
2504
|
|
|
foreach ($vars_to_integrate as $var) |
2505
|
|
|
call_integration_hook('integrate_change_member_data', array($member_names, &$var, &$data[$var], &$knownInts, &$knownFloats)); |
2506
|
|
|
} |
2507
|
|
|
} |
2508
|
|
|
|
2509
|
9 |
|
$setString = ''; |
2510
|
9 |
|
foreach ($data as $var => $val) |
2511
|
|
|
{ |
2512
|
9 |
|
$type = 'string'; |
2513
|
|
|
|
2514
|
9 |
View Code Duplication |
if (in_array($var, $knownInts)) |
2515
|
9 |
|
$type = 'int'; |
2516
|
|
|
elseif (in_array($var, $knownFloats)) |
2517
|
|
|
$type = 'float'; |
2518
|
|
|
elseif ($var == 'birthdate') |
2519
|
|
|
$type = 'date'; |
2520
|
|
|
|
2521
|
|
|
// Doing an increment? |
2522
|
9 |
|
if ($type == 'int' && ($val === '+' || $val === '-')) |
2523
|
9 |
|
{ |
2524
|
4 |
|
$val = $var . ' ' . $val . ' 1'; |
2525
|
4 |
|
$type = 'raw'; |
2526
|
4 |
|
} |
2527
|
|
|
|
2528
|
|
|
// Ensure posts, personal_messages, and unread_messages don't overflow or underflow. |
2529
|
9 |
|
if (in_array($var, array('posts', 'personal_messages', 'unread_messages'))) |
2530
|
9 |
|
{ |
2531
|
6 |
|
if (preg_match('~^' . $var . ' (\+ |- |\+ -)([\d]+)~', $val, $match)) |
2532
|
6 |
|
{ |
2533
|
6 |
|
if ($match[1] != '+ ') |
2534
|
6 |
|
$val = 'CASE WHEN ' . $var . ' <= ' . abs($match[2]) . ' THEN 0 ELSE ' . $val . ' END'; |
2535
|
6 |
|
$type = 'raw'; |
2536
|
6 |
|
} |
2537
|
6 |
|
} |
2538
|
|
|
|
2539
|
9 |
|
$setString .= ' ' . $var . ' = {' . $type . ':p_' . $var . '},'; |
2540
|
9 |
|
$parameters['p_' . $var] = $val; |
2541
|
9 |
|
} |
2542
|
|
|
|
2543
|
9 |
|
$db->query('', ' |
2544
|
|
|
UPDATE {db_prefix}members |
2545
|
9 |
|
SET' . substr($setString, 0, -1) . ' |
2546
|
9 |
|
WHERE ' . $condition, |
2547
|
|
|
$parameters |
2548
|
9 |
|
); |
2549
|
|
|
|
2550
|
9 |
|
require_once(SUBSDIR . '/Membergroups.subs.php'); |
2551
|
9 |
|
updatePostGroupStats($members, array_keys($data)); |
2552
|
|
|
|
2553
|
9 |
|
$cache = Cache::instance(); |
2554
|
|
|
|
2555
|
|
|
// Clear any caching? |
2556
|
9 |
|
if ($cache->levelHigherThan(1) && !empty($members)) |
2557
|
9 |
|
{ |
2558
|
|
|
if (!is_array($members)) |
2559
|
|
|
$members = array($members); |
2560
|
|
|
|
2561
|
|
|
foreach ($members as $member) |
2562
|
|
|
{ |
2563
|
|
|
if ($cache->levelHigherThan(2)) |
2564
|
|
|
{ |
2565
|
|
|
$cache->remove('member_data-profile-' . $member); |
2566
|
|
|
$cache->remove('member_data-normal-' . $member); |
2567
|
|
|
$cache->remove('member_data-minimal-' . $member); |
2568
|
|
|
} |
2569
|
|
|
|
2570
|
|
|
$cache->remove('user_settings-' . $member); |
2571
|
|
|
} |
2572
|
|
|
} |
2573
|
9 |
|
} |
2574
|
|
|
|
2575
|
|
|
/** |
2576
|
|
|
* Loads members who are associated with an ip address |
2577
|
|
|
* |
2578
|
|
|
* @param string $ip_string raw value to use in where clause |
2579
|
|
|
* @param string $ip_var |
2580
|
|
|
*/ |
2581
|
|
|
function loadMembersIPs($ip_string, $ip_var) |
2582
|
|
|
{ |
2583
|
|
|
global $scripturl; |
2584
|
|
|
|
2585
|
|
|
$db = database(); |
2586
|
|
|
|
2587
|
|
|
$request = $db->query('', ' |
2588
|
|
|
SELECT |
2589
|
|
|
id_member, real_name AS display_name, member_ip |
2590
|
|
|
FROM {db_prefix}members |
2591
|
|
|
WHERE member_ip ' . $ip_string, |
2592
|
|
|
array( |
2593
|
|
|
'ip_address' => $ip_var, |
2594
|
|
|
) |
2595
|
|
|
); |
2596
|
|
|
$ips = array(); |
2597
|
|
View Code Duplication |
while ($row = $db->fetch_assoc($request)) |
2598
|
|
|
$ips[$row['member_ip']][] = '<a href="' . $scripturl . '?action=profile;u=' . $row['id_member'] . '">' . $row['display_name'] . '</a>'; |
2599
|
|
|
$db->free_result($request); |
2600
|
|
|
|
2601
|
|
|
ksort($ips); |
2602
|
|
|
|
2603
|
|
|
return $ips; |
2604
|
|
|
} |
2605
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.