Failed Conditions
Branch release-2.1 (4e22cf)
by Rick
06:39
created

ManageMembers.php ➔ jeffsdatediff()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 20
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 9
nc 2
nop 1
dl 0
loc 20
rs 9.4285
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * Show a list of members or a selection of members.
5
 *
6
 * Simple Machines Forum (SMF)
7
 *
8
 * @package SMF
9
 * @author Simple Machines http://www.simplemachines.org
10
 * @copyright 2017 Simple Machines and individual contributors
11
 * @license http://www.simplemachines.org/about/smf/license.php BSD
12
 *
13
 * @version 2.1 Beta 4
14
 */
15
16
if (!defined('SMF'))
17
	die('No direct access...');
18
19
/**
20
 * The main entrance point for the Manage Members screen.
21
 * As everyone else, it calls a function based on the given sub-action.
22
 * Called by ?action=admin;area=viewmembers.
23
 * Requires the moderate_forum permission.
24
 *
25
 * @uses ManageMembers template
26
 * @uses ManageMembers language file.
27
 */
28
function ViewMembers()
29
{
30
	global $txt, $scripturl, $context, $modSettings, $smcFunc;
31
32
	$subActions = array(
33
		'all' => array('ViewMemberlist', 'moderate_forum'),
34
		'approve' => array('AdminApprove', 'moderate_forum'),
35
		'browse' => array('MembersAwaitingActivation', 'moderate_forum'),
36
		'search' => array('SearchMembers', 'moderate_forum'),
37
		'query' => array('ViewMemberlist', 'moderate_forum'),
38
	);
39
40
	call_integration_hook('integrate_manage_members', array(&$subActions));
41
42
	// Default to sub action 'index' or 'settings' depending on permissions.
43
	$_REQUEST['sa'] = isset($_REQUEST['sa']) && isset($subActions[$_REQUEST['sa']]) ? $_REQUEST['sa'] : 'all';
44
45
	// We know the sub action, now we know what you're allowed to do.
46
	isAllowedTo($subActions[$_REQUEST['sa']][1]);
47
48
	// Load the essentials.
49
	loadLanguage('ManageMembers');
50
	loadTemplate('ManageMembers');
51
52
	// Get counts on every type of activation - for sections and filtering alike.
53
	$request = $smcFunc['db_query']('', '
54
		SELECT COUNT(*) AS total_members, is_activated
55
		FROM {db_prefix}members
56
		WHERE is_activated != {int:is_activated}
57
		GROUP BY is_activated',
58
		array(
59
			'is_activated' => 1,
60
		)
61
	);
62
	$context['activation_numbers'] = array();
63
	$context['awaiting_activation'] = 0;
64
	$context['awaiting_approval'] = 0;
65
	while ($row = $smcFunc['db_fetch_assoc']($request))
66
		$context['activation_numbers'][$row['is_activated']] = $row['total_members'];
67
	$smcFunc['db_free_result']($request);
68
69
	foreach ($context['activation_numbers'] as $activation_type => $total_members)
70
	{
71
		if (in_array($activation_type, array(0, 2)))
72
			$context['awaiting_activation'] += $total_members;
73
		elseif (in_array($activation_type, array(3, 4, 5)))
74
			$context['awaiting_approval'] += $total_members;
75
	}
76
77
	// For the page header... do we show activation?
78
	$context['show_activate'] = (!empty($modSettings['registration_method']) && $modSettings['registration_method'] == 1) || !empty($context['awaiting_activation']);
79
80
	// What about approval?
81
	$context['show_approve'] = (!empty($modSettings['registration_method']) && $modSettings['registration_method'] == 2) || !empty($context['awaiting_approval']) || !empty($modSettings['approveAccountDeletion']);
82
83
	// Setup the admin tabs.
84
	$context[$context['admin_menu_name']]['tab_data'] = array(
85
		'title' => $txt['admin_members'],
86
		'help' => 'view_members',
87
		'description' => $txt['admin_members_list'],
88
		'tabs' => array(),
89
	);
90
91
	$context['tabs'] = array(
92
		'viewmembers' => array(
93
			'label' => $txt['view_all_members'],
94
			'description' => $txt['admin_members_list'],
95
			'url' => $scripturl . '?action=admin;area=viewmembers;sa=all',
96
			'is_selected' => $_REQUEST['sa'] == 'all',
97
		),
98
		'search' => array(
99
			'label' => $txt['mlist_search'],
100
			'description' => $txt['admin_members_list'],
101
			'url' => $scripturl . '?action=admin;area=viewmembers;sa=search',
102
			'is_selected' => $_REQUEST['sa'] == 'search' || $_REQUEST['sa'] == 'query',
103
		),
104
		'approve' => array(
105
			'label' => sprintf($txt['admin_browse_awaiting_approval'], $context['awaiting_approval']),
106
			'description' => $txt['admin_browse_approve_desc'],
107
			'url' => $scripturl . '?action=admin;area=viewmembers;sa=browse;type=approve',
108
			'is_selected' => false,
109
		),
110
		'activate' => array(
111
			'label' => sprintf($txt['admin_browse_awaiting_activate'], $context['awaiting_activation']),
112
			'description' => $txt['admin_browse_activate_desc'],
113
			'url' => $scripturl . '?action=admin;area=viewmembers;sa=browse;type=activate',
114
			'is_selected' => false,
115
			'is_last' => true,
116
		),
117
	);
118
119
	// Sort out the tabs for the ones which may not exist!
120
	if (!$context['show_activate'] && ($_REQUEST['sa'] != 'browse' || $_REQUEST['type'] != 'activate'))
121
	{
122
		$context['tabs']['approve']['is_last'] = true;
123
		unset($context['tabs']['activate']);
124
	}
125
	if (!$context['show_approve'] && ($_REQUEST['sa'] != 'browse' || $_REQUEST['type'] != 'approve'))
126
	{
127
		if (!$context['show_activate'] && ($_REQUEST['sa'] != 'browse' || $_REQUEST['type'] != 'activate'))
128
			$context['tabs']['search']['is_last'] = true;
129
		unset($context['tabs']['approve']);
130
	}
131
132
	call_helper($subActions[$_REQUEST['sa']][0]);
133
}
134
135
/**
136
 * View all members list. It allows sorting on several columns, and deletion of
137
 * selected members. It also handles the search query sent by
138
 * ?action=admin;area=viewmembers;sa=search.
139
 * Called by ?action=admin;area=viewmembers;sa=all or ?action=admin;area=viewmembers;sa=query.
140
 * Requires the moderate_forum permission.
141
 *
142
 * @uses the view_members sub template of the ManageMembers template.
143
 */
