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

Profile-Actions.php ➔ list_getUserWarningCount()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 18
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 8
nc 1
nop 1
dl 0
loc 18
rs 9.4285
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * This file handles actions made on a user's profile.
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
 * Activate an account.
21
 *
22
 * @param int $memID The ID of the member whose account we're activating
23
 */
24
function activateAccount($memID)
25
{
26
	global $sourcedir, $context, $user_profile, $modSettings;
27
28
	isAllowedTo('moderate_forum');
29
30
	if (isset($_REQUEST['save']) && isset($user_profile[$memID]['is_activated']) && $user_profile[$memID]['is_activated'] != 1)
31
	{
32
		// If we are approving the deletion of an account, we do something special ;)
33
		if ($user_profile[$memID]['is_activated'] == 4)
34
		{
35
			require_once($sourcedir . '/Subs-Members.php');
36
			deleteMembers($context['id_member']);
37
			redirectexit();
38
		}
39
40
		// Let the integrations know of the activation.
41
		call_integration_hook('integrate_activate', array($user_profile[$memID]['member_name']));
42
43
		// Actually update this member now, as it guarantees the unapproved count can't get corrupted.
44
		updateMemberData($context['id_member'], array('is_activated' => $user_profile[$memID]['is_activated'] >= 10 ? 11 : 1, 'validation_code' => ''));
45
46
		// Log what we did?
47
		require_once($sourcedir . '/Logging.php');
48
		logAction('approve_member', array('member' => $memID), 'admin');
49
50
		// If we are doing approval, update the stats for the member just in case.
51
		if (in_array($user_profile[$memID]['is_activated'], array(3, 4, 5, 13, 14, 15)))
52
			updateSettings(array('unapprovedMembers' => ($modSettings['unapprovedMembers'] > 1 ? $modSettings['unapprovedMembers'] - 1 : 0)));
53
54
		// Make sure we update the stats too.
55
		updateStats('member', false);
56
	}
57
58
	// Leave it be...
59
	redirectexit('action=profile;u=' . $memID . ';area=summary');
60
}
61
62
/**
63
 * Issue/manage an user's warning status.
64
 *
65
 * @param int $memID The ID of the user
66
 */
67
function issueWarning($memID)
68
{
69
	global $txt, $scripturl, $modSettings, $user_info, $mbname;
70
	global $context, $cur_profile, $smcFunc, $sourcedir;
71
72
	// Get all the actual settings.
73
	list ($modSettings['warning_enable'], $modSettings['user_limit']) = explode(',', $modSettings['warning_settings']);
74
75
	// This stores any legitimate errors.
76
	$issueErrors = array();
77
78
	// Doesn't hurt to be overly cautious.
79
	if (empty($modSettings['warning_enable']) || ($context['user']['is_owner'] && !$cur_profile['warning']) || !allowedTo('issue_warning'))
80
		fatal_lang_error('no_access', false);
81
82
	// Get the base (errors related) stuff done.
83
	loadLanguage('Errors');
84
	$context['custom_error_title'] = $txt['profile_warning_errors_occured'];
85
86
	// Make sure things which are disabled stay disabled.
87
	$modSettings['warning_watch'] = !empty($modSettings['warning_watch']) ? $modSettings['warning_watch'] : 110;
88
	$modSettings['warning_moderate'] = !empty($modSettings['warning_moderate']) && !empty($modSettings['postmod_active']) ? $modSettings['warning_moderate'] : 110;
89
	$modSettings['warning_mute'] = !empty($modSettings['warning_mute']) ? $modSettings['warning_mute'] : 110;
90
91
	$context['warning_limit'] = allowedTo('admin_forum') ? 0 : $modSettings['user_limit'];
92
	$context['member']['warning'] = $cur_profile['warning'];
93
	$context['member']['name'] = $cur_profile['real_name'];
94
95
	// What are the limits we can apply?
96
	$context['min_allowed'] = 0;
97
	$context['max_allowed'] = 100;
98
	if ($context['warning_limit'] > 0)
99
	{
100
		// Make sure we cannot go outside of our limit for the day.
101
		$request = $smcFunc['db_query']('', '
102
			SELECT SUM(counter)
103
			FROM {db_prefix}log_comments
104
			WHERE id_recipient = {int:selected_member}
105
				AND id_member = {int:current_member}
106
				AND comment_type = {string:warning}
107
				AND log_time > {int:day_time_period}',
108
			array(
109
				'current_member' => $user_info['id'],
110
				'selected_member' => $memID,
111
				'day_time_period' => time() - 86400,
112
				'warning' => 'warning',
113
			)
114
		);
115
		list ($current_applied) = $smcFunc['db_fetch_row']($request);
116
		$smcFunc['db_free_result']($request);
117
118
		$context['min_allowed'] = max(0, $cur_profile['warning'] - $current_applied - $context['warning_limit']);
119
		$context['max_allowed'] = min(100, $cur_profile['warning'] - $current_applied + $context['warning_limit']);
120
	}
121
122
	// Defaults.
123
	$context['warning_data'] = array(
124
		'reason' => '',
125
		'notify' => '',
126
		'notify_subject' => '',
127
		'notify_body' => '',
128
	);
129
130
	// Are we saving?
131
	if (isset($_POST['save']))
132
	{
133
		// Security is good here.
134
		checkSession();
135
136
		// This cannot be empty!
137
		$_POST['warn_reason'] = isset($_POST['warn_reason']) ? trim($_POST['warn_reason']) : '';
138
		if ($_POST['warn_reason'] == '' && !$context['user']['is_owner'])
139
			$issueErrors[] = 'warning_no_reason';
140
		$_POST['warn_reason'] = $smcFunc['htmlspecialchars']($_POST['warn_reason']);
141
142
		$_POST['warning_level'] = (int) $_POST['warning_level'];
143
		$_POST['warning_level'] = max(0, min(100, $_POST['warning_level']));
144
		if ($_POST['warning_level'] < $context['min_allowed'])
145
			$_POST['warning_level'] = $context['min_allowed'];
146
		elseif ($_POST['warning_level'] > $context['max_allowed'])
147
			$_POST['warning_level'] = $context['max_allowed'];
148
149
		// Do we actually have to issue them with a PM?
150
		$id_notice = 0;
151
		if (!empty($_POST['warn_notify']) && empty($issueErrors))
152
		{
153
			$_POST['warn_sub'] = trim($_POST['warn_sub']);
154
			$_POST['warn_body'] = trim($_POST['warn_body']);
155
			if (empty($_POST['warn_sub']) || empty($_POST['warn_body']))
156
				$issueErrors[] = 'warning_notify_blank';
157
			// Send the PM?
158
			else
159
			{
160
				require_once($sourcedir . '/Subs-Post.php');
161
				$from = array(
162
					'id' => 0,
163
					'name' => $context['forum_name_html_safe'],
164
					'username' => $context['forum_name_html_safe'],
165
				);
166
				sendpm(array('to' => array($memID), 'bcc' => array()), $_POST['warn_sub'], $_POST['warn_body'], false, $from);
167
168
				// Log the notice!
169
				$id_notice = $smcFunc['db_insert']('',
170
					'{db_prefix}log_member_notices',
171
					array(
172
						'subject' => 'string-255', 'body' => 'string-65534',
173
					),
174
					array(
175
						$smcFunc['htmlspecialchars']($_POST['warn_sub']), $smcFunc['htmlspecialchars']($_POST['warn_body']),
176
					),
177
					array('id_notice'),
178
					1
179
				);
180
			}
181
		}
182
183
		// Just in case - make sure notice is valid!
184
		$id_notice = (int) $id_notice;
185
186
		// What have we changed?
187
		$level_change = $_POST['warning_level'] - $cur_profile['warning'];
188
189
		// No errors? Proceed! Only log if you're not the owner.
190
		if (empty($issueErrors))
191
		{
192
			// Log what we've done!
193
			if (!$context['user']['is_owner'])
194
				$smcFunc['db_insert']('',
195
					'{db_prefix}log_comments',
196
					array(
197
						'id_member' => 'int', 'member_name' => 'string', 'comment_type' => 'string', 'id_recipient' => 'int', 'recipient_name' => 'string-255',
198
						'log_time' => 'int', 'id_notice' => 'int', 'counter' => 'int', 'body' => 'string-65534',
199
					),
200
					array(
201
						$user_info['id'], $user_info['name'], 'warning', $memID, $cur_profile['real_name'],
202
						time(), $id_notice, $level_change, $_POST['warn_reason'],
203
					),
204
					array('id_comment')
205
				);
206
207
			// Make the change.
208
			updateMemberData($memID, array('warning' => $_POST['warning_level']));
209
210
			// Leave a lovely message.
211
			$context['profile_updated'] = $context['user']['is_owner'] ? $txt['profile_updated_own'] : $txt['profile_warning_success'];
212
		}
213
		else
214
		{
215
			// Try to remember some bits.
216
			$context['warning_data'] = array(
217
				'reason' => $_POST['warn_reason'],
218
				'notify' => !empty($_POST['warn_notify']),
219
				'notify_subject' => isset($_POST['warn_sub']) ? $_POST['warn_sub'] : '',
220
				'notify_body' => isset($_POST['warn_body']) ? $_POST['warn_body'] : '',
221
			);
222
		}
223
224
		// Show the new improved warning level.
225
		$context['member']['warning'] = $_POST['warning_level'];
226
	}
227
228
	if (isset($_POST['preview']))
229
	{
230
		$warning_body = !empty($_POST['warn_body']) ? trim(censorText($_POST['warn_body'])) : '';
231
		$context['preview_subject'] = !empty($_POST['warn_sub']) ? trim($smcFunc['htmlspecialchars']($_POST['warn_sub'])) : '';
232
		if (empty($_POST['warn_sub']) || empty($_POST['warn_body']))
233
			$issueErrors[] = 'warning_notify_blank';
234
235 View Code Duplication
		if (!empty($_POST['warn_body']))
236
		{
237
			require_once($sourcedir . '/Subs-Post.php');
238
239
			preparsecode($warning_body);
240
			$warning_body = parse_bbc($warning_body, true);
241
		}
242
243
		// Try to remember some bits.
244
		$context['warning_data'] = array(
245
			'reason' => $_POST['warn_reason'],
246
			'notify' => !empty($_POST['warn_notify']),
247
			'notify_subject' => isset($_POST['warn_sub']) ? $_POST['warn_sub'] : '',
248
			'notify_body' => isset($_POST['warn_body']) ? $_POST['warn_body'] : '',
249
			'body_preview' => $warning_body,
250
		);
251
	}
252
253
	if (!empty($issueErrors))
254
	{
255
		// Fill in the suite of errors.
256
		$context['post_errors'] = array();
257
		foreach ($issueErrors as $error)
258
			$context['post_errors'][] = $txt[$error];
259
	}
260
261
262
	$context['page_title'] = $txt['profile_issue_warning'];
263
264
	// Let's use a generic list to get all the current warnings
265
	require_once($sourcedir . '/Subs-List.php');
266
267
	// Work our the various levels.
268
	$context['level_effects'] = array(
269
		0 => $txt['profile_warning_effect_none'],
270
		$modSettings['warning_watch'] => $txt['profile_warning_effect_watch'],
271
		$modSettings['warning_moderate'] => $txt['profile_warning_effect_moderation'],
272
		$modSettings['warning_mute'] => $txt['profile_warning_effect_mute'],
273
	);
274
	$context['current_level'] = 0;
275 View Code Duplication
	foreach ($context['level_effects'] as $limit => $dummy)
276
		if ($context['member']['warning'] >= $limit)
277
			$context['current_level'] = $limit;
278
279
	$listOptions = array(
280
		'id' => 'view_warnings',
281
		'title' => $txt['profile_viewwarning_previous_warnings'],
282
		'items_per_page' => $modSettings['defaultMaxListItems'],
283
		'no_items_label' => $txt['profile_viewwarning_no_warnings'],
284
		'base_href' => $scripturl . '?action=profile;area=issuewarning;sa=user;u=' . $memID,
285
		'default_sort_col' => 'log_time',
286
		'get_items' => array(
287
			'function' => 'list_getUserWarnings',
288
			'params' => array(
289
				$memID,
290
			),
291
		),
292
		'get_count' => array(
293
			'function' => 'list_getUserWarningCount',
294
			'params' => array(
295
				$memID,
296
			),
297
		),
298
		'columns' => array(
299
			'issued_by' => array(
300
				'header' => array(
301
					'value' => $txt['profile_warning_previous_issued'],
302
					'style' => 'width: 20%;',
303
				),
304
				'data' => array(
305
					'function' => function($warning)
306
					{
307
						return $warning['issuer']['link'];
308
					},
309
				),
310
				'sort' => array(
311
					'default' => 'lc.member_name DESC',
312
					'reverse' => 'lc.member_name',
313
				),
314
			),
315
			'log_time' => array(
316
				'header' => array(
317
					'value' => $txt['profile_warning_previous_time'],
318
					'style' => 'width: 30%;',
319
				),
320
				'data' => array(
321
					'db' => 'time',
322
				),
323
				'sort' => array(
324
					'default' => 'lc.log_time DESC',
325
					'reverse' => 'lc.log_time',
326
				),
327
			),
328
			'reason' => array(
329
				'header' => array(
330
					'value' => $txt['profile_warning_previous_reason'],
331
				),
332
				'data' => array(
333 View Code Duplication
					'function' => function($warning) use ($scripturl, $txt)
334
					{
335
						$ret = '
336
						<div class="floatleft">
337
							' . $warning['reason'] . '
338
						</div>';
339
340
						if (!empty($warning['id_notice']))
341
							$ret .= '
342
						<div class="floatright">
343
							<a href="' . $scripturl . '?action=moderate;area=notice;nid=' . $warning['id_notice'] . '" onclick="window.open(this.href, \'\', \'scrollbars=yes,resizable=yes,width=400,height=250\');return false;" target="_blank" class="new_win" title="' . $txt['profile_warning_previous_notice'] . '"><span class="generic_icons filter centericon"></span></a>
344
						</div>';
345
346
						return $ret;
347
					},
348
				),
349
			),
350
			'level' => array(
351
				'header' => array(
352
					'value' => $txt['profile_warning_previous_level'],
353
					'style' => 'width: 6%;',
354
				),
355
				'data' => array(
356
					'db' => 'counter',
357
				),
358
				'sort' => array(
359
					'default' => 'lc.counter DESC',
360
					'reverse' => 'lc.counter',
361
				),
362
			),
363
		),
364
	);
365
366
	// Create the list for viewing.
367
	require_once($sourcedir . '/Subs-List.php');
368
	createList($listOptions);
369
370
	// Are they warning because of a message?
371
	if (isset($_REQUEST['msg']) && 0 < (int) $_REQUEST['msg'])
372
	{
373
		$request = $smcFunc['db_query']('', '
374
			SELECT subject
375
			FROM {db_prefix}messages AS m
376
				INNER JOIN {db_prefix}boards AS b ON (b.id_board = m.id_board)
377
			WHERE id_msg = {int:message}
378
				AND {query_see_board}
379
			LIMIT 1',
380
			array(
381
				'message' => (int) $_REQUEST['msg'],
382
			)
383
		);
384
		if ($smcFunc['db_num_rows']($request) != 0)
385
		{
386
			$context['warning_for_message'] = (int) $_REQUEST['msg'];
387
			list ($context['warned_message_subject']) = $smcFunc['db_fetch_row']($request);
388
		}
389
		$smcFunc['db_free_result']($request);
390
391
	}
392
393
	// Didn't find the message?
394
	if (empty($context['warning_for_message']))
395
	{
396
		$context['warning_for_message'] = 0;
397
		$context['warned_message_subject'] = '';
398
	}
399
400
	// Any custom templates?
401
	$context['notification_templates'] = array();
402
403
	$request = $smcFunc['db_query']('', '
404
		SELECT recipient_name AS template_title, body
405
		FROM {db_prefix}log_comments
406
		WHERE comment_type = {literal:warntpl}
407
			AND (id_recipient = {int:generic} OR id_recipient = {int:current_member})',
408
		array(
409
			'generic' => 0,
410
			'current_member' => $user_info['id'],
411
		)
412
	);
413
	while ($row = $smcFunc['db_fetch_assoc']($request))
414
	{
415
		// If we're not warning for a message skip any that are.
416
		if (!$context['warning_for_message'] && strpos($row['body'], '{MESSAGE}') !== false)
417
			continue;
418
419
		$context['notification_templates'][] = array(
420
			'title' => $row['template_title'],
421
			'body' => $row['body'],
422
		);
423
	}
424
	$smcFunc['db_free_result']($request);
425
426
	// Setup the "default" templates.
427
	foreach (array('spamming', 'offence', 'insulting') as $type)
428
		$context['notification_templates'][] = array(
429
			'title' => $txt['profile_warning_notify_title_' . $type],
430
			'body' => sprintf($txt['profile_warning_notify_template_outline' . (!empty($context['warning_for_message']) ? '_post' : '')], $txt['profile_warning_notify_for_' . $type]),
431
		);
432
433
	// Replace all the common variables in the templates.
434
	foreach ($context['notification_templates'] as $k => $name)
435
		$context['notification_templates'][$k]['body'] = strtr($name['body'], array('{MEMBER}' => un_htmlspecialchars($context['member']['name']), '{MESSAGE}' => '[url=' . $scripturl . '?msg=' . $context['warning_for_message'] . ']' . un_htmlspecialchars($context['warned_message_subject']) . '[/url]', '{SCRIPTURL}' => $scripturl, '{FORUMNAME}' => $mbname, '{REGARDS}' => $txt['regards_team']));
436
}
437
438
/**
439
 * Get the number of warnings a user has. Callback for $listOptions['get_count'] in issueWarning()
440
 *
441
 * @param int $memID The ID of the user
442
 * @return int Total number of warnings for the user
443
 */