144
function ViewMemberlist()
145
{
146
	global $txt, $scripturl, $context, $modSettings, $sourcedir, $smcFunc, $user_info;
147
148
	// Set the current sub action.
149
	$context['sub_action'] = $_REQUEST['sa'];
150
151
	// Are we performing a delete?
152
	if (isset($_POST['delete_members']) && !empty($_POST['delete']) && allowedTo('profile_remove_any'))
153
	{
154
		checkSession();
155
156
		// Clean the input.
157
		foreach ($_POST['delete'] as $key => $value)
158
		{
159
			// Don't delete yourself, idiot.
160
			if ($value != $user_info['id'])
161
				$delete[$key] = (int) $value;
0 ignored issues
show
Coding Style Comprehensibility introduced by
$delete was never initialized. Although not strictly required by PHP, it is generally a good practice to add $delete = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
162
		}
163
164
		if (!empty($delete))
165
		{
166
			// Delete all the selected members.
167
			require_once($sourcedir . '/Subs-Members.php');
168
			deleteMembers($delete, true);
169
		}
170
	}
171
172
	// Check input after a member search has been submitted.
173
	if ($context['sub_action'] == 'query')
174
	{
175
		// Retrieving the membergroups and postgroups.
176
		$context['membergroups'] = array(
177
			array(
178
				'id' => 0,
179
				'name' => $txt['membergroups_members'],
180
				'can_be_additional' => false
181
			)
182
		);
183
		$context['postgroups'] = array();
184
185
		$request = $smcFunc['db_query']('', '
186
			SELECT id_group, group_name, min_posts
187
			FROM {db_prefix}membergroups
188
			WHERE id_group != {int:moderator_group}
189
			ORDER BY min_posts, CASE WHEN id_group < {int:newbie_group} THEN id_group ELSE 4 END, group_name',
190
			array(
191
				'moderator_group' => 3,
192
				'newbie_group' => 4,
193
			)
194
		);
195 View Code Duplication
		while ($row = $smcFunc['db_fetch_assoc']($request))
196
		{
197
			if ($row['min_posts'] == -1)
198
				$context['membergroups'][] = array(
199
					'id' => $row['id_group'],
200
					'name' => $row['group_name'],
201
					'can_be_additional' => true
202
				);
203
			else
204
				$context['postgroups'][] = array(
205
					'id' => $row['id_group'],
206
					'name' => $row['group_name']
207
				);
208
		}
209
		$smcFunc['db_free_result']($request);
210
211
		// Some data about the form fields and how they are linked to the database.
212
		$params = array(
213
			'mem_id' => array(
214
				'db_fields' => array('id_member'),
215
				'type' => 'int',
216
				'range' => true
217
			),
218
			'age' => array(
219
				'db_fields' => array('birthdate'),
220
				'type' => 'age',
221
				'range' => true
222
			),
223
			'posts' => array(
224
				'db_fields' => array('posts'),
225
				'type' => 'int',
226
				'range' => true
227
			),
228
			'reg_date' => array(
229
				'db_fields' => array('date_registered'),
230
				'type' => 'date',
231
				'range' => true
232
			),
233
			'last_online' => array(
234
				'db_fields' => array('last_login'),
235
				'type' => 'date',
236
				'range' => true
237
			),
238
			'activated' => array(
239
				'db_fields' => array('CASE WHEN is_activated IN (1, 11) THEN 1 ELSE 0 END'),
240
				'type' => 'checkbox',
241
				'values' => array('0', '1'),
242
			),
243
			'membername' => array(
244
				'db_fields' => array('member_name', 'real_name'),
245
				'type' => 'string'
246
			),
247
			'email' => array(
248
				'db_fields' => array('email_address'),
249
				'type' => 'string'
250
			),
251
			'website' => array(
252
				'db_fields' => array('website_title', 'website_url'),
253
				'type' => 'string'
254
			),
255
			'ip' => array(
256
				'db_fields' => array('member_ip'),
257
				'type' => 'inet'
258
			)
259
		);
260
		$range_trans = array(
261
			'--' => '<',
262
			'-' => '<=',
263
			'=' => '=',
264
			'+' => '>=',
265
			'++' => '>'
266
		);
267
268
		call_integration_hook('integrate_view_members_params', array(&$params));
269
270
		$search_params = array();
271
		if ($context['sub_action'] == 'query' && !empty($_REQUEST['params']) && empty($_POST['types']))
272
			$search_params = $smcFunc['json_decode'](base64_decode($_REQUEST['params']), true);
273
		elseif (!empty($_POST))
274
		{
275
			$search_params['types'] = $_POST['types'];
276
			foreach ($params as $param_name => $param_info)
277
				if (isset($_POST[$param_name]))
278
					$search_params[$param_name] = $_POST[$param_name];
279
		}
280
281
		$search_url_params = isset($search_params) ? base64_encode($smcFunc['json_encode']($search_params)) : null;
282
283
		// @todo Validate a little more.
0 ignored issues
show
Coding Style Best Practice introduced by
Comments for TODO tasks are often forgotten in the code; it might be better to use a dedicated issue tracker.
Loading history...
284
285
		// Loop through every field of the form.
286
		$query_parts = array();
287
		$where_params = array();
288
		foreach ($params as $param_name => $param_info)
289
		{
290
			// Not filled in?
291
			if (!isset($search_params[$param_name]) || $search_params[$param_name] === '')
292
				continue;
293
294
			// Make sure numeric values are really numeric.
295
			if (in_array($param_info['type'], array('int', 'age')))
296
				$search_params[$param_name] = (int) $search_params[$param_name];
297
			// Date values have to match the specified format.
298
			elseif ($param_info['type'] == 'date')
299
			{
300
				// Check if this date format is valid.
301
				if (preg_match('/^\d{4}-\d{1,2}-\d{1,2}$/', $search_params[$param_name]) == 0)
302
					continue;
303
304
				$search_params[$param_name] = strtotime($search_params[$param_name]);
305
			}
306
307
			// Those values that are in some kind of range (<, <=, =, >=, >).
308
			if (!empty($param_info['range']))
309
			{
310
				// Default to '=', just in case...
0 ignored issues
show
Unused Code Comprehensibility introduced by
36% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
311
				if (empty($range_trans[$search_params['types'][$param_name]]))
312
					$search_params['types'][$param_name] = '=';
313
314
				// Handle special case 'age'.
315
				if ($param_info['type'] == 'age')
316
				{
317
					// All people that were born between $lowerlimit and $upperlimit are currently the specified age.
318
					$datearray = getdate(forum_time());
319
					$upperlimit = sprintf('%04d-%02d-%02d', $datearray['year'] - $search_params[$param_name], $datearray['mon'], $datearray['mday']);
320
					$lowerlimit = sprintf('%04d-%02d-%02d', $datearray['year'] - $search_params[$param_name] - 1, $datearray['mon'], $datearray['mday']);
321
					if (in_array($search_params['types'][$param_name], array('-', '--', '=')))
322
					{
323
						$query_parts[] = ($param_info['db_fields'][0]) . ' > {string:' . $param_name . '_minlimit}';
324
						$where_params[$param_name . '_minlimit'] = ($search_params['types'][$param_name] == '--' ? $upperlimit : $lowerlimit);
325
					}
326
					if (in_array($search_params['types'][$param_name], array('+', '++', '=')))
327
					{
328
						$query_parts[] = ($param_info['db_fields'][0]) . ' <= {string:' . $param_name . '_pluslimit}';
329
						$where_params[$param_name . '_pluslimit'] = ($search_params['types'][$param_name] == '++' ? $lowerlimit : $upperlimit);
330
331
						// Make sure that members that didn't set their birth year are not queried.
332
						$query_parts[] = ($param_info['db_fields'][0]) . ' > {date:dec_zero_date}';
333
						$where_params['dec_zero_date'] = '0004-12-31';
334
					}
335
				}
336
				// Special case - equals a date.
337
				elseif ($param_info['type'] == 'date' && $search_params['types'][$param_name] == '=')
338
				{
339
					$query_parts[] = $param_info['db_fields'][0] . ' > ' . $search_params[$param_name] . ' AND ' . $param_info['db_fields'][0] . ' < ' . ($search_params[$param_name] + 86400);
340
				}
341
				else
342
					$query_parts[] = $param_info['db_fields'][0] . ' ' . $range_trans[$search_params['types'][$param_name]] . ' ' . $search_params[$param_name];
343
			}
344
			// Checkboxes.
345
			elseif ($param_info['type'] == 'checkbox')
346
			{
347
				// Each checkbox or no checkbox at all is checked -> ignore.
348
				if (!is_array($search_params[$param_name]) || count($search_params[$param_name]) == 0 || count($search_params[$param_name]) == count($param_info['values']))
349
					continue;
350
351
				$query_parts[] = ($param_info['db_fields'][0]) . ' IN ({array_string:' . $param_name . '_check})';
352
				$where_params[$param_name . '_check'] = $search_params[$param_name];
353
			}
354
			else
355
			{
356
				// Replace the wildcard characters ('*' and '?') into MySQL ones.
357
				$parameter = strtolower(strtr($smcFunc['htmlspecialchars']($search_params[$param_name], ENT_QUOTES), array('%' => '\%', '_' => '\_', '*' => '%', '?' => '_')));
358
359
				if ($smcFunc['db_case_sensitive'])
360
					$query_parts[] = '(LOWER(' . implode(') LIKE {string:' . $param_name . '_normal} OR LOWER(', $param_info['db_fields']) . ') LIKE {string:' . $param_name . '_normal})';
361
				else
362
					$query_parts[] = '(' . implode(' LIKE {string:' . $param_name . '_normal} OR ', $param_info['db_fields']) . ' LIKE {string:' . $param_name . '_normal})';
363
				$where_params[$param_name . '_normal'] = '%' . $parameter . '%';
364
			}
365
		}
366
367
		// Set up the membergroup query part.
368
		$mg_query_parts = array();
369
370
		// Primary membergroups, but only if at least was was not selected.
371
		if (!empty($search_params['membergroups'][1]) && count($context['membergroups']) != count($search_params['membergroups'][1]))
372
		{
373
			$mg_query_parts[] = 'mem.id_group IN ({array_int:group_check})';
374
			$where_params['group_check'] = $search_params['membergroups'][1];
375
		}
376
377
		// Additional membergroups (these are only relevant if not all primary groups where selected!).
378
		if (!empty($search_params['membergroups'][2]) && (empty($search_params['membergroups'][1]) || count($context['membergroups']) != count($search_params['membergroups'][1])))
379
			foreach ($search_params['membergroups'][2] as $mg)
380
			{
381
				$mg_query_parts[] = 'FIND_IN_SET({int:add_group_' . $mg . '}, mem.additional_groups) != 0';
382
				$where_params['add_group_' . $mg] = $mg;
383
			}
384
385
		// Combine the one or two membergroup parts into one query part linked with an OR.
386
		if (!empty($mg_query_parts))
387
			$query_parts[] = '(' . implode(' OR ', $mg_query_parts) . ')';
388
389
		// Get all selected post count related membergroups.
390
		if (!empty($search_params['postgroups']) && count($search_params['postgroups']) != count($context['postgroups']))
391
		{
392
			$query_parts[] = 'id_post_group IN ({array_int:post_groups})';
393
			$where_params['post_groups'] = $search_params['postgroups'];
394
		}
395
396
		// Construct the where part of the query.
397
		$where = empty($query_parts) ? '1=1' : implode('
398
			AND ', $query_parts);
399
	}
400
	else
401
		$search_url_params = null;
402
403
	// Construct the additional URL part with the query info in it.
404
	$context['params_url'] = $context['sub_action'] == 'query' ? ';sa=query;params=' . $search_url_params : '';
405
406
	// Get the title and sub template ready..
407
	$context['page_title'] = $txt['admin_members'];
408
409
	$listOptions = array(
410
		'id' => 'member_list',
411
		'title' => $txt['members_list'],
412
		'items_per_page' => $modSettings['defaultMaxMembers'],
413
		'base_href' => $scripturl . '?action=admin;area=viewmembers' . $context['params_url'],
414
		'default_sort_col' => 'user_name',
415
		'get_items' => array(
416
			'file' => $sourcedir . '/Subs-Members.php',
417
			'function' => 'list_getMembers',
418
			'params' => array(
419
				isset($where) ? $where : '1=1',
420
				isset($where_params) ? $where_params : array(),
421
			),
422
		),
423
		'get_count' => array(
424
			'file' => $sourcedir . '/Subs-Members.php',
425
			'function' => 'list_getNumMembers',
426
			'params' => array(
427
				isset($where) ? $where : '1=1',
428
				isset($where_params) ? $where_params : array(),
429
			),
430
		),
431
		'columns' => array(
432
			'id_member' => array(
433
				'header' => array(
434
					'value' => $txt['member_id'],
435
				),
436
				'data' => array(
437
					'db' => 'id_member',
438
				),
439
				'sort' => array(
440
					'default' => 'id_member',
441
					'reverse' => 'id_member DESC',
442
				),
443
			),
444
			'user_name' => array(
445
				'header' => array(
446
					'value' => $txt['username'],
447
				),
448
				'data' => array(
449
					'sprintf' => array(
450
						'format' => '<a href="' . strtr($scripturl, array('%' => '%%')) . '?action=profile;u=%1$d">%2$s</a>',
451
						'params' => array(
452
							'id_member' => false,
453
							'member_name' => false,
454
						),
455
					),
456
					'class' => 'hidden',
457
				),
458
				'sort' => array(
459
					'default' => 'member_name',
460
					'reverse' => 'member_name DESC',
461
				),
462
			),
463
			'display_name' => array(
464
				'header' => array(
465
					'value' => $txt['display_name'],
466
				),
467
				'data' => array(
468
					'sprintf' => array(
469
						'format' => '<a href="' . strtr($scripturl, array('%' => '%%')) . '?action=profile;u=%1$d">%2$s</a>',
470
						'params' => array(
471
							'id_member' => false,
472
							'real_name' => false,
473
						),
474
					),
475
				),
476
				'sort' => array(
477
					'default' => 'real_name',
478
					'reverse' => 'real_name DESC',
479
				),
480
			),
481
			'email' => array(
482
				'header' => array(
483
					'value' => $txt['email_address'],
484
				),
485
				'data' => array(
486
					'sprintf' => array(
487
						'format' => '<a href="mailto:%1$s">%1$s</a>',
488
						'params' => array(
489
							'email_address' => true,
490
						),
491
					),
492
				),
493
				'sort' => array(
494
					'default' => 'email_address',
495
					'reverse' => 'email_address DESC',
496
				),
497
			),
498
			'ip' => array(
499
				'header' => array(
500
					'value' => $txt['ip_address'],
501
				),
502
				'data' => array(
503
					'sprintf' => array(
504
						'format' => '<a href="' . strtr($scripturl, array('%' => '%%')) . '?action=trackip;searchip=%1$s">%1$s</a>',
505
						'params' => array(
506
							'member_ip' => false,
507
						),
508
					),
509
					'class' => 'hidden',
510
				),
511
				'sort' => array(
512
					'default' => 'member_ip',
513
					'reverse' => 'member_ip DESC',
514
				),
515
			),
516
			'last_active' => array(
517
				'header' => array(
518
					'value' => $txt['viewmembers_online'],
519
				),
520
				'data' => array(
521
					'function' => function($rowData) use ($txt)
522
					{
523
						// Calculate number of days since last online.
524
						if (empty($rowData['last_login']))
525
							$difference = $txt['never'];
526
						else
527
						{
528
							$num_days_difference = jeffsdatediff($rowData['last_login']);
529
530
							// Today.
531
							if (empty($num_days_difference))
532
								$difference = $txt['viewmembers_today'];
533
534
							// Yesterday.
535
							elseif ($num_days_difference == 1)
536
								$difference = sprintf('1 %1$s', $txt['viewmembers_day_ago']);
537
538
							// X days ago.
539
							else
540
								$difference = sprintf('%1$d %2$s', $num_days_difference, $txt['viewmembers_days_ago']);
541
						}
542
543
						// Show it in italics if they're not activated...
544
						if ($rowData['is_activated'] % 10 != 1)
545
							$difference = sprintf('<em title="%1$s">%2$s</em>', $txt['not_activated'], $difference);
546
547
						return $difference;
548
					},
549
					'class' => 'hidden',
550
				),
551
				'sort' => array(
552
					'default' => 'last_login DESC',
553
					'reverse' => 'last_login',
554
				),
555
			),
556
			'posts' => array(
557
				'header' => array(
558
					'value' => $txt['member_postcount'],
559
				),
560
				'data' => array(
561
					'db' => 'posts',
562
					'class' => 'hidden',
563
				),
564
				'sort' => array(
565
					'default' => 'posts',
566
					'reverse' => 'posts DESC',
567
				),
568
			),
569
			'check' => array(
570
				'header' => array(
571
					'value' => '<input type="checkbox" onclick="invertAll(this, this.form);" class="input_check">',
572
					'class' => 'centercol',
573
				),
574
				'data' => array(
575
					'function' => function($rowData) use ($user_info)
576
					{
577
						return '<input type="checkbox" name="delete[]" value="' . $rowData['id_member'] . '" class="input_check"' . ($rowData['id_member'] == $user_info['id'] || $rowData['id_group'] == 1 || in_array(1, explode(',', $rowData['additional_groups'])) ? ' disabled' : '') . '>';
578
					},
579
					'class' => 'centercol',
580
				),
581
			),
582
		),
583
		'form' => array(
584
			'href' => $scripturl . '?action=admin;area=viewmembers' . $context['params_url'],
585
			'include_start' => true,
586
			'include_sort' => true,
587
		),
588
		'additional_rows' => array(
589
			array(
590
				'position' => 'below_table_data',
591
				'value' => '<input type="submit" name="delete_members" value="' . $txt['admin_delete_members'] . '" data-confirm="' . $txt['confirm_delete_members'] . '" class="button_submit you_sure">',
592
			),
593
		),
594
	);
595
596
	// Without enough permissions, don't show 'delete members' checkboxes.
597
	if (!allowedTo('profile_remove_any'))
598
		unset($listOptions['cols']['check'], $listOptions['form'], $listOptions['additional_rows']);
599
600
	require_once($sourcedir . '/Subs-List.php');
601
	createList($listOptions);
602
603
	$context['sub_template'] = 'show_list';
604
	$context['default_list'] = 'member_list';
605
}
606
607
/**
608
 * Search the member list, using one or more criteria.
609
 * Called by ?action=admin;area=viewmembers;sa=search.
610
 * Requires the moderate_forum permission.
611
 * form is submitted to action=admin;area=viewmembers;sa=query.
612
 *
613
 * @uses the search_members sub template of the ManageMembers template.
614
 */
615
function SearchMembers()
616
{
617
	global $context, $txt, $smcFunc;
618
619
	// Get a list of all the membergroups and postgroups that can be selected.
620
	$context['membergroups'] = array(
621
		array(
622
			'id' => 0,
623
			'name' => $txt['membergroups_members'],
624
			'can_be_additional' => false
625
		)
626
	);
627
	$context['postgroups'] = array();
628
629
	$request = $smcFunc['db_query']('', '
630
		SELECT id_group, group_name, min_posts
631
		FROM {db_prefix}membergroups
632
		WHERE id_group != {int:moderator_group}
633
		ORDER BY min_posts, CASE WHEN id_group < {int:newbie_group} THEN id_group ELSE 4 END, group_name',
634
		array(
635
			'moderator_group' => 3,
636
			'newbie_group' => 4,
637
		)
638
	);
639 View Code Duplication
	while ($row = $smcFunc['db_fetch_assoc']($request))
640
	{
641
		if ($row['min_posts'] == -1)
642
			$context['membergroups'][] = array(
643
				'id' => $row['id_group'],
644
				'name' => $row['group_name'],
645
				'can_be_additional' => true
646
			);
647
		else
648
			$context['postgroups'][] = array(
649
				'id' => $row['id_group'],
650
				'name' => $row['group_name']
651
			);
652
	}
653
	$smcFunc['db_free_result']($request);
654
655
	$context['page_title'] = $txt['admin_members'];
656
	$context['sub_template'] = 'search_members';
657
}
658
659
/**
660
 * List all members who are awaiting approval / activation, sortable on different columns.
661
 * It allows instant approval or activation of (a selection of) members.
662
 * Called by ?action=admin;area=viewmembers;sa=browse;type=approve
663
 *  or ?action=admin;area=viewmembers;sa=browse;type=activate.
664
 * The form submits to ?action=admin;area=viewmembers;sa=approve.
665
 * Requires the moderate_forum permission.
666
 *
667
 * @uses the admin_browse sub template of the ManageMembers template.
668
 */
669
function MembersAwaitingActivation()
670
{
671
	global $txt, $context, $scripturl, $modSettings;
672
	global $sourcedir;
673
674
	// Not a lot here!
675
	$context['page_title'] = $txt['admin_members'];
676
	$context['sub_template'] = 'admin_browse';
677
	$context['browse_type'] = isset($_REQUEST['type']) ? $_REQUEST['type'] : (!empty($modSettings['registration_method']) && $modSettings['registration_method'] == 1 ? 'activate' : 'approve');
678
	if (isset($context['tabs'][$context['browse_type']]))
679
		$context['tabs'][$context['browse_type']]['is_selected'] = true;
680
681
	// Allowed filters are those we can have, in theory.
682
	$context['allowed_filters'] = $context['browse_type'] == 'approve' ? array(3, 4, 5) : array(0, 2);
683
	$context['current_filter'] = isset($_REQUEST['filter']) && in_array($_REQUEST['filter'], $context['allowed_filters']) && !empty($context['activation_numbers'][$_REQUEST['filter']]) ? (int) $_REQUEST['filter'] : -1;
684
685
	// Sort out the different sub areas that we can actually filter by.
686
	$context['available_filters'] = array();
687
	foreach ($context['activation_numbers'] as $type => $amount)
688
	{
689
		// We have some of these...
690
		if (in_array($type, $context['allowed_filters']) && $amount > 0)
691
			$context['available_filters'][] = array(
692
				'type' => $type,
693
				'amount' => $amount,
694
				'desc' => isset($txt['admin_browse_filter_type_' . $type]) ? $txt['admin_browse_filter_type_' . $type] : '?',
695
				'selected' => $type == $context['current_filter']
696
			);
697
	}
698
699
	// If the filter was not sent, set it to whatever has people in it!
700
	if ($context['current_filter'] == -1 && !empty($context['available_filters'][0]['amount']))
701
		$context['current_filter'] = $context['available_filters'][0]['type'];
702
703
	// This little variable is used to determine if we should flag where we are looking.
704
	$context['show_filter'] = ($context['current_filter'] != 0 && $context['current_filter'] != 3) || count($context['available_filters']) > 1;
705
706
	// The columns that can be sorted.
707
	$context['columns'] = array(
708
		'id_member' => array('label' => $txt['admin_browse_id']),
709
		'member_name' => array('label' => $txt['admin_browse_username']),
710
		'email_address' => array('label' => $txt['admin_browse_email']),
711
		'member_ip' => array('label' => $txt['admin_browse_ip']),
712
		'date_registered' => array('label' => $txt['admin_browse_registered']),
713
	);
714
715
	// Are we showing duplicate information?
716
	if (isset($_GET['showdupes']))
717
		$_SESSION['showdupes'] = (int) $_GET['showdupes'];
718
	$context['show_duplicates'] = !empty($_SESSION['showdupes']);
719
720
	// Determine which actions we should allow on this page.
721
	if ($context['browse_type'] == 'approve')
722
	{
723
		// If we are approving deleted accounts we have a slightly different list... actually a mirror ;)
724
		if ($context['current_filter'] == 4)
725
			$context['allowed_actions'] = array(
726
				'reject' => $txt['admin_browse_w_approve_deletion'],
727
				'ok' => $txt['admin_browse_w_reject'],
728
			);
729
		else
730
			$context['allowed_actions'] = array(
731
				'ok' => $txt['admin_browse_w_approve'],
732
				'okemail' => $txt['admin_browse_w_approve'] . ' ' . $txt['admin_browse_w_email'],
733
				'require_activation' => $txt['admin_browse_w_approve_require_activate'],
734
				'reject' => $txt['admin_browse_w_reject'],
735
				'rejectemail' => $txt['admin_browse_w_reject'] . ' ' . $txt['admin_browse_w_email'],
736
			);
737
	}
738
	elseif ($context['browse_type'] == 'activate')
739
		$context['allowed_actions'] = array(
740
			'ok' => $txt['admin_browse_w_activate'],
741
			'okemail' => $txt['admin_browse_w_activate'] . ' ' . $txt['admin_browse_w_email'],
742
			'delete' => $txt['admin_browse_w_delete'],
743
			'deleteemail' => $txt['admin_browse_w_delete'] . ' ' . $txt['admin_browse_w_email'],
744
			'remind' => $txt['admin_browse_w_remind'] . ' ' . $txt['admin_browse_w_email'],
745
		);
746
747
	// Create an option list for actions allowed to be done with selected members.
748
	$allowed_actions = '
749
			<option selected value="">' . $txt['admin_browse_with_selected'] . ':</option>
750
			<option value="" disabled>-----------------------------</option>';
751
	foreach ($context['allowed_actions'] as $key => $desc)
752
		$allowed_actions .= '
753
			<option value="' . $key . '">' . $desc . '</option>';
754
755
	// Setup the Javascript function for selecting an action for the list.
756
	$javascript = '
757
		function onSelectChange()
758
		{
759
			if (document.forms.postForm.todo.value == "")
760
				return;
761
762
			var message = "";';
763
764
	// We have special messages for approving deletion of accounts - it's surprisingly logical - honest.
765
	if ($context['current_filter'] == 4)
766
		$javascript .= '
767
			if (document.forms.postForm.todo.value.indexOf("reject") != -1)
768
				message = "' . $txt['admin_browse_w_delete'] . '";
769
			else
770
				message = "' . $txt['admin_browse_w_reject'] . '";';
771
	// Otherwise a nice standard message.
772
	else
773
		$javascript .= '
774
			if (document.forms.postForm.todo.value.indexOf("delete") != -1)
775
				message = "' . $txt['admin_browse_w_delete'] . '";
776
			else if (document.forms.postForm.todo.value.indexOf("reject") != -1)
777
				message = "' . $txt['admin_browse_w_reject'] . '";
778
			else if (document.forms.postForm.todo.value == "remind")
779
				message = "' . $txt['admin_browse_w_remind'] . '";
780
			else
781
				message = "' . ($context['browse_type'] == 'approve' ? $txt['admin_browse_w_approve'] : $txt['admin_browse_w_activate']) . '";';
782
	$javascript .= '
783
			if (confirm(message + " ' . $txt['admin_browse_warn'] . '"))
784
				document.forms.postForm.submit();
785
		}';
786
787
	$listOptions = array(
788
		'id' => 'approve_list',
789
// 		'title' => $txt['members_approval_title'],
0 ignored issues
show
Unused Code Comprehensibility introduced by
70% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
790
		'items_per_page' => $modSettings['defaultMaxMembers'],
791
		'base_href' => $scripturl . '?action=admin;area=viewmembers;sa=browse;type=' . $context['browse_type'] . (!empty($context['show_filter']) ? ';filter=' . $context['current_filter'] : ''),
792
		'default_sort_col' => 'date_registered',
793
		'get_items' => array(
794
			'file' => $sourcedir . '/Subs-Members.php',
795
			'function' => 'list_getMembers',
796
			'params' => array(
797
				'is_activated = {int:activated_status}',
798
				array('activated_status' => $context['current_filter']),
799
				$context['show_duplicates'],
800
			),
801
		),
802
		'get_count' => array(
803
			'file' => $sourcedir . '/Subs-Members.php',
804
			'function' => 'list_getNumMembers',
805
			'params' => array(
806
				'is_activated = {int:activated_status}',
807
				array('activated_status' => $context['current_filter']),
808
			),
809
		),
810
		'columns' => array(
811
			'id_member' => array(
812
				'header' => array(
813
					'value' => $txt['member_id'],
814
				),
815
				'data' => array(
816
					'db' => 'id_member',
817
				),
818
				'sort' => array(
819
					'default' => 'id_member',
820
					'reverse' => 'id_member DESC',
821
				),
822
			),
823
			'user_name' => array(
824
				'header' => array(
825
					'value' => $txt['username'],
826
				),
827
				'data' => array(
828
					'sprintf' => array(
829
						'format' => '<a href="' . strtr($scripturl, array('%' => '%%')) . '?action=profile;u=%1$d">%2$s</a>',
830
						'params' => array(
831
							'id_member' => false,
832
							'member_name' => false,
833
						),
834
					),
835
				),
836
				'sort' => array(
837
					'default' => 'member_name',
838
					'reverse' => 'member_name DESC',
839
				),
840
			),
841
			'email' => array(
842
				'header' => array(
843
					'value' => $txt['email_address'],
844
				),
845
				'data' => array(
846
					'sprintf' => array(
847
						'format' => '<a href="mailto:%1$s">%1$s</a>',
848
						'params' => array(
849
							'email_address' => true,
850
						),
851
					),
852
				),
853
				'sort' => array(
854
					'default' => 'email_address',
855
					'reverse' => 'email_address DESC',
856
				),
857
			),
858
			'ip' => array(
859
				'header' => array(
860
					'value' => $txt['ip_address'],
861
				),
862
				'data' => array(
863
					'sprintf' => array(
864
						'format' => '<a href="' . strtr($scripturl, array('%' => '%%')) . '?action=trackip;searchip=%1$s">%1$s</a>',
865
						'params' => array(
866
							'member_ip' => false,
867
						),
868
					),
869
				),
870
				'sort' => array(
871
					'default' => 'member_ip',
872
					'reverse' => 'member_ip DESC',
873
				),
874
			),
875
			'hostname' => array(
876
				'header' => array(
877
					'value' => $txt['hostname'],
878
				),
879
				'data' => array(
880
					'function' => function($rowData)
881
					{
882
						return host_from_ip(inet_dtop($rowData['member_ip']));
0 ignored issues
show
Security Bug introduced by
It seems like inet_dtop($rowData['member_ip']) targeting inet_dtop() can also be of type false; however, host_from_ip() does only seem to accept string, did you maybe forget to handle an error condition?
Loading history...
883
					},
884
					'class' => 'smalltext',
885
				),
886
			),
887
			'date_registered' => array(
888
				'header' => array(
889
					'value' => $context['current_filter'] == 4 ? $txt['viewmembers_online'] : $txt['date_registered'],
890
				),
891
				'data' => array(
892
					'function' => function($rowData) use ($context)
893
					{
894
						return timeformat($rowData['' . ($context['current_filter'] == 4 ? 'last_login' : 'date_registered') . '']);
895
					},
896
				),
897
				'sort' => array(
898
					'default' => $context['current_filter'] == 4 ? 'mem.last_login DESC' : 'date_registered DESC',
899
					'reverse' => $context['current_filter'] == 4 ? 'mem.last_login' : 'date_registered',
900
				),
901
			),
902
			'duplicates' => array(
903
				'header' => array(
904
					'value' => $txt['duplicates'],
905
					// Make sure it doesn't go too wide.
906
					'style' => 'width: 20%;',
907
				),
908
				'data' => array(
909
					'function' => function($rowData) use ($scripturl, $txt)
910
					{
911
						$member_links = array();
912
						foreach ($rowData['duplicate_members'] as $member)
913
						{
914
							if ($member['id'])
915
								$member_links[] = '<a href="' . $scripturl . '?action=profile;u=' . $member['id'] . '" ' . (!empty($member['is_banned']) ? 'class="red"' : '') . '>' . $member['name'] . '</a>';
916
							else
917
								$member_links[] = $member['name'] . ' (' . $txt['guest'] . ')';
918
						}
919
						return implode(', ', $member_links);
920
					},
921
					'class' => 'smalltext',
922
				),
923
			),
924
			'check' => array(
925
				'header' => array(
926
					'value' => '<input type="checkbox" onclick="invertAll(this, this.form);" class="input_check">',
927
					'class' => 'centercol',
928
				),
929
				'data' => array(
930
					'sprintf' => array(
931
						'format' => '<input type="checkbox" name="todoAction[]" value="%1$d" class="input_check">',
932
						'params' => array(
933
							'id_member' => false,
934
						),
935
					),
936
					'class' => 'centercol',
937
				),
938
			),
939
		),
940
		'javascript' => $javascript,
941
		'form' => array(
942
			'href' => $scripturl . '?action=admin;area=viewmembers;sa=approve;type=' . $context['browse_type'],
943
			'name' => 'postForm',
944
			'include_start' => true,
945
			'include_sort' => true,
946
			'hidden_fields' => array(
947
				'orig_filter' => $context['current_filter'],
948
			),
949
		),
950
		'additional_rows' => array(
951
			array(
952
				'position' => 'below_table_data',
953
				'value' => '
954
					[<a href="' . $scripturl . '?action=admin;area=viewmembers;sa=browse;showdupes=' . ($context['show_duplicates'] ? 0 : 1) . ';type=' . $context['browse_type'] . (!empty($context['show_filter']) ? ';filter=' . $context['current_filter'] : '') . ';' . $context['session_var'] . '=' . $context['session_id'] . '">' . ($context['show_duplicates'] ? $txt['dont_check_for_duplicate'] : $txt['check_for_duplicate']) . '</a>]
955
					<select name="todo" onchange="onSelectChange();">
956
						' . $allowed_actions . '
957
					</select>
958
					<noscript><input type="submit" value="' . $txt['go'] . '" class="button_submit"><br class="clear_right"></noscript>
959
				',
960
				'class' => 'floatright',
961
			),
962
		),
963
	);
964
965
	// Pick what column to actually include if we're showing duplicates.
966
	if ($context['show_duplicates'])
967
		unset($listOptions['columns']['email']);
968
	else
969
		unset($listOptions['columns']['duplicates']);
970
971
	// Only show hostname on duplicates as it takes a lot of time.
972
	if (!$context['show_duplicates'] || !empty($modSettings['disableHostnameLookup']))
973
		unset($listOptions['columns']['hostname']);
974
975
	// Is there any need to show filters?
976
	if (isset($context['available_filters']) && count($context['available_filters']) > 1)
977
	{
978
		$filterOptions = '
979
			<strong>' . $txt['admin_browse_filter_by'] . ':</strong>
980
			<select name="filter" onchange="this.form.submit();">';
981
		foreach ($context['available_filters'] as $filter)
982
			$filterOptions .= '
983
				<option value="' . $filter['type'] . '"' . ($filter['selected'] ? ' selected' : '') . '>' . $filter['desc'] . ' - ' . $filter['amount'] . ' ' . ($filter['amount'] == 1 ? $txt['user'] : $txt['users']) . '</option>';
984
		$filterOptions .= '
985
			</select>
986
			<noscript><input type="submit" value="' . $txt['go'] . '" name="filter" class="button_submit"></noscript>';
987
		$listOptions['additional_rows'][] = array(
988
			'position' => 'top_of_list',
989
			'value' => $filterOptions,
990
			'class' => 'righttext',
991
		);
992
	}
993
994
	// What about if we only have one filter, but it's not the "standard" filter - show them what they are looking at.
995
	if (!empty($context['show_filter']) && !empty($context['available_filters']))
996
		$listOptions['additional_rows'][] = array(
997
			'position' => 'above_column_headers',
998
			'value' => '<strong>' . $txt['admin_browse_filter_show'] . ':</strong> ' . $context['available_filters'][0]['desc'],
999
			'class' => 'smalltext floatright',
1000
		);
1001
1002
	// Now that we have all the options, create the list.
1003
	require_once($sourcedir . '/Subs-List.php');
1004
	createList($listOptions);
1005
}
1006
1007
/**
1008
 * This function handles the approval, rejection, activation or deletion of members.
1009
 * Called by ?action=admin;area=viewmembers;sa=approve.
1010
 * Requires the moderate_forum permission.
1011
 * Redirects to ?action=admin;area=viewmembers;sa=browse
1012
 * with the same parameters as the calling page.
1013
 */
1014
function AdminApprove()
1015
{
1016
	global $scripturl, $modSettings, $sourcedir, $language, $user_info, $smcFunc;
1017
1018
	// First, check our session.
1019
	checkSession();
1020
1021
	require_once($sourcedir . '/Subs-Post.php');
1022
1023
	// We also need to the login languages here - for emails.
1024
	loadLanguage('Login');
1025
1026
	// Sort out where we are going...
1027
	$current_filter = (int) $_REQUEST['orig_filter'];
1028
1029
	// If we are applying a filter do just that - then redirect.
1030
	if (isset($_REQUEST['filter']) && $_REQUEST['filter'] != $_REQUEST['orig_filter'])
1031
		redirectexit('action=admin;area=viewmembers;sa=browse;type=' . $_REQUEST['type'] . ';sort=' . $_REQUEST['sort'] . ';filter=' . $_REQUEST['filter'] . ';start=' . $_REQUEST['start']);
1032
1033
	// Nothing to do?
1034
	if (!isset($_POST['todoAction']) && !isset($_POST['time_passed']))
1035
		redirectexit('action=admin;area=viewmembers;sa=browse;type=' . $_REQUEST['type'] . ';sort=' . $_REQUEST['sort'] . ';filter=' . $current_filter . ';start=' . $_REQUEST['start']);
1036
1037
	// Are we dealing with members who have been waiting for > set amount of time?
1038
	if (isset($_POST['time_passed']))
1039
	{
1040
		$timeBefore = time() - 86400 * (int) $_POST['time_passed'];
1041
		$condition = '
1042
			AND date_registered < {int:time_before}';
1043
	}
1044
	// Coming from checkboxes - validate the members passed through to us.
1045
	else
1046
	{
1047
		$members = array();
1048
		foreach ($_POST['todoAction'] as $id)
1049
			$members[] = (int) $id;
1050
		$condition = '
1051
			AND id_member IN ({array_int:members})';
1052
	}
1053
1054
	// Get information on each of the members, things that are important to us, like email address...
1055
	$request = $smcFunc['db_query']('', '
1056
		SELECT id_member, member_name, real_name, email_address, validation_code, lngfile
1057
		FROM {db_prefix}members
1058
		WHERE is_activated = {int:activated_status}' . $condition . '
1059
		ORDER BY lngfile',
1060
		array(
1061
			'activated_status' => $current_filter,
1062
			'time_before' => empty($timeBefore) ? 0 : $timeBefore,
1063
			'members' => empty($members) ? array() : $members,
1064
		)
1065
	);
1066
1067
	$member_count = $smcFunc['db_num_rows']($request);
1068
1069
	// If no results then just return!
1070
	if ($member_count == 0)
1071
		redirectexit('action=admin;area=viewmembers;sa=browse;type=' . $_REQUEST['type'] . ';sort=' . $_REQUEST['sort'] . ';filter=' . $current_filter . ';start=' . $_REQUEST['start']);
1072
1073
	$member_info = array();
1074
	$members = array();
1075
	// Fill the info array.
1076
	while ($row = $smcFunc['db_fetch_assoc']($request))
1077
	{
1078
		$members[] = $row['id_member'];
1079
		$member_info[] = array(
1080
			'id' => $row['id_member'],
1081
			'username' => $row['member_name'],
1082
			'name' => $row['real_name'],
1083
			'email' => $row['email_address'],
1084
			'language' => empty($row['lngfile']) || empty($modSettings['userLanguage']) ? $language : $row['lngfile'],
1085
			'code' => $row['validation_code']
1086
		);
1087
	}
1088
	$smcFunc['db_free_result']($request);
1089
1090
	// Are we activating or approving the members?
1091
	if ($_POST['todo'] == 'ok' || $_POST['todo'] == 'okemail')
1092
	{
1093
		// Approve/activate this member.
1094
		$smcFunc['db_query']('', '
1095
			UPDATE {db_prefix}members
1096
			SET validation_code = {string:blank_string}, is_activated = {int:is_activated}
1097
			WHERE is_activated = {int:activated_status}' . $condition,
1098
			array(
1099
				'is_activated' => 1,
1100
				'time_before' => empty($timeBefore) ? 0 : $timeBefore,
1101
				'members' => empty($members) ? array() : $members,
1102
				'activated_status' => $current_filter,
1103
				'blank_string' => '',
1104
			)
1105
		);
1106
1107
		// Do we have to let the integration code know about the activations?
1108
		if (!empty($modSettings['integrate_activate']))
1109
		{
1110
			foreach ($member_info as $member)
1111
				call_integration_hook('integrate_activate', array($member['username']));
1112
		}
1113
1114
		// Check for email.
1115
		if ($_POST['todo'] == 'okemail')
1116
		{
1117
			foreach ($member_info as $member)
1118
			{
1119
				$replacements = array(
1120
					'NAME' => $member['name'],
1121
					'USERNAME' => $member['username'],
1122
					'PROFILELINK' => $scripturl . '?action=profile;u=' . $member['id'],
1123
					'FORGOTPASSWORDLINK' => $scripturl . '?action=reminder',
1124
				);
1125
1126
				$emaildata = loadEmailTemplate('admin_approve_accept', $replacements, $member['language']);
1127
				sendmail($member['email'], $emaildata['subject'], $emaildata['body'], null, 'accapp' . $member['id'], $emaildata['is_html'], 0);
1128
			}
1129
		}
1130
	}
1131
	// Maybe we're sending it off for activation?
1132
	elseif ($_POST['todo'] == 'require_activation')
1133
	{
1134
		require_once($sourcedir . '/Subs-Members.php');
1135
1136
		// We have to do this for each member I'm afraid.
1137
		foreach ($member_info as $member)
1138
		{
1139
			// Generate a random activation code.
1140
			$validation_code = generateValidationCode();
1141
1142
			// Set these members for activation - I know this includes two id_member checks but it's safer than bodging $condition ;).
1143
			$smcFunc['db_query']('', '
1144
				UPDATE {db_prefix}members
1145
				SET validation_code = {string:validation_code}, is_activated = {int:not_activated}
1146
				WHERE is_activated = {int:activated_status}
1147
					' . $condition . '
1148
					AND id_member = {int:selected_member}',
1149
				array(
1150
					'not_activated' => 0,
1151
					'activated_status' => $current_filter,
1152
					'selected_member' => $member['id'],
1153
					'validation_code' => $validation_code,
1154
					'time_before' => empty($timeBefore) ? 0 : $timeBefore,
1155
					'members' => empty($members) ? array() : $members,
1156
				)
1157
			);
1158
1159
			$replacements = array(
1160
				'USERNAME' => $member['name'],
1161
				'ACTIVATIONLINK' => $scripturl . '?action=activate;u=' . $member['id'] . ';code=' . $validation_code,
1162
				'ACTIVATIONLINKWITHOUTCODE' => $scripturl . '?action=activate;u=' . $member['id'],
1163
				'ACTIVATIONCODE' => $validation_code,
1164
			);
1165
1166
			$emaildata = loadEmailTemplate('admin_approve_activation', $replacements, $member['language']);
1167
			sendmail($member['email'], $emaildata['subject'], $emaildata['body'], null, 'accact' . $member['id'], $emaildata['is_html'], 0);
1168
		}
1169
	}
1170
	// Are we rejecting them?
1171 View Code Duplication
	elseif ($_POST['todo'] == 'reject' || $_POST['todo'] == 'rejectemail')
1172
	{
1173
		require_once($sourcedir . '/Subs-Members.php');
1174
		deleteMembers($members);
1175
1176
		// Send email telling them they aren't welcome?
1177
		if ($_POST['todo'] == 'rejectemail')
1178
		{
1179
			foreach ($member_info as $member)
1180
			{
1181
				$replacements = array(
1182
					'USERNAME' => $member['name'],
1183
				);
1184
1185
				$emaildata = loadEmailTemplate('admin_approve_reject', $replacements, $member['language']);
1186
				sendmail($member['email'], $emaildata['subject'], $emaildata['body'], null, 'accrej', $emaildata['is_html'], 1);
1187
			}
1188
		}
1189
	}
1190
	// A simple delete?
1191 View Code Duplication
	elseif ($_POST['todo'] == 'delete' || $_POST['todo'] == 'deleteemail')
1192
	{
1193
		require_once($sourcedir . '/Subs-Members.php');
1194
		deleteMembers($members);
1195
1196
		// Send email telling them they aren't welcome?
1197
		if ($_POST['todo'] == 'deleteemail')
1198
		{
1199
			foreach ($member_info as $member)
1200
			{
1201
				$replacements = array(
1202
					'USERNAME' => $member['name'],
1203
				);
1204
1205
				$emaildata = loadEmailTemplate('admin_approve_delete', $replacements, $member['language']);
1206
				sendmail($member['email'], $emaildata['subject'], $emaildata['body'], null, 'accdel', $emaildata['is_html'], 1);
1207
			}
1208
		}
1209
	}
1210
	// Remind them to activate their account?
1211
	elseif ($_POST['todo'] == 'remind')
1212
	{
1213
		foreach ($member_info as $member)
1214
		{
1215
			$replacements = array(
1216
				'USERNAME' => $member['name'],
1217
				'ACTIVATIONLINK' => $scripturl . '?action=activate;u=' . $member['id'] . ';code=' . $member['code'],
1218
				'ACTIVATIONLINKWITHOUTCODE' => $scripturl . '?action=activate;u=' . $member['id'],
1219
				'ACTIVATIONCODE' => $member['code'],
1220
			);
1221
1222
			$emaildata = loadEmailTemplate('admin_approve_remind', $replacements, $member['language']);
1223
			sendmail($member['email'], $emaildata['subject'], $emaildata['body'], null, 'accrem' . $member['id'], $emaildata['is_html'], 1);
1224
		}
1225
	}
1226
1227
	// @todo current_language is never set, no idea what this is for. Remove?
0 ignored issues
show
Coding Style Best Practice introduced by
Comments for TODO tasks are often forgotten in the code; it might be better to use a dedicated issue tracker.
Loading history...
1228
	// Back to the user's language!
1229
	if (isset($current_language) && $current_language != $user_info['language'])
0 ignored issues
show
Bug introduced by
The variable $current_language does not exist. Did you mean $language?

This check looks for variables that are accessed but have not been defined. It raises an issue if it finds another variable that has a similar name.

The variable may have been renamed without also renaming all references.

Loading history...
1230
	{
1231
		loadLanguage('index');
1232
		loadLanguage('ManageMembers');
1233
	}
1234
1235
	// Log what we did?
1236
	if (!empty($modSettings['modlog_enabled']) && in_array($_POST['todo'], array('ok', 'okemail', 'require_activation', 'remind')))
1237
	{
1238
		$log_action = $_POST['todo'] == 'remind' ? 'remind_member' : 'approve_member';
1239
1240
		require_once($sourcedir . '/Logging.php');
1241
		foreach ($member_info as $member)
1242
			logAction($log_action, array('member' => $member['id']), 'admin');
1243
	}
1244
1245
	// Although updateStats *may* catch this, best to do it manually just in case (Doesn't always sort out unapprovedMembers).
1246
	if (in_array($current_filter, array(3, 4, 5)))
1247
		updateSettings(array('unapprovedMembers' => ($modSettings['unapprovedMembers'] > $member_count ? $modSettings['unapprovedMembers'] - $member_count : 0)));
1248
1249
	// Update the member's stats. (but, we know the member didn't change their name.)
1250
	updateStats('member', false);
1251
1252
	// If they haven't been deleted, update the post group statistics on them...
1253
	if (!in_array($_POST['todo'], array('delete', 'deleteemail', 'reject', 'rejectemail', 'remind')))
1254
		updateStats('postgroups', $members);
1255
1256
	redirectexit('action=admin;area=viewmembers;sa=browse;type=' . $_REQUEST['type'] . ';sort=' . $_REQUEST['sort'] . ';filter=' . $current_filter . ';start=' . $_REQUEST['start']);
1257
}
1258
1259
/**
1260
 * Nifty function to calculate the number of days ago a given date was.
1261
 * Requires a unix timestamp as input, returns an integer.
1262
 * Named in honour of Jeff Lewis, the original creator of...this function.
1263
 *
1264
 * @param int $old The timestamp of the old date
1265
 * @return int The number of days since $old, based on the forum time
0 ignored issues
show
Documentation introduced by
Should the return type not be integer|double?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
1266
 */
1267
function jeffsdatediff($old)
1268
{
1269
	// Get the current time as the user would see it...
1270
	$forumTime = forum_time();
1271
1272
	// Calculate the seconds that have passed since midnight.
1273
	$sinceMidnight = date('H', $forumTime) * 60 * 60 + date('i', $forumTime) * 60 + date('s', $forumTime);
1274
1275
	// Take the difference between the two times.
1276
	$dis = time() - $old;
1277
1278
	// Before midnight?
1279
	if ($dis < $sinceMidnight)
1280
		return 0;
1281
	else
1282
		$dis -= $sinceMidnight;
1283
1284
	// Divide out the seconds in a day to get the number of days.
1285
	return ceil($dis / (24 * 60 * 60));
1286
}
1287
1288
?>