444
function list_getUserWarningCount($memID)
445
{
446
	global $smcFunc;
447
448
	$request = $smcFunc['db_query']('', '
449
		SELECT COUNT(*)
450
		FROM {db_prefix}log_comments
451
		WHERE id_recipient = {int:selected_member}
452
			AND comment_type = {literal:warning}',
453
		array(
454
			'selected_member' => $memID,
455
		)
456
	);
457
	list ($total_warnings) = $smcFunc['db_fetch_row']($request);
458
	$smcFunc['db_free_result']($request);
459
460
	return $total_warnings;
461
}
462
463
/**
464
 * Get the data about a user's warnings. Callback function for the list in issueWarning()
465
 *
466
 * @param int $start The item to start with (for pagination purposes)
467
 * @param int $items_per_page How many items to show on each page
468
 * @param string $sort A string indicating how to sort the results
469
 * @param int $memID The member ID
470
 * @return array An array of information about the user's warnings
471
 */
472
function list_getUserWarnings($start, $items_per_page, $sort, $memID)
473
{
474
	global $smcFunc, $scripturl;
475
476
	$request = $smcFunc['db_query']('', '
477
		SELECT COALESCE(mem.id_member, 0) AS id_member, COALESCE(mem.real_name, lc.member_name) AS member_name,
478
			lc.log_time, lc.body, lc.counter, lc.id_notice
479
		FROM {db_prefix}log_comments AS lc
480
			LEFT JOIN {db_prefix}members AS mem ON (mem.id_member = lc.id_member)
481
		WHERE lc.id_recipient = {int:selected_member}
482
			AND lc.comment_type = {literal:warning}
483
		ORDER BY {raw:sort}
484
		LIMIT {int:start}, {int:max}',
485
		array(
486
			'selected_member' => $memID,
487
			'sort' => $sort,
488
			'start' => $start,
489
			'max' => $items_per_page,
490
		)
491
	);
492
	$previous_warnings = array();
493
	while ($row = $smcFunc['db_fetch_assoc']($request))
494
	{
495
		$previous_warnings[] = array(
496
			'issuer' => array(
497
				'id' => $row['id_member'],
498
				'link' => $row['id_member'] ? ('<a href="' . $scripturl . '?action=profile;u=' . $row['id_member'] . '">' . $row['member_name'] . '</a>') : $row['member_name'],
499
			),
500
			'time' => timeformat($row['log_time']),
501
			'reason' => $row['body'],
502
			'counter' => $row['counter'] > 0 ? '+' . $row['counter'] : $row['counter'],
503
			'id_notice' => $row['id_notice'],
504
		);
505
	}
506
	$smcFunc['db_free_result']($request);
507
508
	return $previous_warnings;
509
}
510
511
/**
512
 * Present a screen to make sure the user wants to be deleted
513
 *
514
 * @param int $memID The member ID
515
 */
516
function deleteAccount($memID)
0 ignored issues
show
Unused Code introduced by
The parameter $memID is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
517
{
518
	global $txt, $context, $modSettings, $cur_profile;
519
520 View Code Duplication
	if (!$context['user']['is_owner'])
521
		isAllowedTo('profile_remove_any');
522
	elseif (!allowedTo('profile_remove_any'))
523
		isAllowedTo('profile_remove_own');
524
525
	// Permissions for removing stuff...
526
	$context['can_delete_posts'] = !$context['user']['is_owner'] && allowedTo('moderate_forum');
527
528
	// Show an extra option if recycling is enabled...
529
	$context['show_perma_delete'] = !empty($modSettings['recycle_enable']) && !empty($modSettings['recycle_board']);
530
531
	// Can they do this, or will they need approval?
532
	$context['needs_approval'] = $context['user']['is_owner'] && !empty($modSettings['approveAccountDeletion']) && !allowedTo('moderate_forum');
533
	$context['page_title'] = $txt['deleteAccount'] . ': ' . $cur_profile['real_name'];
534
}
535
536
/**
537
 * Actually delete an account.
538
 *
539
 * @param int $memID The member ID
540
 */
541
function deleteAccount2($memID)
542
{
543
	global $user_info, $sourcedir, $context, $cur_profile, $modSettings, $smcFunc;
544
545
	// Try get more time...
546
	@set_time_limit(600);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
547
548
	// @todo Add a way to delete pms as well?
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...
549
550 View Code Duplication
	if (!$context['user']['is_owner'])
551
		isAllowedTo('profile_remove_any');
552
	elseif (!allowedTo('profile_remove_any'))
553
		isAllowedTo('profile_remove_own');
554
555
	checkSession();
556
557
	$old_profile = &$cur_profile;
558
559
	// Too often, people remove/delete their own only account.
560
	if (in_array(1, explode(',', $old_profile['additional_groups'])) || $old_profile['id_group'] == 1)
561
	{
562
		// Are you allowed to administrate the forum, as they are?
563
		isAllowedTo('admin_forum');
564
565
		$request = $smcFunc['db_query']('', '
566
			SELECT id_member
567
			FROM {db_prefix}members
568
			WHERE (id_group = {int:admin_group} OR FIND_IN_SET({int:admin_group}, additional_groups) != 0)
569
				AND id_member != {int:selected_member}
570
			LIMIT 1',
571
			array(
572
				'admin_group' => 1,
573
				'selected_member' => $memID,
574
			)
575
		);
576
		list ($another) = $smcFunc['db_fetch_row']($request);
577
		$smcFunc['db_free_result']($request);
578
579
		if (empty($another))
580
			fatal_lang_error('at_least_one_admin', 'critical');
581
	}
582
583
	// This file is needed for the deleteMembers function.
584
	require_once($sourcedir . '/Subs-Members.php');
585
586
	// Do you have permission to delete others profiles, or is that your profile you wanna delete?
587
	if ($memID != $user_info['id'])
588
	{
589
		isAllowedTo('profile_remove_any');
590
591
		// Before we go any further, handle possible poll vote deletion as well
592
		if (!empty($_POST['deleteVotes']) && allowedTo('moderate_forum'))
593
		{
594
			// First we find any polls that this user has voted in...
595
			$get_voted_polls = $smcFunc['db_query']('', '
596
				SELECT DISTINCT id_poll
597
				FROM {db_prefix}log_polls
598
				WHERE id_member = {int:selected_member}',
599
				array(
600
					'selected_member' => $memID,
601
				)
602
			);
603
604
			$polls_to_update = array();
605
606
			while ($row = $smcFunc['db_fetch_assoc']($get_voted_polls))
607
			{
608
				$polls_to_update[] = $row['id_poll'];
609
			}
610
611
			$smcFunc['db_free_result']($get_voted_polls);
612
613
			// Now we delete the votes and update the polls
614
			if (!empty($polls_to_update))
615
			{
616
				$smcFunc['db_query']('', '
617
					DELETE FROM {db_prefix}log_polls
618
					WHERE id_member = {int:selected_member}',
619
					array(
620
						'selected_member' => $memID,
621
					)
622
				);
623
624
				$smcFunc['db_query']('', '
625
					UPDATE {db_prefix}polls
626
					SET votes = votes - 1
627
					WHERE id_poll IN {array_int:polls_to_update}',
628
					array(
629
						'polls_to_update' => $polls_to_update
630
					)
631
				);
632
			}
633
		}
634
635
		// Now, have you been naughty and need your posts deleting?
636
		// @todo Should this check board permissions?
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...
637
		if (!empty($_POST['deletePosts']) && in_array($_POST['remove_type'], array('posts', 'topics')) && allowedTo('moderate_forum'))
638
		{
639
			// Include RemoveTopics - essential for this type of work!
640
			require_once($sourcedir . '/RemoveTopic.php');
641
642
			$extra = empty($_POST['perma_delete']) ? ' AND t.id_board != {int:recycle_board}' : '';
643
			$recycle_board = empty($modSettings['recycle_board']) ? 0 : $modSettings['recycle_board'];
644
645
			// First off we delete any topics the member has started - if they wanted topics being done.
646
			if ($_POST['remove_type'] == 'topics')
647
			{
648
				// Fetch all topics started by this user within the time period.
649
				$request = $smcFunc['db_query']('', '
650
					SELECT t.id_topic
651
					FROM {db_prefix}topics AS t
652
					WHERE t.id_member_started = {int:selected_member}' . $extra,
653
					array(
654
						'selected_member' => $memID,
655
						'recycle_board' => $recycle_board,
656
					)
657
				);
658
				$topicIDs = array();
659
				while ($row = $smcFunc['db_fetch_assoc']($request))
660
					$topicIDs[] = $row['id_topic'];
661
				$smcFunc['db_free_result']($request);
662
663
				// Actually remove the topics. Ignore recycling if we want to perma-delete things...
664
				// @todo This needs to check permissions, but we'll let it slide for now because of moderate_forum already being had.
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...
665
				removeTopics($topicIDs, true, !empty($extra));
666
			}
667
668
			// Now delete the remaining messages.
669
			$request = $smcFunc['db_query']('', '
670
				SELECT m.id_msg
671
				FROM {db_prefix}messages AS m
672
					INNER JOIN {db_prefix}topics AS t ON (t.id_topic = m.id_topic
673
						AND t.id_first_msg != m.id_msg)
674
				WHERE m.id_member = {int:selected_member}' . $extra,
675
				array(
676
					'selected_member' => $memID,
677
					'recycle_board' => $recycle_board,
678
				)
679
			);
680
			// This could take a while... but ya know it's gonna be worth it in the end.
681
			while ($row = $smcFunc['db_fetch_assoc']($request))
682
			{
683
				if (function_exists('apache_reset_timeout'))
684
					@apache_reset_timeout();
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
685
686
				removeMessage($row['id_msg']);
687
			}
688
			$smcFunc['db_free_result']($request);
689
		}
690
691
		// Only delete this poor members account if they are actually being booted out of camp.
692
		if (isset($_POST['deleteAccount']))
693
			deleteMembers($memID);
694
	}
695
	// Do they need approval to delete?
696
	elseif (!empty($modSettings['approveAccountDeletion']) && !allowedTo('moderate_forum'))
697
	{
698
		// Setup their account for deletion ;)
699
		updateMemberData($memID, array('is_activated' => 4));
700
		// Another account needs approval...
701
		updateSettings(array('unapprovedMembers' => true), true);
702
	}
703
	// Also check if you typed your password correctly.
704
	else
705
	{
706
		deleteMembers($memID);
707
708
		require_once($sourcedir . '/LogInOut.php');
709
		LogOut(true);
710
711
		redirectexit();
712
	}
713
}
714
715
/**
716
 * Function for doing all the paid subscription stuff - kinda.
717
 *
718
 * @param int $memID The ID of the user whose subscriptions we're viewing
719
 */
720
function subscriptions($memID)
721
{
722
	global $context, $txt, $sourcedir, $modSettings, $smcFunc, $scripturl;
723
724
	// Load the paid template anyway.
725
	loadTemplate('ManagePaid');
726
	loadLanguage('ManagePaid');
727
728
	// Load all of the subscriptions.
729
	require_once($sourcedir . '/ManagePaid.php');
730
	loadSubscriptions();
731
	$context['member']['id'] = $memID;
732
733
	// Remove any invalid ones.
734
	foreach ($context['subscriptions'] as $id => $sub)
735
	{
736
		// Work out the costs.
737
		$costs = $smcFunc['json_decode']($sub['real_cost'], true);
738
739
		$cost_array = array();
740
		if ($sub['real_length'] == 'F')
741
		{
742
			foreach ($costs as $duration => $cost)
743
			{
744
				if ($cost != 0)
745
					$cost_array[$duration] = $cost;
746
			}
747
		}
748
		else
749
		{
750
			$cost_array['fixed'] = $costs['fixed'];
751
		}
752
753
		if (empty($cost_array))
754
			unset($context['subscriptions'][$id]);
755
		else
756
		{
757
			$context['subscriptions'][$id]['member'] = 0;
758
			$context['subscriptions'][$id]['subscribed'] = false;
759
			$context['subscriptions'][$id]['costs'] = $cost_array;
760
		}
761
	}
762
763
	// Work out what gateways are enabled.
764
	$gateways = loadPaymentGateways();
765
	foreach ($gateways as $id => $gateway)
766
	{
767
		$gateways[$id] = new $gateway['display_class']();
768
		if (!$gateways[$id]->gatewayEnabled())
769
			unset($gateways[$id]);
770
	}
771
772
	// No gateways yet?
773
	if (empty($gateways))
774
		fatal_error($txt['paid_admin_not_setup_gateway']);
775
776
	// Get the current subscriptions.
777
	$request = $smcFunc['db_query']('', '
778
		SELECT id_sublog, id_subscribe, start_time, end_time, status, payments_pending, pending_details
779
		FROM {db_prefix}log_subscribed
780
		WHERE id_member = {int:selected_member}',
781
		array(
782
			'selected_member' => $memID,
783
		)
784
	);
785
	$context['current'] = array();
786
	while ($row = $smcFunc['db_fetch_assoc']($request))
787
	{
788
		// The subscription must exist!
789
		if (!isset($context['subscriptions'][$row['id_subscribe']]))
790
			continue;
791
792
		$context['current'][$row['id_subscribe']] = array(
793
			'id' => $row['id_sublog'],
794
			'sub_id' => $row['id_subscribe'],
795
			'hide' => $row['status'] == 0 && $row['end_time'] == 0 && $row['payments_pending'] == 0,
796
			'name' => $context['subscriptions'][$row['id_subscribe']]['name'],
797
			'start' => timeformat($row['start_time'], false),
798
			'end' => $row['end_time'] == 0 ? $txt['not_applicable'] : timeformat($row['end_time'], false),
799
			'pending_details' => $row['pending_details'],
800
			'status' => $row['status'],
801
			'status_text' => $row['status'] == 0 ? ($row['payments_pending'] ? $txt['paid_pending'] : $txt['paid_finished']) : $txt['paid_active'],
802
		);
803
804
		if ($row['status'] == 1)
805
			$context['subscriptions'][$row['id_subscribe']]['subscribed'] = true;
806
	}
807
	$smcFunc['db_free_result']($request);
808
809
	// Simple "done"?
810
	if (isset($_GET['done']))
811
	{
812
		$_GET['sub_id'] = (int) $_GET['sub_id'];
813
814
		// Must exist but let's be sure...
815
		if (isset($context['current'][$_GET['sub_id']]))
816
		{
817
			// What are the details like?
818
			$current_pending = $smcFunc['json_decode']($context['current'][$_GET['sub_id']]['pending_details'], true);
819
			if (!empty($current_pending))
820
			{
821
				$current_pending = array_reverse($current_pending);
822
				foreach ($current_pending as $id => $sub)
823
				{
824
					// Just find one and change it.
825
					if ($sub[0] == $_GET['sub_id'] && $sub[3] == 'prepay')
826
					{
827
						$current_pending[$id][3] = 'payback';
828
						break;
829
					}
830
				}
831
832
				// Save the details back.
833
				$pending_details = $smcFunc['json_encode']($current_pending);
834
835
				$smcFunc['db_query']('', '
836
					UPDATE {db_prefix}log_subscribed
837
					SET payments_pending = payments_pending + 1, pending_details = {string:pending_details}
838
					WHERE id_sublog = {int:current_subscription_id}
839
						AND id_member = {int:selected_member}',
840
					array(
841
						'current_subscription_id' => $context['current'][$_GET['sub_id']]['id'],
842
						'selected_member' => $memID,
843
						'pending_details' => $pending_details,
844
					)
845
				);
846
			}
847
		}
848
849
		$context['sub_template'] = 'paid_done';
850
		return;
851
	}
852
	// If this is confirmation then it's simpler...
853
	if (isset($_GET['confirm']) && isset($_POST['sub_id']) && is_array($_POST['sub_id']))
854
	{
855
		// Hopefully just one.
856
		foreach ($_POST['sub_id'] as $k => $v)
857
			$ID_SUB = (int) $k;
858
859
		if (!isset($context['subscriptions'][$ID_SUB]) || $context['subscriptions'][$ID_SUB]['active'] == 0)
0 ignored issues
show
Bug introduced by
The variable $ID_SUB does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
860
			fatal_lang_error('paid_sub_not_active');
861
862
		// Simplify...
863
		$context['sub'] = $context['subscriptions'][$ID_SUB];
864
		$period = 'xx';
865
		if ($context['sub']['flexible'])
866
			$period = isset($_POST['cur'][$ID_SUB]) && isset($context['sub']['costs'][$_POST['cur'][$ID_SUB]]) ? $_POST['cur'][$ID_SUB] : 'xx';
867
868
		// Check we have a valid cost.
869
		if ($context['sub']['flexible'] && $period == 'xx')
870
			fatal_lang_error('paid_sub_not_active');
871
872
		// Sort out the cost/currency.
873
		$context['currency'] = $modSettings['paid_currency_code'];
874
		$context['recur'] = $context['sub']['repeatable'];
875
876
		if ($context['sub']['flexible'])
877
		{
878
			// Real cost...
879
			$context['value'] = $context['sub']['costs'][$_POST['cur'][$ID_SUB]];
880
			$context['cost'] = sprintf($modSettings['paid_currency_symbol'], $context['value']) . '/' . $txt[$_POST['cur'][$ID_SUB]];
881
			// The period value for paypal.
882
			$context['paypal_period'] = strtoupper(substr($_POST['cur'][$ID_SUB], 0, 1));
883
		}
884
		else
885
		{
886
			// Real cost...
887
			$context['value'] = $context['sub']['costs']['fixed'];
888
			$context['cost'] = sprintf($modSettings['paid_currency_symbol'], $context['value']);
889
890
			// Recur?
891
			preg_match('~(\d*)(\w)~', $context['sub']['real_length'], $match);
892
			$context['paypal_unit'] = $match[1];
893
			$context['paypal_period'] = $match[2];
894
		}
895
896
		// Setup the gateway context.
897
		$context['gateways'] = array();
898
		foreach ($gateways as $id => $gateway)
899
		{
900
			$fields = $gateways[$id]->fetchGatewayFields($context['sub']['id'] . '+' . $memID, $context['sub'], $context['value'], $period, $scripturl . '?action=profile;u=' . $memID . ';area=subscriptions;sub_id=' . $context['sub']['id'] . ';done');
901
			if (!empty($fields['form']))
902
				$context['gateways'][] = $fields;
903
		}
904
905
		// Bugger?!
906
		if (empty($context['gateways']))
907
			fatal_error($txt['paid_admin_not_setup_gateway']);
908
909
		// Now we are going to assume they want to take this out ;)
910
		$new_data = array($context['sub']['id'], $context['value'], $period, 'prepay');
911
		if (isset($context['current'][$context['sub']['id']]))
912
		{
913
			// What are the details like?
914
			$current_pending = array();
915
			if ($context['current'][$context['sub']['id']]['pending_details'] != '')
916
				$current_pending = $smcFunc['json_decode']($context['current'][$context['sub']['id']]['pending_details'], true);
917
			// Don't get silly.
918
			if (count($current_pending) > 9)
919
				$current_pending = array();
920
			$pending_count = 0;
921
			// Only record real pending payments as will otherwise confuse the admin!
922
			foreach ($current_pending as $pending)
923
				if ($pending[3] == 'payback')
924
					$pending_count++;
925
926
			if (!in_array($new_data, $current_pending))
927
			{
928
				$current_pending[] = $new_data;
929
				$pending_details = $smcFunc['json_encode']($current_pending);
930
931
				$smcFunc['db_query']('', '
932
					UPDATE {db_prefix}log_subscribed
933
					SET payments_pending = {int:pending_count}, pending_details = {string:pending_details}
934
					WHERE id_sublog = {int:current_subscription_item}
935
						AND id_member = {int:selected_member}',
936
					array(
937
						'pending_count' => $pending_count,
938
						'current_subscription_item' => $context['current'][$context['sub']['id']]['id'],
939
						'selected_member' => $memID,
940
						'pending_details' => $pending_details,
941
					)
942
				);
943
			}
944
945
		}
946
		// Never had this before, lovely.
947
		else
948
		{
949
			$pending_details = $smcFunc['json_encode'](array($new_data));
950
			$smcFunc['db_insert']('',
951
				'{db_prefix}log_subscribed',
952
				array(
953
					'id_subscribe' => 'int', 'id_member' => 'int', 'status' => 'int', 'payments_pending' => 'int', 'pending_details' => 'string-65534',
954
					'start_time' => 'int', 'vendor_ref' => 'string-255',
955
				),
956
				array(
957
					$context['sub']['id'], $memID, 0, 0, $pending_details,
958
					time(), '',
959
				),
960
				array('id_sublog')
961
			);
962
		}
963
964
		// Change the template.
965
		$context['sub_template'] = 'choose_payment';
966
967
		// Quit.
968
		return;
969
	}
970
	else
971
		$context['sub_template'] = 'user_subscription';
972
}
973
974
?>