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

ManagePaid.php ➔ ModifySubscriptionSettings()   D

Complexity

Conditions 18
Paths 70

Size

Total Lines 154
Code Lines 65

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 18
eloc 65
nc 70
nop 1
dl 0
loc 154
rs 4.7996
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
/**
4
 * This file contains all the administration functions for subscriptions.
5
 * (and some more than that :P)
6
 *
7
 * Simple Machines Forum (SMF)
8
 *
9
 * @package SMF
10
 * @author Simple Machines http://www.simplemachines.org
11
 * @copyright 2017 Simple Machines and individual contributors
12
 * @license http://www.simplemachines.org/about/smf/license.php BSD
13
 *
14
 * @version 2.1 Beta 4
15
 */
16
17
if (!defined('SMF'))
18
	die('No direct access...');
19
20
/**
21
 * The main entrance point for the 'Paid Subscription' screen, calling
22
 * the right function based on the given sub-action.
23
 * It defaults to sub-action 'view'.
24
 * Accessed from ?action=admin;area=paidsubscribe.
25
 * It requires admin_forum permission for admin based actions.
26
 */
27
function ManagePaidSubscriptions()
28
{
29
	global $context, $txt, $modSettings;
30
31
	// Load the required language and template.
32
	loadLanguage('ManagePaid');
33
	loadTemplate('ManagePaid');
34
35
	if (!empty($modSettings['paid_enabled']))
36
		$subActions = array(
37
			'modify' => array('ModifySubscription', 'admin_forum'),
38
			'modifyuser' => array('ModifyUserSubscription', 'admin_forum'),
39
			'settings' => array('ModifySubscriptionSettings', 'admin_forum'),
40
			'view' => array('ViewSubscriptions', 'admin_forum'),
41
			'viewsub' => array('ViewSubscribedUsers', 'admin_forum'),
42
		);
43
	else
44
		$subActions = array(
45
			'settings' => array('ModifySubscriptionSettings', 'admin_forum'),
46
		);
47
48
	// Default the sub-action to 'view subscriptions', but only if they have already set things up..
49
	$_REQUEST['sa'] = isset($_REQUEST['sa']) && isset($subActions[$_REQUEST['sa']]) ? $_REQUEST['sa'] : (!empty($modSettings['paid_currency_symbol']) && !empty($modSettings['paid_enabled']) ? 'view' : 'settings');
50
51
	// Make sure you can do this.
52
	isAllowedTo($subActions[$_REQUEST['sa']][1]);
53
54
	$context['page_title'] = $txt['paid_subscriptions'];
55
56
	// Tabs for browsing the different subscription functions.
57
	$context[$context['admin_menu_name']]['tab_data'] = array(
58
		'title' => $txt['paid_subscriptions'],
59
		'help' => '',
60
		'description' => $txt['paid_subscriptions_desc'],
61
	);
62 View Code Duplication
	if (!empty($modSettings['paid_enabled']))
63
		$context[$context['admin_menu_name']]['tab_data']['tabs'] = array(
64
			'view' => array(
65
				'description' => $txt['paid_subs_view_desc'],
66
			),
67
			'settings' => array(
68
				'description' => $txt['paid_subs_settings_desc'],
69
			),
70
		);
71
72
	call_integration_hook('integrate_manage_subscriptions', array(&$subActions));
73
74
	// Call the right function for this sub-action.
75
	call_helper($subActions[$_REQUEST['sa']][0]);
76
}
77
78
/**
79
 * Set any setting related to paid subscriptions, i.e.
80
 * modify which payment methods are to be used.
81
 * It requires the moderate_forum permission
82
 * Accessed from ?action=admin;area=paidsubscribe;sa=settings.
83
 *
84
 * @param bool $return_config Whether or not to return the $config_vars array (used for admin search)
85
 * @return void|array Returns nothing or returns the config_vars array if $return_config is true
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use array<*,string[]|string|...rray>|array|array>|null.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
86
 */
87
function ModifySubscriptionSettings($return_config = false)
88
{
89
	global $context, $txt, $modSettings, $sourcedir, $smcFunc, $scripturl;
90
91
	if (!empty($modSettings['paid_enabled']))
92
	{
93
		// If the currency is set to something different then we need to set it to other for this to work and set it back shortly.
94
		$modSettings['paid_currency'] = !empty($modSettings['paid_currency_code']) ? $modSettings['paid_currency_code'] : '';
95
		if (!empty($modSettings['paid_currency_code']) && !in_array($modSettings['paid_currency_code'], array('usd', 'eur', 'gbp', 'cad', 'aud')))
96
			$modSettings['paid_currency'] = 'other';
97
98
		// These are all the default settings.
99
		$config_vars = array(
100
				array('check', 'paid_enabled'),
101
			'',
102
				array('select', 'paid_email', array(0 => $txt['paid_email_no'], 1 => $txt['paid_email_error'], 2 => $txt['paid_email_all']), 'subtext' => $txt['paid_email_desc']),
103
				array('email', 'paid_email_to', 'subtext' => $txt['paid_email_to_desc'], 'size' => 60),
104
			'',
105
				'dummy_currency' => array('select', 'paid_currency', array('usd' => $txt['usd'], 'eur' => $txt['eur'], 'gbp' => $txt['gbp'], 'cad' => $txt['cad'], 'aud' => $txt['aud'], 'other' => $txt['other']), 'javascript' => 'onchange="toggleOther();"'),
106
				array('text', 'paid_currency_code', 'subtext' => $txt['paid_currency_code_desc'], 'size' => 5, 'force_div_id' => 'custom_currency_code_div'),
107
				array('text', 'paid_currency_symbol', 'subtext' => $txt['paid_currency_symbol_desc'], 'size' => 8, 'force_div_id' => 'custom_currency_symbol_div'),
108
				array('check', 'paidsubs_test', 'subtext' => $txt['paidsubs_test_desc'], 'onclick' => 'return document.getElementById(\'paidsubs_test\').checked ? confirm(\'' . $txt['paidsubs_test_confirm'] . '\') : true;'),
109
		);
110
111
		// Now load all the other gateway settings.
112
		$gateways = loadPaymentGateways();
113
		foreach ($gateways as $gateway)
114
		{
115
			$gatewayClass = new $gateway['display_class']();
116
			$setting_data = $gatewayClass->getGatewaySettings();
117
			if (!empty($setting_data))
118
			{
119
				$config_vars[] = array('title', $gatewayClass->title, 'text_label' => (isset($txt['paidsubs_gateway_title_' . $gatewayClass->title]) ? $txt['paidsubs_gateway_title_' . $gatewayClass->title] : $gatewayClass->title));
120
				$config_vars = array_merge($config_vars, $setting_data);
121
			}
122
		}
123
124
		$context['settings_message'] = $txt['paid_note'];
125
		$context[$context['admin_menu_name']]['current_subsection'] = 'settings';
126
		$context['settings_title'] = $txt['settings'];
127
128
		// We want javascript for our currency options.
129
		addInlineJavaScript('
130
		function toggleOther()
131
		{
132
			var otherOn = document.getElementById("paid_currency").value == \'other\';
133
			var currencydd = document.getElementById("custom_currency_code_div_dd");
134
135
			if (otherOn)
136
			{
137
				document.getElementById("custom_currency_code_div").style.display = "";
138
				document.getElementById("custom_currency_symbol_div").style.display = "";
139
140
				if (currencydd)
141
				{
142
					document.getElementById("custom_currency_code_div_dd").style.display = "";
143
					document.getElementById("custom_currency_symbol_div_dd").style.display = "";
144
				}
145
			}
146
			else
147
			{
148
				document.getElementById("custom_currency_code_div").style.display = "none";
149
				document.getElementById("custom_currency_symbol_div").style.display = "none";
150
151
				if (currencydd)
152
				{
153
					document.getElementById("custom_currency_symbol_div_dd").style.display = "none";
154
					document.getElementById("custom_currency_code_div_dd").style.display = "none";
155
				}
156
			}
157
		}
158
		toggleOther();', true);
159
	}
160
	else
161
	{
162
		$config_vars = array(
163
			array('check', 'paid_enabled'),
164
		);
165
		$context['settings_title'] = $txt['paid_subscriptions'];
166
	}
167
168
	// Just searching?
169
	if ($return_config)
170
		return $config_vars;
171
172
	// Get the settings template fired up.
173
	require_once($sourcedir . '/ManageServer.php');
174
175
	// Some important context stuff
176
	$context['page_title'] = $txt['settings'];
177
	$context['sub_template'] = 'show_settings';
178
179
	// Get the final touches in place.
180
	$context['post_url'] = $scripturl . '?action=admin;area=paidsubscribe;save;sa=settings';
181
182
	// Saving the settings?
183
	if (isset($_GET['save']))
184
	{
185
		checkSession();
186
187
		$old = !empty($modSettings['paid_enabled']);
188
		$new = !empty($_POST['paid_enabled']);
189
		if ($old != $new)
190
		{
191
			// So we're changing this fundamental status. Great.
192
			$smcFunc['db_query']('', '
193
				UPDATE {db_prefix}scheduled_tasks
194
				SET disabled = {int:disabled}
195
				WHERE task = {string:task}',
196
				array(
197
					'disabled' => $new ? 0 : 1,
198
					'task' => 'paid_subscriptions',
199
				)
200
			);
201
202
			// This may well affect the next trigger, whether we're enabling or not.
203
			require_once($sourcedir . '/ScheduledTasks.php');
204
			CalculateNextTrigger('paid_subscriptions');
205
		}
206
207
		// Check the email addresses were actually email addresses.
208
		if (!empty($_POST['paid_email_to']))
209
		{
210
			$email_addresses = array();
211
			foreach (explode(',', $_POST['paid_email_to']) as $email)
212
			{
213
				$email = trim($email);
214
				if (!empty($email) && filter_var($email, FILTER_VALIDATE_EMAIL))
215
					$email_addresses[] = $email;
216
				$_POST['paid_email_to'] = implode(',', $email_addresses);
217
			}
218
		}
219
220
		// Can only handle this stuff if it's already enabled...
221
		if (!empty($modSettings['paid_enabled']))
222
		{
223
			// Sort out the currency stuff.
224
			if ($_POST['paid_currency'] != 'other')
225
			{
226
				$_POST['paid_currency_code'] = $_POST['paid_currency'];
227
				$_POST['paid_currency_symbol'] = $txt[$_POST['paid_currency'] . '_symbol'];
228
			}
229
			unset($config_vars['dummy_currency']);
230
		}
231
232
		saveDBSettings($config_vars);
233
		$_SESSION['adm-save'] = true;
234
235
		redirectexit('action=admin;area=paidsubscribe;sa=settings');
236
	}
237
238
	// Prepare the settings...
239
	prepareDBSettingContext($config_vars);
240
}
241
242
/**
243
 * View a list of all the current subscriptions
244
 * Requires the admin_forum permission.
245
 * Accessed from ?action=admin;area=paidsubscribe;sa=view.
246
 */
247
function ViewSubscriptions()
248
{
249
	global $context, $txt, $modSettings, $sourcedir, $scripturl;
250
251
	// Not made the settings yet?
252
	if (empty($modSettings['paid_currency_symbol']))
253
		fatal_lang_error('paid_not_set_currency', false, $scripturl . '?action=admin;area=paidsubscribe;sa=settings');
0 ignored issues
show
Documentation introduced by
$scripturl . '?action=ad...dsubscribe;sa=settings' is of type string, but the function expects a array.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
254
255
	// Some basic stuff.
256
	$context['page_title'] = $txt['paid_subs_view'];
257
	loadSubscriptions();
258
259
	$listOptions = array(
260
		'id' => 'subscription_list',
261
		'title' => $txt['subscriptions'],
262
		'items_per_page' => $modSettings['defaultMaxListItems'],
263
		'base_href' => $scripturl . '?action=admin;area=paidsubscribe;sa=view',
264
		'get_items' => array(
265
			'function' => function($start, $items_per_page) use ($context)
266
			{
267
				$subscriptions = array();
268
				$counter = 0;
269
				$start++;
270
271
				foreach ($context['subscriptions'] as $data)
272
				{
273
					if (++$counter < $start)
274
						continue;
275
					elseif ($counter == $start + $items_per_page)
276
						break;
277
278
					$subscriptions[] = $data;
279
				}
280
				return $subscriptions;
281
			},
282
		),
283
		'get_count' => array(
284
			'function' => function() use ($context)
285
			{
286
				return count($context['subscriptions']);
287
			},
288
		),
289
		'no_items_label' => $txt['paid_none_yet'],
290
		'columns' => array(
291
			'name' => array(
292
				'header' => array(
293
					'value' => $txt['paid_name'],
294
					'style' => 'width: 35%;',
295
				),
296
				'data' => array(
297
					'function' => function($rowData) use ($scripturl)
298
					{
299
						return sprintf('<a href="%1$s?action=admin;area=paidsubscribe;sa=viewsub;sid=%2$s">%3$s</a>', $scripturl, $rowData['id'], $rowData['name']);
300
					},
301
				),
302
			),
303
			'cost' => array(
304
				'header' => array(
305
					'value' => $txt['paid_cost'],
306
				),
307
				'data' => array(
308
					'function' => function($rowData) use ($txt)
309
					{
310
						return $rowData['flexible'] ? '<em>' . $txt['flexible'] . '</em>' : $rowData['cost'] . ' / ' . $rowData['length'];
311
					},
312
				),
313
			),
314
			'pending' => array(
315
				'header' => array(
316
					'value' => $txt['paid_pending'],
317
					'style' => 'width: 18%;',
318
					'class' => 'centercol',
319
				),
320
				'data' => array(
321
					'db_htmlsafe' => 'pending',
322
					'class' => 'centercol',
323
				),
324
			),
325
			'finished' => array(
326
				'header' => array(
327
					'value' => $txt['paid_finished'],
328
					'class' => 'centercol',
329
				),
330
				'data' => array(
331
					'db_htmlsafe' => 'finished',
332
					'class' => 'centercol',
333
				),
334
			),
335
			'total' => array(
336
				'header' => array(
337
					'value' => $txt['paid_active'],
338
					'class' => 'centercol',
339
				),
340
				'data' => array(
341
					'db_htmlsafe' => 'total',
342
					'class' => 'centercol',
343
				),
344
			),
345
			'is_active' => array(
346
				'header' => array(
347
					'value' => $txt['paid_is_active'],
348
					'class' => 'centercol',
349
				),
350
				'data' => array(
351 View Code Duplication
					'function' => function($rowData) use ($txt)
352
					{
353
						return '<span style="color: ' . ($rowData['active'] ? 'green' : 'red') . '">' . ($rowData['active'] ? $txt['yes'] : $txt['no']) . '</span>';
354
					},
355
					'class' => 'centercol',
356
				),
357
			),
358
			'modify' => array(
359
				'data' => array(
360 View Code Duplication
					'function' => function($rowData) use ($txt, $scripturl)
361
					{
362
						return '<a href="' . $scripturl . '?action=admin;area=paidsubscribe;sa=modify;sid=' . $rowData['id'] . '">' . $txt['modify'] . '</a>';
363
					},
364
					'class' => 'centercol',
365
				),
366
			),
367
			'delete' => array(
368
				'data' => array(
369 View Code Duplication
					'function' => function($rowData) use ($scripturl, $txt)
370
					{
371
						return '<a href="' . $scripturl . '?action=admin;area=paidsubscribe;sa=modify;delete;sid=' . $rowData['id'] . '">' . $txt['delete'] . '</a>';
372
					},
373
					'class' => 'centercol',
374
				),
375
			),
376
		),
377
		'form' => array(
378
			'href' => $scripturl . '?action=admin;area=paidsubscribe;sa=modify',
379
		),
380
		'additional_rows' => array(
381
			array(
382
				'position' => 'above_table_headers',
383
				'value' => '<input type="submit" name="add" value="' . $txt['paid_add_subscription'] . '" class="button_submit">',
384
			),
385
			array(
386
				'position' => 'below_table_data',
387
				'value' => '<input type="submit" name="add" value="' . $txt['paid_add_subscription'] . '" class="button_submit">',
388
			),
389
		),
390
	);
391
392
	require_once($sourcedir . '/Subs-List.php');
393
	createList($listOptions);
394
395
	$context['sub_template'] = 'show_list';
396
	$context['default_list'] = 'subscription_list';
397
}
398
399
/**
400
 * Adding, editing and deleting subscriptions.
401
 * Accessed from ?action=admin;area=paidsubscribe;sa=modify.
402
 */
403
function ModifySubscription()
404
{
405
	global $context, $txt, $smcFunc;
406
407
	$context['sub_id'] = isset($_REQUEST['sid']) ? (int) $_REQUEST['sid'] : 0;
408
	$context['action_type'] = $context['sub_id'] ? (isset($_REQUEST['delete']) ? 'delete' : 'edit') : 'add';
409
410
	// Setup the template.
411
	$context['sub_template'] = $context['action_type'] == 'delete' ? 'delete_subscription' : 'modify_subscription';
412
	$context['page_title'] = $txt['paid_' . $context['action_type'] . '_subscription'];
413
414
	// Delete it?
415
	if (isset($_POST['delete_confirm']) && isset($_REQUEST['delete']))
416
	{
417
		checkSession();
418
		validateToken('admin-pmsd');
419
420
		// Before we delete the subscription we need to find out if anyone currently has said subscription.
421
		$request = $smcFunc['db_query']('', '
422
			SELECT ls.id_member, ls.old_id_group, mem.id_group, mem.additional_groups
423
			FROM {db_prefix}log_subscribed AS ls
424
				INNER JOIN {db_prefix}members AS mem ON (ls.id_member = mem.id_member)
425
			WHERE id_subscribe = {int:current_subscription}
426
				AND status = {int:is_active}',
427
			array(
428
				'current_subscription' => $context['sub_id'],
429
				'is_active' => 1,
430
			)
431
		);
432
		$members = array();
433
		while ($row = $smcFunc['db_fetch_assoc']($request))
434
		{
435
			$id_member = array_shift($row);
436
			$members[$id_member] = $row;
437
		}
438
		$smcFunc['db_free_result']($request);
439
440
		// If there are any members with this subscription, we have to do some more work before we go any further.
441
		if (!empty($members))
442
		{
443
			$request = $smcFunc['db_query']('', '
444
				SELECT id_group, add_groups
445
				FROM {db_prefix}subscriptions
446
				WHERE id_subscribe = {int:current_subscription}',
447
				array(
448
					'current_subscription' => $context['sub_id'],
449
				)
450
			);
451
			$id_group = 0;
452
			$add_groups = '';
453
			if ($smcFunc['db_num_rows']($request))
454
				list ($id_group, $add_groups) = $smcFunc['db_fetch_row']($request);
455
			$smcFunc['db_free_result']($request);
456
457
			$changes = array();
458
459
			// Is their group changing? This subscription may not have changed primary group.
460
			if (!empty($id_group))
461
			{
462
				foreach ($members as $id_member => $member_data)
463
				{
464
					// If their current primary group isn't what they had before the subscription, and their current group was
465
					// granted by the sub, remove it.
466
					if ($member_data['old_id_group'] != $member_data['id_group'] && $member_data['id_group'] == $id_group)
467
						$changes[$id_member]['id_group'] = $member_data['old_id_group'];
468
				}
469
			}
470
471
			// Did this subscription add secondary groups?
472
			if (!empty($add_groups))
473
			{
474
				$add_groups = explode(',', $add_groups);
475
				foreach ($members as $id_member => $member_data)
476
				{
477
					// First let's get their groups sorted.
478
					$current_groups = explode(',', $member_data['additional_groups']);
479
					$new_groups = implode(',', array_diff($current_groups, $add_groups));
480
					if ($new_groups != $member_data['additional_groups'])
481
						$changes[$id_member]['additional_groups'] = $new_groups;
482
				}
483
			}
484
485
			// We're going through changes...
486
			if (!empty($changes))
487
				foreach ($changes as $id_member => $new_values)
488
					updateMemberData($id_member, $new_values);
489
		}
490
491
		// Delete the subscription
492
		$smcFunc['db_query']('', '
493
			DELETE FROM {db_prefix}subscriptions
494
			WHERE id_subscribe = {int:current_subscription}',
495
			array(
496
				'current_subscription' => $context['sub_id'],
497
			)
498
		);
499
500
		// And delete any subscriptions to it to clear the phantom data too.
501
		$smcFunc['db_query']('', '
502
			DELETE FROM {db_prefix}log_subscribed
503
			WHERE id_subscribe = {int:current_subscription}',
504
			array(
505
				'current_subscription' => $context['sub_id'],
506
			)
507
		);
508
509
		call_integration_hook('integrate_delete_subscription', array($context['sub_id']));
510
511
		redirectexit('action=admin;area=paidsubscribe;view');
512
	}
513
514
	// Saving?
515
	if (isset($_POST['save']))
516
	{
517
		checkSession();
518
519
		// Some cleaning...
520
		$isActive = isset($_POST['active']) ? 1 : 0;
521
		$isRepeatable = isset($_POST['repeatable']) ? 1 : 0;
522
		$allowpartial = isset($_POST['allow_partial']) ? 1 : 0;
523
		$reminder = isset($_POST['reminder']) ? (int) $_POST['reminder'] : 0;
524
		$emailComplete = strlen($_POST['emailcomplete']) > 10 ? trim($_POST['emailcomplete']) : '';
525
526
		// Is this a fixed one?
527
		if ($_POST['duration_type'] == 'fixed')
528
		{
529
			// There are sanity check limits on these things.
530
			$limits = array(
531
				'D' => 90,
532
				'W' => 52,
533
				'M' => 24,
534
				'Y' => 5,
535
			);
536
			if (empty($_POST['span_unit']) || empty($limits[$_POST['span_unit']]) || empty($_POST['span_value']) || $_POST['span_value'] < 1)
537
				fatal_lang_error('paid_invalid_duration', false);
538
539
			if ($_POST['span_value'] > $limits[$_POST['span_unit']])
540
				fatal_lang_error('paid_invalid_duration_' . $_POST['span_unit'], false);
541
542
			// Clean the span.
543
			$span = $_POST['span_value'] . $_POST['span_unit'];
544
545
			// Sort out the cost.
546
			$cost = array('fixed' => sprintf('%01.2f', strtr($_POST['cost'], ',', '.')));
547
548
			// There needs to be something.
549
			if (empty($_POST['span_value']) || empty($_POST['cost']))
550
				fatal_lang_error('paid_no_cost_value');
551
		}
552
		// Flexible is harder but more fun ;)
553
		else
554
		{
555
			$span = 'F';
556
557
			$cost = array(
558
				'day' => sprintf('%01.2f', strtr($_POST['cost_day'], ',', '.')),
559
				'week' => sprintf('%01.2f', strtr($_POST['cost_week'], ',', '.')),
560
				'month' => sprintf('%01.2f', strtr($_POST['cost_month'], ',', '.')),
561
				'year' => sprintf('%01.2f', strtr($_POST['cost_year'], ',', '.')),
562
			);
563
564
			if (empty($_POST['cost_day']) && empty($_POST['cost_week']) && empty($_POST['cost_month']) && empty($_POST['cost_year']))
565
				fatal_lang_error('paid_all_freq_blank');
566
		}
567
		$cost = $smcFunc['json_encode']($cost);
568
569
		// Having now validated everything that might throw an error, let's also now deal with the token.
570
		validateToken('admin-pms');
571
572
		// Yep, time to do additional groups.
573
		$addgroups = array();
574
		if (!empty($_POST['addgroup']))
575
			foreach ($_POST['addgroup'] as $id => $dummy)
576
				$addgroups[] = (int) $id;
577
		$addgroups = implode(',', $addgroups);
578
579
		// Is it new?!
0 ignored issues
show
Unused Code Comprehensibility introduced by
38% 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...
580
		if ($context['action_type'] == 'add')
581
		{
582
			$id_subscribe = $smcFunc['db_insert']('',
583
				'{db_prefix}subscriptions',
584
				array(
585
					'name' => 'string-60', 'description' => 'string-255', 'active' => 'int', 'length' => 'string-4', 'cost' => 'string',
586
					'id_group' => 'int', 'add_groups' => 'string-40', 'repeatable' => 'int', 'allow_partial' => 'int', 'email_complete' => 'string',
587
					'reminder' => 'int',
588
				),
589
				array(
590
					$_POST['name'], $_POST['desc'], $isActive, $span, $cost,
591
					$_POST['prim_group'], $addgroups, $isRepeatable, $allowpartial, $emailComplete,
592
					$reminder,
593
				),
594
				array('id_subscribe'),
595
				1
596
			);
597
		}
598
		// Otherwise must be editing.
599
		else
600
		{
601
			// Don't do groups if there are active members
602
			$request = $smcFunc['db_query']('', '
603
				SELECT COUNT(*)
604
				FROM {db_prefix}log_subscribed
605
				WHERE id_subscribe = {int:current_subscription}
606
					AND status = {int:is_active}',
607
				array(
608
					'current_subscription' => $context['sub_id'],
609
					'is_active' => 1,
610
				)
611
			);
612
			list ($disableGroups) = $smcFunc['db_fetch_row']($request);
613
			$smcFunc['db_free_result']($request);
614
615
			$smcFunc['db_query']('substring', '
616
				UPDATE {db_prefix}subscriptions
617
					SET name = SUBSTRING({string:name}, 1, 60), description = SUBSTRING({string:description}, 1, 255), active = {int:is_active},
618
					length = SUBSTRING({string:length}, 1, 4), cost = {string:cost}' . ($disableGroups ? '' : ', id_group = {int:id_group},
619
					add_groups = {string:additional_groups}') . ', repeatable = {int:repeatable}, allow_partial = {int:allow_partial},
620
					email_complete = {string:email_complete}, reminder = {int:reminder}
621
				WHERE id_subscribe = {int:current_subscription}',
622
				array(
623
					'is_active' => $isActive,
624
					'id_group' => !empty($_POST['prim_group']) ? $_POST['prim_group'] : 0,
625
					'repeatable' => $isRepeatable,
626
					'allow_partial' => $allowpartial,
627
					'reminder' => $reminder,
628
					'current_subscription' => $context['sub_id'],
629
					'name' => $_POST['name'],
630
					'description' => $_POST['desc'],
631
					'length' => $span,
632
					'cost' => $cost,
633
					'additional_groups' => !empty($addgroups) ? $addgroups : '',
634
					'email_complete' => $emailComplete,
635
				)
636
			);
637
		}
638
		call_integration_hook('integrate_save_subscription', array(($context['action_type'] == 'add' ? $id_subscribe : $context['sub_id']), $_POST['name'], $_POST['desc'], $isActive, $span, $cost, $_POST['prim_group'], $addgroups, $isRepeatable, $allowpartial, $emailComplete, $reminder));
0 ignored issues
show
Bug introduced by
The variable $id_subscribe 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...
639
640
		redirectexit('action=admin;area=paidsubscribe;view');
641
	}
642
643
	// Defaults.
644
	if ($context['action_type'] == 'add')
645
	{
646
		$context['sub'] = array(
647
			'name' => '',
648
			'desc' => '',
649
			'cost' => array(
650
				'fixed' => 0,
651
			),
652
			'span' => array(
653
				'value' => '',
654
				'unit' => 'D',
655
			),
656
			'prim_group' => 0,
657
			'add_groups' => array(),
658
			'active' => 1,
659
			'repeatable' => 1,
660
			'allow_partial' => 0,
661
			'duration' => 'fixed',
662
			'email_complete' => '',
663
			'reminder' => 0,
664
		);
665
	}
666
	// Otherwise load up all the details.
667
	else
668
	{
669
		$request = $smcFunc['db_query']('', '
670
			SELECT name, description, cost, length, id_group, add_groups, active, repeatable, allow_partial, email_complete, reminder
671
			FROM {db_prefix}subscriptions
672
			WHERE id_subscribe = {int:current_subscription}
673
			LIMIT 1',
674
			array(
675
				'current_subscription' => $context['sub_id'],
676
			)
677
		);
678
		while ($row = $smcFunc['db_fetch_assoc']($request))
679
		{
680
			// Sort the date.
681
			preg_match('~(\d*)(\w)~', $row['length'], $match);
682
			if (isset($match[2]))
683
			{
684
				$span_value = $match[1];
685
				$span_unit = $match[2];
686
			}
687
			else
688
			{
689
				$span_value = 0;
690
				$span_unit = 'D';
691
			}
692
693
			// Is this a flexible one?
694
			if ($row['length'] == 'F')
695
				$isFlexible = true;
696
			else
697
				$isFlexible = false;
698
699
			$context['sub'] = array(
700
				'name' => $row['name'],
701
				'desc' => $row['description'],
702
				'cost' => $smcFunc['json_decode']($row['cost'], true),
703
				'span' => array(
704
					'value' => $span_value,
705
					'unit' => $span_unit,
706
				),
707
				'prim_group' => $row['id_group'],
708
				'add_groups' => explode(',', $row['add_groups']),
709
				'active' => $row['active'],
710
				'repeatable' => $row['repeatable'],
711
				'allow_partial' => $row['allow_partial'],
712
				'duration' => $isFlexible ? 'flexible' : 'fixed',
713
				'email_complete' => $smcFunc['htmlspecialchars']($row['email_complete']),
714
				'reminder' => $row['reminder'],
715
			);
716
		}
717
		$smcFunc['db_free_result']($request);
718
719
		// Does this have members who are active?
720
		$request = $smcFunc['db_query']('', '
721
			SELECT COUNT(*)
722
			FROM {db_prefix}log_subscribed
723
			WHERE id_subscribe = {int:current_subscription}
724
				AND status = {int:is_active}',
725
			array(
726
				'current_subscription' => $context['sub_id'],
727
				'is_active' => 1,
728
			)
729
		);
730
		list ($context['disable_groups']) = $smcFunc['db_fetch_row']($request);
731
		$smcFunc['db_free_result']($request);
732
	}
733
734
	// Load up all the groups.
735
	$request = $smcFunc['db_query']('', '
736
		SELECT id_group, group_name
737
		FROM {db_prefix}membergroups
738
		WHERE id_group != {int:moderator_group}
739
			AND min_posts = {int:min_posts}',
740
		array(
741
			'moderator_group' => 3,
742
			'min_posts' => -1,
743
		)
744
	);
745
	$context['groups'] = array();
746
	while ($row = $smcFunc['db_fetch_assoc']($request))
747
		$context['groups'][$row['id_group']] = $row['group_name'];
748
	$smcFunc['db_free_result']($request);
749
750
	// This always happens.
751
	createToken($context['action_type'] == 'delete' ? 'admin-pmsd' : 'admin-pms');
752
}
753
754
/**
755
 * View all the users subscribed to a particular subscription.
756
 * Requires the admin_forum permission.
757
 * Accessed from ?action=admin;area=paidsubscribe;sa=viewsub.
758
 *
759
 * Subscription ID is required, in the form of $_GET['sid'].
760
 */
761
function ViewSubscribedUsers()
762
{
763
	global $context, $txt, $scripturl, $smcFunc, $sourcedir, $modSettings;
764
765
	// Setup the template.
766
	$context['page_title'] = $txt['viewing_users_subscribed'];
767
768
	// ID of the subscription.
769
	$context['sub_id'] = (int) $_REQUEST['sid'];
770
771
	// Load the subscription information.
772
	$request = $smcFunc['db_query']('', '
773
		SELECT id_subscribe, name, description, cost, length, id_group, add_groups, active
774
		FROM {db_prefix}subscriptions
775
		WHERE id_subscribe = {int:current_subscription}',
776
		array(
777
			'current_subscription' => $context['sub_id'],
778
		)
779
	);
780
	// Something wrong?
781
	if ($smcFunc['db_num_rows']($request) == 0)
782
		fatal_lang_error('no_access', false);
783
	// Do the subscription context.
784
	$row = $smcFunc['db_fetch_assoc']($request);
785
	$context['subscription'] = array(
786
		'id' => $row['id_subscribe'],
787
		'name' => $row['name'],
788
		'desc' => $row['description'],
789
		'active' => $row['active'],
790
	);
791
	$smcFunc['db_free_result']($request);
792
793
	// Are we searching for people?
794
	$search_string = isset($_POST['ssearch']) && !empty($_POST['sub_search']) ? ' AND COALESCE(mem.real_name, {string:guest}) LIKE {string:search}' : '';
795
	$search_vars = empty($_POST['sub_search']) ? array() : array('search' => '%' . $_POST['sub_search'] . '%', 'guest' => $txt['guest']);
796
797
	$listOptions = array(
798
		'id' => 'subscribed_users_list',
799
		'title' => sprintf($txt['view_users_subscribed'], $row['name']),
800
		'items_per_page' => $modSettings['defaultMaxListItems'],
801
		'base_href' => $scripturl . '?action=admin;area=paidsubscribe;sa=viewsub;sid=' . $context['sub_id'],
802
		'default_sort_col' => 'name',
803
		'get_items' => array(
804
			'function' => 'list_getSubscribedUsers',
805
			'params' => array(
806
				$context['sub_id'],
807
				$search_string,
808
				$search_vars,
809
			),
810
		),
811
		'get_count' => array(
812
			'function' => 'list_getSubscribedUserCount',
813
			'params' => array(
814
				$context['sub_id'],
815
				$search_string,
816
				$search_vars,
817
			),
818
		),
819
		'no_items_label' => $txt['no_subscribers'],
820
		'columns' => array(
821
			'name' => array(
822
				'header' => array(
823
					'value' => $txt['who_member'],
824
					'style' => 'width: 20%;',
825
				),
826
				'data' => array(
827
					'function' => function($rowData) use ($scripturl, $txt)
828
					{
829
						return $rowData['id_member'] == 0 ? $txt['guest'] : '<a href="' . $scripturl . '?action=profile;u=' . $rowData['id_member'] . '">' . $rowData['name'] . '</a>';
830
					},
831
				),
832
				'sort' => array(
833
					'default' => 'name',
834
					'reverse' => 'name DESC',
835
				),
836
			),
837
			'status' => array(
838
				'header' => array(
839
					'value' => $txt['paid_status'],
840
					'style' => 'width: 10%;',
841
				),
842
				'data' => array(
843
					'db_htmlsafe' => 'status_text',
844
				),
845
				'sort' => array(
846
					'default' => 'status',
847
					'reverse' => 'status DESC',
848
				),
849
			),
850
			'payments_pending' => array(
851
				'header' => array(
852
					'value' => $txt['paid_payments_pending'],
853
					'style' => 'width: 15%;',
854
				),
855
				'data' => array(
856
					'db_htmlsafe' => 'pending',
857
				),
858
				'sort' => array(
859
					'default' => 'payments_pending',
860
					'reverse' => 'payments_pending DESC',
861
				),
862
			),
863
			'start_time' => array(
864
				'header' => array(
865
					'value' => $txt['start_date'],
866
					'style' => 'width: 20%;',
867
				),
868
				'data' => array(
869
					'db_htmlsafe' => 'start_date',
870
					'class' => 'smalltext',
871
				),
872
				'sort' => array(
873
					'default' => 'start_time',
874
					'reverse' => 'start_time DESC',
875
				),
876
			),
877
			'end_time' => array(
878
				'header' => array(
879
					'value' => $txt['end_date'],
880
					'style' => 'width: 20%;',
881
				),
882
				'data' => array(
883
					'db_htmlsafe' => 'end_date',
884
					'class' => 'smalltext',
885
				),
886
				'sort' => array(
887
					'default' => 'end_time',
888
					'reverse' => 'end_time DESC',
889
				),
890
			),
891
			'modify' => array(
892
				'header' => array(
893
					'style' => 'width: 10%;',
894
					'class' => 'centercol',
895
				),
896
				'data' => array(
897 View Code Duplication
					'function' => function($rowData) use ($scripturl, $txt)
898
					{
899
						return '<a href="' . $scripturl . '?action=admin;area=paidsubscribe;sa=modifyuser;lid=' . $rowData['id'] . '">' . $txt['modify'] . '</a>';
900
					},
901
					'class' => 'centercol',
902
				),
903
			),
904
			'delete' => array(
905
				'header' => array(
906
					'style' => 'width: 4%;',
907
					'class' => 'centercol',
908
				),
909
				'data' => array(
910
					'function' => function($rowData)
911
					{
912
						return '<input type="checkbox" name="delsub[' . $rowData['id'] . ']" class="input_check">';
913
					},
914
					'class' => 'centercol',
915
				),
916
			),
917
		),
918
		'form' => array(
919
			'href' => $scripturl . '?action=admin;area=paidsubscribe;sa=modifyuser;sid=' . $context['sub_id'],
920
		),
921
		'additional_rows' => array(
922
			array(
923
				'position' => 'below_table_data',
924
				'value' => '
925
					<input type="submit" name="add" value="' . $txt['add_subscriber'] . '" class="button_submit">
926
					<input type="submit" name="finished" value="' . $txt['complete_selected'] . '" data-confirm="' . $txt['complete_are_sure'] . '" class="button_submit you_sure">
927
					<input type="submit" name="delete" value="' . $txt['delete_selected'] . '" data-confirm="' . $txt['delete_are_sure'] . '" class="button_submit you_sure">
928
				',
929
			),
930
			array(
931
				'position' => 'top_of_list',
932
				'value' => '
933
					<div class="flow_auto">
934
						<input type="submit" name="ssearch" value="' . $txt['search_sub'] . '" class="button_submit" style="margin-top: 3px;">
935
						<input type="text" name="sub_search" value="" class="input_text floatright">
936
					</div>
937
				',
938
			),
939
		),
940
	);
941
942
	require_once($sourcedir . '/Subs-List.php');
943
	createList($listOptions);
944
945
	$context['sub_template'] = 'show_list';
946
	$context['default_list'] = 'subscribed_users_list';
947
}
948
949
/**
950
 * Returns how many people are subscribed to a paid subscription.
951
 * @todo refactor away
0 ignored issues
show
Coding Style introduced by
Comment refers to a TODO task

This check looks TODO comments that have been left in the code.

``TODO``s show that something is left unfinished and should be attended to.

Loading history...
952
 *
953
 * @param int $id_sub The ID of the subscription
954
 * @param string $search_string A search string
955
 * @param array $search_vars An array of variables for the search string
956
 * @return int The number of subscribed users matching the given parameters
957
 */
958 View Code Duplication
function list_getSubscribedUserCount($id_sub, $search_string, $search_vars = array())
0 ignored issues
show
Duplication introduced by
This function seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
959
{
960
	global $smcFunc;
961
962
	// Get the total amount of users.
963
	$request = $smcFunc['db_query']('', '
964
		SELECT COUNT(*) AS total_subs
965
		FROM {db_prefix}log_subscribed AS ls
966
			LEFT JOIN {db_prefix}members AS mem ON (mem.id_member = ls.id_member)
967
		WHERE ls.id_subscribe = {int:current_subscription} ' . $search_string . '
968
			AND (ls.end_time != {int:no_end_time} OR ls.payments_pending != {int:no_pending_payments})',
969
		array_merge($search_vars, array(
970
			'current_subscription' => $id_sub,
971
			'no_end_time' => 0,
972
			'no_pending_payments' => 0,
973
		))
974
	);
975
	list ($memberCount) = $smcFunc['db_fetch_row']($request);
976
	$smcFunc['db_free_result']($request);
977
978
	return $memberCount;
979
}
980
981
/**
982
 * Return the subscribed users list, for the given parameters.
983
 * @todo refactor outta here
0 ignored issues
show
Coding Style introduced by
Comment refers to a TODO task

This check looks TODO comments that have been left in the code.

``TODO``s show that something is left unfinished and should be attended to.

Loading history...
984
 *
985
 * @param int $start The item to start with (for pagination purposes)
986
 * @param int $items_per_page How many items to show on each page
987
 * @param string $sort A string indicating how to sort the results
988
 * @param int $id_sub The ID of the subscription
989
 * @param string $search_string A search string
990
 * @param array $search_vars The variables for the search string
991
 * @return array An array of information about the subscribed users matching the given parameters
992
 */
993
function list_getSubscribedUsers($start, $items_per_page, $sort, $id_sub, $search_string, $search_vars = array())
994
{
995
	global $smcFunc, $txt;
996
997
	$request = $smcFunc['db_query']('', '
998
		SELECT ls.id_sublog, COALESCE(mem.id_member, 0) AS id_member, COALESCE(mem.real_name, {string:guest}) AS name, ls.start_time, ls.end_time,
999
			ls.status, ls.payments_pending
1000
		FROM {db_prefix}log_subscribed AS ls
1001
			LEFT JOIN {db_prefix}members AS mem ON (mem.id_member = ls.id_member)
1002
		WHERE ls.id_subscribe = {int:current_subscription} ' . $search_string . '
1003
			AND (ls.end_time != {int:no_end_time} OR ls.payments_pending != {int:no_payments_pending})
1004
		ORDER BY {raw:sort}
1005
		LIMIT {int:start}, {int:max}',
1006
		array_merge($search_vars, array(
1007
			'current_subscription' => $id_sub,
1008
			'no_end_time' => 0,
1009
			'no_payments_pending' => 0,
1010
			'guest' => $txt['guest'],
1011
			'sort' => $sort,
1012
			'start' => $start,
1013
			'max' => $items_per_page,
1014
		))
1015
	);
1016
	$subscribers = array();
1017
	while ($row = $smcFunc['db_fetch_assoc']($request))
1018
		$subscribers[] = array(
1019
			'id' => $row['id_sublog'],
1020
			'id_member' => $row['id_member'],
1021
			'name' => $row['name'],
1022
			'start_date' => timeformat($row['start_time'], false),
1023
			'end_date' => $row['end_time'] == 0 ? 'N/A' : timeformat($row['end_time'], false),
1024
			'pending' => $row['payments_pending'],
1025
			'status' => $row['status'],
1026
			'status_text' => $row['status'] == 0 ? ($row['payments_pending'] == 0 ? $txt['paid_finished'] : $txt['paid_pending']) : $txt['paid_active'],
1027
		);
1028
	$smcFunc['db_free_result']($request);
1029
1030
	return $subscribers;
1031
}
1032
1033
/**
1034
 * Edit or add a user subscription.
1035
 * Accessed from ?action=admin;area=paidsubscribe;sa=modifyuser.
1036
 */
1037
function ModifyUserSubscription()
1038
{
1039
	global $context, $txt, $modSettings, $smcFunc;
1040
1041
	loadSubscriptions();
1042
1043
	$context['log_id'] = isset($_REQUEST['lid']) ? (int) $_REQUEST['lid'] : 0;
1044
	$context['sub_id'] = isset($_REQUEST['sid']) ? (int) $_REQUEST['sid'] : 0;
1045
	$context['action_type'] = $context['log_id'] ? 'edit' : 'add';
1046
1047
	// Setup the template.
1048
	$context['sub_template'] = 'modify_user_subscription';
1049
	$context['page_title'] = $txt[$context['action_type'] . '_subscriber'];
1050
1051
	// If we haven't been passed the subscription ID get it.
1052
	if ($context['log_id'] && !$context['sub_id'])
1053
	{
1054
		$request = $smcFunc['db_query']('', '
1055
			SELECT id_subscribe
1056
			FROM {db_prefix}log_subscribed
1057
			WHERE id_sublog = {int:current_log_item}',
1058
			array(
1059
				'current_log_item' => $context['log_id'],
1060
			)
1061
		);
1062
		if ($smcFunc['db_num_rows']($request) == 0)
1063
			fatal_lang_error('no_access', false);
1064
		list ($context['sub_id']) = $smcFunc['db_fetch_row']($request);
1065
		$smcFunc['db_free_result']($request);
1066
	}
1067
1068
	if (!isset($context['subscriptions'][$context['sub_id']]))
1069
		fatal_lang_error('no_access', false);
1070
	$context['current_subscription'] = $context['subscriptions'][$context['sub_id']];
1071
1072
	// Searching?
1073
	if (isset($_POST['ssearch']))
1074
	{
1075
		return ViewSubscribedUsers();
1076
	}
1077
	// Saving?
1078
	elseif (isset($_REQUEST['save_sub']))
1079
	{
1080
		checkSession();
1081
1082
		// Work out the dates...
1083
		$starttime = mktime($_POST['hour'], $_POST['minute'], 0, $_POST['month'], $_POST['day'], $_POST['year']);
1084
		$endtime = mktime($_POST['hourend'], $_POST['minuteend'], 0, $_POST['monthend'], $_POST['dayend'], $_POST['yearend']);
1085
1086
		// Status.
1087
		$status = $_POST['status'];
1088
1089
		// New one?
1090
		if (empty($context['log_id']))
1091
		{
1092
			// Find the user...
1093
			$request = $smcFunc['db_query']('', '
1094
				SELECT id_member, id_group
1095
				FROM {db_prefix}members
1096
				WHERE real_name = {string:name}
1097
				LIMIT 1',
1098
				array(
1099
					'name' => $_POST['name'],
1100
				)
1101
			);
1102
			if ($smcFunc['db_num_rows']($request) == 0)
1103
				fatal_lang_error('error_member_not_found');
1104
1105
			list ($id_member, $id_group) = $smcFunc['db_fetch_row']($request);
1106
			$smcFunc['db_free_result']($request);
1107
1108
			// Ensure the member doesn't already have a subscription!
1109
			$request = $smcFunc['db_query']('', '
1110
				SELECT id_subscribe
1111
				FROM {db_prefix}log_subscribed
1112
				WHERE id_subscribe = {int:current_subscription}
1113
					AND id_member = {int:current_member}',
1114
				array(
1115
					'current_subscription' => $context['sub_id'],
1116
					'current_member' => $id_member,
1117
				)
1118
			);
1119
			if ($smcFunc['db_num_rows']($request) != 0)
1120
				fatal_lang_error('member_already_subscribed');
1121
			$smcFunc['db_free_result']($request);
1122
1123
			// Actually put the subscription in place.
1124
			if ($status == 1)
1125
				addSubscription($context['sub_id'], $id_member, 0, $starttime, $endtime);
1126
			else
1127
			{
1128
				$smcFunc['db_insert']('',
1129
					'{db_prefix}log_subscribed',
1130
					array(
1131
						'id_subscribe' => 'int', 'id_member' => 'int', 'old_id_group' => 'int', 'start_time' => 'int',
1132
						'end_time' => 'int', 'status' => 'int',
1133
					),
1134
					array(
1135
						$context['sub_id'], $id_member, $id_group, $starttime,
1136
						$endtime, $status,
1137
					),
1138
					array('id_sublog')
1139
				);
1140
			}
1141
		}
1142
		// Updating.
1143
		else
1144
		{
1145
			$request = $smcFunc['db_query']('', '
1146
				SELECT id_member, status
1147
				FROM {db_prefix}log_subscribed
1148
				WHERE id_sublog = {int:current_log_item}',
1149
				array(
1150
					'current_log_item' => $context['log_id'],
1151
				)
1152
			);
1153
			if ($smcFunc['db_num_rows']($request) == 0)
1154
				fatal_lang_error('no_access', false);
1155
1156
			list ($id_member, $old_status) = $smcFunc['db_fetch_row']($request);
1157
			$smcFunc['db_free_result']($request);
1158
1159
			// Pick the right permission stuff depending on what the status is changing from/to.
1160
			if ($old_status == 1 && $status != 1)
1161
				removeSubscription($context['sub_id'], $id_member);
1162
			elseif ($status == 1 && $old_status != 1)
1163
			{
1164
				addSubscription($context['sub_id'], $id_member, 0, $starttime, $endtime);
1165
			}
1166
			else
1167
			{
1168
				$smcFunc['db_query']('', '
1169
					UPDATE {db_prefix}log_subscribed
1170
					SET start_time = {int:start_time}, end_time = {int:end_time}, status = {int:status}
1171
					WHERE id_sublog = {int:current_log_item}',
1172
					array(
1173
						'start_time' => $starttime,
1174
						'end_time' => $endtime,
1175
						'status' => $status,
1176
						'current_log_item' => $context['log_id'],
1177
					)
1178
				);
1179
			}
1180
		}
1181
1182
		// Done - redirect...
1183
		redirectexit('action=admin;area=paidsubscribe;sa=viewsub;sid=' . $context['sub_id']);
1184
	}
1185
	// Deleting?
1186
	elseif (isset($_REQUEST['delete']) || isset($_REQUEST['finished']))
1187
	{
1188
		checkSession();
1189
1190
		// Do the actual deletes!
1191 View Code Duplication
		if (!empty($_REQUEST['delsub']))
1192
		{
1193
			$toDelete = array();
1194
			foreach ($_REQUEST['delsub'] as $id => $dummy)
1195
				$toDelete[] = (int) $id;
1196
1197
			$request = $smcFunc['db_query']('', '
1198
				SELECT id_subscribe, id_member
1199
				FROM {db_prefix}log_subscribed
1200
				WHERE id_sublog IN ({array_int:subscription_list})',
1201
				array(
1202
					'subscription_list' => $toDelete,
1203
				)
1204
			);
1205
			while ($row = $smcFunc['db_fetch_assoc']($request))
1206
				removeSubscription($row['id_subscribe'], $row['id_member'], isset($_REQUEST['delete']));
1207
			$smcFunc['db_free_result']($request);
1208
		}
1209
		redirectexit('action=admin;area=paidsubscribe;sa=viewsub;sid=' . $context['sub_id']);
1210
	}
1211
1212
	// Default attributes.
1213
	if ($context['action_type'] == 'add')
1214
	{
1215
		$context['sub'] = array(
1216
			'id' => 0,
1217
			'start' => array(
1218
				'year' => (int) strftime('%Y', time()),
1219
				'month' => (int) strftime('%m', time()),
1220
				'day' => (int) strftime('%d', time()),
1221
				'hour' => (int) strftime('%H', time()),
1222
				'min' => (int) strftime('%M', time()) < 10 ? '0' . (int) strftime('%M', time()) : (int) strftime('%M', time()),
1223
				'last_day' => 0,
1224
			),
1225
			'end' => array(
1226
				'year' => (int) strftime('%Y', time()),
1227
				'month' => (int) strftime('%m', time()),
1228
				'day' => (int) strftime('%d', time()),
1229
				'hour' => (int) strftime('%H', time()),
1230
				'min' => (int) strftime('%M', time()) < 10 ? '0' . (int) strftime('%M', time()) : (int) strftime('%M', time()),
1231
				'last_day' => 0,
1232
			),
1233
			'status' => 1,
1234
		);
1235
		$context['sub']['start']['last_day'] = (int) strftime('%d', mktime(0, 0, 0, $context['sub']['start']['month'] == 12 ? 1 : $context['sub']['start']['month'] + 1, 0, $context['sub']['start']['month'] == 12 ? $context['sub']['start']['year'] + 1 : $context['sub']['start']['year']));
1236
		$context['sub']['end']['last_day'] = (int) strftime('%d', mktime(0, 0, 0, $context['sub']['end']['month'] == 12 ? 1 : $context['sub']['end']['month'] + 1, 0, $context['sub']['end']['month'] == 12 ? $context['sub']['end']['year'] + 1 : $context['sub']['end']['year']));
1237
1238
		if (isset($_GET['uid']))
1239
		{
1240
			$request = $smcFunc['db_query']('', '
1241
				SELECT real_name
1242
				FROM {db_prefix}members
1243
				WHERE id_member = {int:current_member}',
1244
				array(
1245
					'current_member' => (int) $_GET['uid'],
1246
				)
1247
			);
1248
			list ($context['sub']['username']) = $smcFunc['db_fetch_row']($request);
1249
			$smcFunc['db_free_result']($request);
1250
		}
1251
		else
1252
			$context['sub']['username'] = '';
1253
	}
1254
	// Otherwise load the existing info.
1255
	else
1256
	{
1257
		$request = $smcFunc['db_query']('', '
1258
			SELECT ls.id_sublog, ls.id_subscribe, ls.id_member, start_time, end_time, status, payments_pending, pending_details,
1259
				COALESCE(mem.real_name, {string:blank_string}) AS username
1260
			FROM {db_prefix}log_subscribed AS ls
1261
				LEFT JOIN {db_prefix}members AS mem ON (mem.id_member = ls.id_member)
1262
			WHERE ls.id_sublog = {int:current_subscription_item}
1263
			LIMIT 1',
1264
			array(
1265
				'current_subscription_item' => $context['log_id'],
1266
				'blank_string' => '',
1267
			)
1268
		);
1269
		if ($smcFunc['db_num_rows']($request) == 0)
1270
			fatal_lang_error('no_access', false);
1271
		$row = $smcFunc['db_fetch_assoc']($request);
1272
		$smcFunc['db_free_result']($request);
1273
1274
		// Any pending payments?
1275
		$context['pending_payments'] = array();
1276
		if (!empty($row['pending_details']))
1277
		{
1278
			$pending_details = $smcFunc['json_decode']($row['pending_details'], true);
1279
			foreach ($pending_details as $id => $pending)
1280
			{
1281
				// Only this type need be displayed.
1282
				if ($pending[3] == 'payback')
1283
				{
1284
					// Work out what the options were.
1285
					$costs = $smcFunc['json_decode']($context['current_subscription']['real_cost'], true);
1286
1287
					if ($context['current_subscription']['real_length'] == 'F')
1288
					{
1289
						foreach ($costs as $duration => $cost)
1290
						{
1291
							if ($cost != 0 && $cost == $pending[1] && $duration == $pending[2])
1292
								$context['pending_payments'][$id] = array(
1293
									'desc' => sprintf($modSettings['paid_currency_symbol'], $cost . '/' . $txt[$duration]),
1294
								);
1295
						}
1296
					}
1297
					elseif ($costs['fixed'] == $pending[1])
1298
					{
1299
						$context['pending_payments'][$id] = array(
1300
							'desc' => sprintf($modSettings['paid_currency_symbol'], $costs['fixed']),
1301
						);
1302
					}
1303
				}
1304
			}
1305
1306
			// Check if we are adding/removing any.
1307
			if (isset($_GET['pending']))
1308
			{
1309
				foreach ($pending_details as $id => $pending)
1310
				{
1311
					// Found the one to action?
1312
					if ($_GET['pending'] == $id && $pending[3] == 'payback' && isset($context['pending_payments'][$id]))
1313
					{
1314
						// Flexible?
1315
						if (isset($_GET['accept']))
1316
							addSubscription($context['current_subscription']['id'], $row['id_member'], $context['current_subscription']['real_length'] == 'F' ? strtoupper(substr($pending[2], 0, 1)) : 0);
1317
						unset($pending_details[$id]);
1318
1319
						$new_details = $smcFunc['json_encode']($pending_details);
1320
1321
						// Update the entry.
1322
						$smcFunc['db_query']('', '
1323
							UPDATE {db_prefix}log_subscribed
1324
							SET payments_pending = payments_pending - 1, pending_details = {string:pending_details}
1325
							WHERE id_sublog = {int:current_subscription_item}',
1326
							array(
1327
								'current_subscription_item' => $context['log_id'],
1328
								'pending_details' => $new_details,
1329
							)
1330
						);
1331
1332
						// Reload
1333
						redirectexit('action=admin;area=paidsubscribe;sa=modifyuser;lid=' . $context['log_id']);
1334
					}
1335
				}
1336
			}
1337
		}
1338
1339
		$context['sub_id'] = $row['id_subscribe'];
1340
		$context['sub'] = array(
1341
			'id' => 0,
1342
			'start' => array(
1343
				'year' => (int) strftime('%Y', $row['start_time']),
1344
				'month' => (int) strftime('%m', $row['start_time']),
1345
				'day' => (int) strftime('%d', $row['start_time']),
1346
				'hour' => (int) strftime('%H', $row['start_time']),
1347
				'min' => (int) strftime('%M', $row['start_time']) < 10 ? '0' . (int) strftime('%M', $row['start_time']) : (int) strftime('%M', $row['start_time']),
1348
				'last_day' => 0,
1349
			),
1350
			'end' => array(
1351
				'year' => (int) strftime('%Y', $row['end_time']),
1352
				'month' => (int) strftime('%m', $row['end_time']),
1353
				'day' => (int) strftime('%d', $row['end_time']),
1354
				'hour' => (int) strftime('%H', $row['end_time']),
1355
				'min' => (int) strftime('%M', $row['end_time']) < 10 ? '0' . (int) strftime('%M', $row['end_time']) : (int) strftime('%M', $row['end_time']),
1356
				'last_day' => 0,
1357
			),
1358
			'status' => $row['status'],
1359
			'username' => $row['username'],
1360
		);
1361
		$context['sub']['start']['last_day'] = (int) strftime('%d', mktime(0, 0, 0, $context['sub']['start']['month'] == 12 ? 1 : $context['sub']['start']['month'] + 1, 0, $context['sub']['start']['month'] == 12 ? $context['sub']['start']['year'] + 1 : $context['sub']['start']['year']));
1362
		$context['sub']['end']['last_day'] = (int) strftime('%d', mktime(0, 0, 0, $context['sub']['end']['month'] == 12 ? 1 : $context['sub']['end']['month'] + 1, 0, $context['sub']['end']['month'] == 12 ? $context['sub']['end']['year'] + 1 : $context['sub']['end']['year']));
1363
	}
1364
1365
	loadJavaScriptFile('suggest.js', array('defer' => false), 'smf_suggest');
1366
}
1367
1368
/**
1369
 * Reapplies all subscription rules for each of the users.
1370
 *
1371
 * @param array $users An array of user IDs
1372
 */
1373
function reapplySubscriptions($users)
1374
{
1375
	global $smcFunc;
1376
1377
	// Make it an array.
1378
	if (!is_array($users))
1379
		$users = array($users);
1380
1381
	// Get all the members current groups.
1382
	$groups = array();
1383
	$request = $smcFunc['db_query']('', '
1384
		SELECT id_member, id_group, additional_groups
1385
		FROM {db_prefix}members
1386
		WHERE id_member IN ({array_int:user_list})',
1387
		array(
1388
			'user_list' => $users,
1389
		)
1390
	);
1391
	while ($row = $smcFunc['db_fetch_assoc']($request))
1392
	{
1393
		$groups[$row['id_member']] = array(
1394
			'primary' => $row['id_group'],
1395
			'additional' => explode(',', $row['additional_groups']),
1396
		);
1397
	}
1398
	$smcFunc['db_free_result']($request);
1399
1400
	$request = $smcFunc['db_query']('', '
1401
		SELECT ls.id_member, ls.old_id_group, s.id_group, s.add_groups
1402
		FROM {db_prefix}log_subscribed AS ls
1403
			INNER JOIN {db_prefix}subscriptions AS s ON (s.id_subscribe = ls.id_subscribe)
1404
		WHERE ls.id_member IN ({array_int:user_list})
1405
			AND ls.end_time > {int:current_time}',
1406
		array(
1407
			'user_list' => $users,
1408
			'current_time' => time(),
1409
		)
1410
	);
1411
	while ($row = $smcFunc['db_fetch_assoc']($request))
1412
	{
1413
		// Specific primary group?
1414
		if ($row['id_group'] != 0)
1415
		{
1416
			// If this is changing - add the old one to the additional groups so it's not lost.
1417
			if ($row['id_group'] != $groups[$row['id_member']]['primary'])
1418
				$groups[$row['id_member']]['additional'][] = $groups[$row['id_member']]['primary'];
1419
			$groups[$row['id_member']]['primary'] = $row['id_group'];
1420
		}
1421
1422
		// Additional groups.
1423
		if (!empty($row['add_groups']))
1424
			$groups[$row['id_member']]['additional'] = array_merge($groups[$row['id_member']]['additional'], explode(',', $row['add_groups']));
1425
	}
1426
	$smcFunc['db_free_result']($request);
1427
1428
	// Update all the members.
1429
	foreach ($groups as $id => $group)
1430
	{
1431
		$group['additional'] = array_unique($group['additional']);
1432
		foreach ($group['additional'] as $key => $value)
1433
			if (empty($value))
1434
				unset($group['additional'][$key]);
1435
		$addgroups = implode(',', $group['additional']);
1436
1437
		$smcFunc['db_query']('', '
1438
			UPDATE {db_prefix}members
1439
			SET id_group = {int:primary_group}, additional_groups = {string:additional_groups}
1440
			WHERE id_member = {int:current_member}
1441
			LIMIT 1',
1442
			array(
1443
				'primary_group' => $group['primary'],
1444
				'current_member' => $id,
1445
				'additional_groups' => $addgroups,
1446
			)
1447
		);
1448
	}
1449
}
1450
1451
/**
1452
 * Add or extend a subscription of a user.
1453
 *
1454
 * @param int $id_subscribe The subscription ID
1455
 * @param int $id_member The ID of the member
1456
 * @param int|string $renewal 0 if we're forcing start/end time, otherwise a string indicating how long to renew the subscription for ('D', 'W', 'M' or 'Y')
0 ignored issues
show
Documentation introduced by
Consider making the type for parameter $renewal a bit more specific; maybe use integer.
Loading history...
1457
 * @param int $forceStartTime If set, forces the subscription to start at the specified time
1458
 * @param int $forceEndTime If set, forces the subscription to end at the specified time
1459
 */
1460
function addSubscription($id_subscribe, $id_member, $renewal = 0, $forceStartTime = 0, $forceEndTime = 0)
1461
{
1462
	global $context, $smcFunc;
1463
1464
	// Take the easy way out...
1465
	loadSubscriptions();
1466
1467
	// Exists, yes?
1468
	if (!isset($context['subscriptions'][$id_subscribe]))
1469
		return;
1470
1471
	$curSub = $context['subscriptions'][$id_subscribe];
1472
1473
	// Grab the duration.
1474
	$duration = $curSub['num_length'];
1475
1476
	// If this is a renewal change the duration to be correct.
1477
	if (!empty($renewal))
1478
	{
1479
		switch ($renewal)
1480
		{
1481
			case 'D':
1482
				$duration = 86400;
1483
				break;
1484
			case 'W':
1485
				$duration = 604800;
1486
				break;
1487
			case 'M':
1488
				$duration = 2629743;
1489
				break;
1490
			case 'Y':
1491
				$duration = 31556926;
1492
				break;
1493
			default:
1494
				break;
1495
		}
1496
	}
1497
1498
	// Firstly, see whether it exists, and is active. If so then this is meerly an extension.
1499
	$request = $smcFunc['db_query']('', '
1500
		SELECT id_sublog, end_time, start_time
1501
		FROM {db_prefix}log_subscribed
1502
		WHERE id_subscribe = {int:current_subscription}
1503
			AND id_member = {int:current_member}
1504
			AND status = {int:is_active}',
1505
		array(
1506
			'current_subscription' => $id_subscribe,
1507
			'current_member' => $id_member,
1508
			'is_active' => 1,
1509
		)
1510
	);
1511
1512
	if ($smcFunc['db_num_rows']($request) != 0)
1513
	{
1514
		list ($id_sublog, $endtime, $starttime) = $smcFunc['db_fetch_row']($request);
1515
1516
		// If this has already expired but is active, extension means the period from now.
1517
		if ($endtime < time())
1518
			$endtime = time();
1519
		if ($starttime == 0)
1520
			$starttime = time();
1521
1522
		// Work out the new expiry date.
1523
		$endtime += $duration;
1524
1525
		if ($forceEndTime != 0)
1526
			$endtime = $forceEndTime;
1527
1528
		// As everything else should be good, just update!
1529
		$smcFunc['db_query']('', '
1530
			UPDATE {db_prefix}log_subscribed
1531
			SET end_time = {int:end_time}, start_time = {int:start_time}, reminder_sent = {int:no_reminder_sent}
1532
			WHERE id_sublog = {int:current_subscription_item}',
1533
			array(
1534
				'end_time' => $endtime,
1535
				'start_time' => $starttime,
1536
				'current_subscription_item' => $id_sublog,
1537
				'no_reminder_sent' => 0,
1538
			)
1539
		);
1540
1541
		return;
1542
	}
1543
	$smcFunc['db_free_result']($request);
1544
1545
	// If we're here, that means we don't have an active subscription - that means we need to do some work!
1546
	$request = $smcFunc['db_query']('', '
1547
		SELECT m.id_group, m.additional_groups
1548
		FROM {db_prefix}members AS m
1549
		WHERE m.id_member = {int:current_member}',
1550
		array(
1551
			'current_member' => $id_member,
1552
		)
1553
	);
1554
1555
	// Just in case the member doesn't exist.
1556
	if ($smcFunc['db_num_rows']($request) == 0)
1557
		return;
1558
1559
	list ($old_id_group, $additional_groups) = $smcFunc['db_fetch_row']($request);
1560
	$smcFunc['db_free_result']($request);
1561
1562
	// Prepare additional groups.
1563
	$newAddGroups = explode(',', $curSub['add_groups']);
1564
	$curAddGroups = explode(',', $additional_groups);
1565
1566
	$newAddGroups = array_merge($newAddGroups, $curAddGroups);
1567
1568
	// Simple, simple, simple - hopefully... id_group first.
1569
	if ($curSub['prim_group'] != 0)
1570
	{
1571
		$id_group = $curSub['prim_group'];
1572
1573
		// Ensure their old privileges are maintained.
1574
		if ($old_id_group != 0)
1575
			$newAddGroups[] = $old_id_group;
1576
	}
1577
	else
1578
		$id_group = $old_id_group;
1579
1580
	// Yep, make sure it's unique, and no empties.
1581
	foreach ($newAddGroups as $k => $v)
1582
		if (empty($v))
1583
			unset($newAddGroups[$k]);
1584
	$newAddGroups = array_unique($newAddGroups);
1585
	$newAddGroups = implode(',', $newAddGroups);
1586
1587
	// Store the new settings.
1588
	$smcFunc['db_query']('', '
1589
		UPDATE {db_prefix}members
1590
		SET id_group = {int:primary_group}, additional_groups = {string:additional_groups}
1591
		WHERE id_member = {int:current_member}',
1592
		array(
1593
			'primary_group' => $id_group,
1594
			'current_member' => $id_member,
1595
			'additional_groups' => $newAddGroups,
1596
		)
1597
	);
1598
1599
	// Now log the subscription - maybe we have a dorment subscription we can restore?
1600
	$request = $smcFunc['db_query']('', '
1601
		SELECT id_sublog, end_time, start_time
1602
		FROM {db_prefix}log_subscribed
1603
		WHERE id_subscribe = {int:current_subscription}
1604
			AND id_member = {int:current_member}',
1605
		array(
1606
			'current_subscription' => $id_subscribe,
1607
			'current_member' => $id_member,
1608
		)
1609
	);
1610
1611
	/**
1612
	 * @todo Don't really need to do this twice...
0 ignored issues
show
Coding Style introduced by
Comment refers to a TODO task

This check looks TODO comments that have been left in the code.

``TODO``s show that something is left unfinished and should be attended to.

Loading history...
1613
	 */
1614
	if ($smcFunc['db_num_rows']($request) != 0)
1615
	{
1616
		list ($id_sublog, $endtime, $starttime) = $smcFunc['db_fetch_row']($request);
1617
1618
		// If this has already expired but is active, extension means the period from now.
1619
		if ($endtime < time())
1620
			$endtime = time();
1621
		if ($starttime == 0)
1622
			$starttime = time();
1623
1624
		// Work out the new expiry date.
1625
		$endtime += $duration;
1626
1627
		if ($forceEndTime != 0)
1628
			$endtime = $forceEndTime;
1629
1630
		// As everything else should be good, just update!
1631
		$smcFunc['db_query']('', '
1632
			UPDATE {db_prefix}log_subscribed
1633
			SET start_time = {int:start_time}, end_time = {int:end_time}, old_id_group = {int:old_id_group}, status = {int:is_active}, reminder_sent = {int:no_reminder_sent}
1634
			WHERE id_sublog = {int:current_subscription_item}',
1635
			array(
1636
				'start_time' => $starttime,
1637
				'end_time' => $endtime,
1638
				'old_id_group' => $old_id_group,
1639
				'is_active' => 1,
1640
				'no_reminder_sent' => 0,
1641
				'current_subscription_item' => $id_sublog,
1642
			)
1643
		);
1644
1645
		return;
1646
	}
1647
	$smcFunc['db_free_result']($request);
1648
1649
	// Otherwise a very simple insert.
1650
	$endtime = time() + $duration;
1651
	if ($forceEndTime != 0)
1652
		$endtime = $forceEndTime;
1653
1654
	if ($forceStartTime == 0)
1655
		$starttime = time();
1656
	else
1657
		$starttime = $forceStartTime;
1658
1659
	$smcFunc['db_insert']('',
1660
		'{db_prefix}log_subscribed',
1661
		array(
1662
			'id_subscribe' => 'int', 'id_member' => 'int', 'old_id_group' => 'int', 'start_time' => 'int',
1663
			'end_time' => 'int', 'status' => 'int', 'pending_details' => 'string',
1664
		),
1665
		array(
1666
			$id_subscribe, $id_member, $old_id_group, $starttime,
1667
			$endtime, 1, '',
1668
		),
1669
		array('id_sublog')
1670
	);
1671
}
1672
1673
/**
1674
 * Removes a subscription from a user, as in removes the groups.
1675
 *
1676
 * @param int $id_subscribe The ID of the subscription
1677
 * @param int $id_member The ID of the member
1678
 * @param bool $delete Whether to delete the subscription or just disable it
1679
 */
1680
function removeSubscription($id_subscribe, $id_member, $delete = false)
1681
{
1682
	global $context, $smcFunc;
1683
1684
	loadSubscriptions();
1685
1686
	// Load the user core bits.
1687
	$request = $smcFunc['db_query']('', '
1688
		SELECT m.id_group, m.additional_groups
1689
		FROM {db_prefix}members AS m
1690
		WHERE m.id_member = {int:current_member}',
1691
		array(
1692
			'current_member' => $id_member,
1693
		)
1694
	);
1695
1696
	// Just in case of errors.
1697
	if ($smcFunc['db_num_rows']($request) == 0)
1698
	{
1699
		$smcFunc['db_query']('', '
1700
			DELETE FROM {db_prefix}log_subscribed
1701
			WHERE id_member = {int:current_member}',
1702
			array(
1703
				'current_member' => $id_member,
1704
			)
1705
		);
1706
		return;
1707
	}
1708
	list ($id_group, $additional_groups) = $smcFunc['db_fetch_row']($request);
1709
	$smcFunc['db_free_result']($request);
1710
1711
	// Get all of the subscriptions for this user that are active - it will be necessary!
1712
	$request = $smcFunc['db_query']('', '
1713
		SELECT id_subscribe, old_id_group
1714
		FROM {db_prefix}log_subscribed
1715
		WHERE id_member = {int:current_member}
1716
			AND status = {int:is_active}',
1717
		array(
1718
			'current_member' => $id_member,
1719
			'is_active' => 1,
1720
		)
1721
	);
1722
1723
	// These variables will be handy, honest ;)
1724
	$removals = array();
1725
	$allowed = array();
1726
	$old_id_group = 0;
1727
	$new_id_group = -1;
1728
	while ($row = $smcFunc['db_fetch_assoc']($request))
1729
	{
1730
		if (!isset($context['subscriptions'][$row['id_subscribe']]))
1731
			continue;
1732
1733
		// The one we're removing?
1734
		if ($row['id_subscribe'] == $id_subscribe)
1735
		{
1736
			$removals = explode(',', $context['subscriptions'][$row['id_subscribe']]['add_groups']);
1737
			if ($context['subscriptions'][$row['id_subscribe']]['prim_group'] != 0)
1738
				$removals[] = $context['subscriptions'][$row['id_subscribe']]['prim_group'];
1739
			$old_id_group = $row['old_id_group'];
1740
		}
1741
		// Otherwise things we allow.
1742
		else
1743
		{
1744
			$allowed = array_merge($allowed, explode(',', $context['subscriptions'][$row['id_subscribe']]['add_groups']));
1745
			if ($context['subscriptions'][$row['id_subscribe']]['prim_group'] != 0)
1746
			{
1747
				$allowed[] = $context['subscriptions'][$row['id_subscribe']]['prim_group'];
1748
				$new_id_group = $context['subscriptions'][$row['id_subscribe']]['prim_group'];
1749
			}
1750
		}
1751
	}
1752
	$smcFunc['db_free_result']($request);
1753
1754
	// Now, for everything we are removing check they definitely are not allowed it.
1755
	$existingGroups = explode(',', $additional_groups);
1756
	foreach ($existingGroups as $key => $group)
1757
		if (empty($group) || (in_array($group, $removals) && !in_array($group, $allowed)))
1758
			unset($existingGroups[$key]);
1759
1760
	// Finally, do something with the current primary group.
1761
	if (in_array($id_group, $removals))
1762
	{
1763
		// If this primary group is actually allowed keep it.
1764
		if (in_array($id_group, $allowed))
1765
			$existingGroups[] = $id_group;
1766
1767
		// Either way, change the id_group back.
1768
		if ($new_id_group < 1)
1769
		{
1770
			// If we revert to the old id-group we need to ensure it wasn't from a subscription.
1771
			foreach ($context['subscriptions'] as $id => $group)
1772
				// It was? Make them a regular member then!
1773
				if ($group['prim_group'] == $old_id_group)
1774
					$old_id_group = 0;
1775
1776
			$id_group = $old_id_group;
1777
		}
1778
		else
1779
			$id_group = $new_id_group;
1780
	}
1781
1782
	// Crazy stuff, we seem to have our groups fixed, just make them unique
1783
	$existingGroups = array_unique($existingGroups);
1784
	$existingGroups = implode(',', $existingGroups);
1785
1786
	// Update the member
1787
	$smcFunc['db_query']('', '
1788
		UPDATE {db_prefix}members
1789
		SET id_group = {int:primary_group}, additional_groups = {string:existing_groups}
1790
		WHERE id_member = {int:current_member}',
1791
		array(
1792
			'primary_group' => $id_group,
1793
			'current_member' => $id_member,
1794
			'existing_groups' => $existingGroups,
1795
		)
1796
	);
1797
1798
	// Disable the subscription.
1799
	if (!$delete)
1800
		$smcFunc['db_query']('', '
1801
			UPDATE {db_prefix}log_subscribed
1802
			SET status = {int:not_active}
1803
			WHERE id_member = {int:current_member}
1804
				AND id_subscribe = {int:current_subscription}',
1805
			array(
1806
				'not_active' => 0,
1807
				'current_member' => $id_member,
1808
				'current_subscription' => $id_subscribe,
1809
			)
1810
		);
1811
	// Otherwise delete it!
1812
	else
1813
		$smcFunc['db_query']('', '
1814
			DELETE FROM {db_prefix}log_subscribed
1815
			WHERE id_member = {int:current_member}
1816
				AND id_subscribe = {int:current_subscription}',
1817
			array(
1818
				'current_member' => $id_member,
1819
				'current_subscription' => $id_subscribe,
1820
			)
1821
		);
1822
}
1823
1824
/**
1825
 * This just kind of caches all the subscription data.
1826
 */
1827
function loadSubscriptions()
1828
{
1829
	global $context, $txt, $modSettings, $smcFunc;
1830
1831
	if (!empty($context['subscriptions']))
1832
		return;
1833
1834
	// Make sure this is loaded, just in case.
1835
	loadLanguage('ManagePaid');
1836
1837
	$request = $smcFunc['db_query']('', '
1838
		SELECT id_subscribe, name, description, cost, length, id_group, add_groups, active, repeatable
1839
		FROM {db_prefix}subscriptions',
1840
		array(
1841
		)
1842
	);
1843
	$context['subscriptions'] = array();
1844
	while ($row = $smcFunc['db_fetch_assoc']($request))
1845
	{
1846
		// Pick a cost.
1847
		$costs = $smcFunc['json_decode']($row['cost'], true);
1848
1849
		if ($row['length'] != 'F' && !empty($modSettings['paid_currency_symbol']) && !empty($costs['fixed']))
1850
			$cost = sprintf($modSettings['paid_currency_symbol'], $costs['fixed']);
1851
		else
1852
			$cost = '???';
1853
1854
		// Do the span.
1855
		preg_match('~(\d*)(\w)~', $row['length'], $match);
1856
		if (isset($match[2]))
1857
		{
1858
			$num_length = $match[1];
1859
			$length = $match[1] . ' ';
1860
			switch ($match[2])
1861
			{
1862
				case 'D':
1863
					$length .= $txt['paid_mod_span_days'];
1864
					$num_length *= 86400;
1865
					break;
1866
				case 'W':
1867
					$length .= $txt['paid_mod_span_weeks'];
1868
					$num_length *= 604800;
1869
					break;
1870
				case 'M':
1871
					$length .= $txt['paid_mod_span_months'];
1872
					$num_length *= 2629743;
1873
					break;
1874
				case 'Y':
1875
					$length .= $txt['paid_mod_span_years'];
1876
					$num_length *= 31556926;
1877
					break;
1878
			}
1879
		}
1880
		else
1881
			$length = '??';
1882
1883
		$context['subscriptions'][$row['id_subscribe']] = array(
1884
			'id' => $row['id_subscribe'],
1885
			'name' => $row['name'],
1886
			'desc' => $row['description'],
1887
			'cost' => $cost,
1888
			'real_cost' => $row['cost'],
1889
			'length' => $length,
1890
			'num_length' => $num_length,
0 ignored issues
show
Bug introduced by
The variable $num_length 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...
1891
			'real_length' => $row['length'],
1892
			'pending' => 0,
1893
			'finished' => 0,
1894
			'total' => 0,
1895
			'active' => $row['active'],
1896
			'prim_group' => $row['id_group'],
1897
			'add_groups' => $row['add_groups'],
1898
			'flexible' => $row['length'] == 'F' ? true : false,
1899
			'repeatable' => $row['repeatable'],
1900
		);
1901
	}
1902
	$smcFunc['db_free_result']($request);
1903
1904
	// Do the counts.
1905
	$request = $smcFunc['db_query']('', '
1906
		SELECT COUNT(id_sublog) AS member_count, id_subscribe, status
1907
		FROM {db_prefix}log_subscribed
1908
		GROUP BY id_subscribe, status',
1909
		array(
1910
		)
1911
	);
1912
	while ($row = $smcFunc['db_fetch_assoc']($request))
1913
	{
1914
		$ind = $row['status'] == 0 ? 'finished' : 'total';
1915
1916 View Code Duplication
		if (isset($context['subscriptions'][$row['id_subscribe']]))
1917
			$context['subscriptions'][$row['id_subscribe']][$ind] = $row['member_count'];
1918
	}
1919
	$smcFunc['db_free_result']($request);
1920
1921
	// How many payments are we waiting on?
1922
	$request = $smcFunc['db_query']('', '
1923
		SELECT SUM(payments_pending) AS total_pending, id_subscribe
1924
		FROM {db_prefix}log_subscribed
1925
		GROUP BY id_subscribe',
1926
		array(
1927
		)
1928
	);
1929
	while ($row = $smcFunc['db_fetch_assoc']($request))
1930
	{
1931 View Code Duplication
		if (isset($context['subscriptions'][$row['id_subscribe']]))
1932
			$context['subscriptions'][$row['id_subscribe']]['pending'] = $row['total_pending'];
1933
	}
1934
	$smcFunc['db_free_result']($request);
1935
}
1936
1937
/**
1938
 * Load all the payment gateways.
1939
 * Checks the Sources directory for any files fitting the format of a payment gateway,
1940
 * loads each file to check it's valid, includes each file and returns the
1941
 * function name and whether it should work with this version of SMF.
1942
 *
1943
 * @return array An array of information about available payment gateways
1944
 */
1945
function loadPaymentGateways()
1946
{
1947
	global $sourcedir;
1948
1949
	$gateways = array();
1950
	if ($dh = opendir($sourcedir))
0 ignored issues
show
Comprehensibility introduced by
Avoid variables with short names like $dh. Configured minimum length is 3.

Short variable names may make your code harder to understand. Variable names should be self-descriptive. This check looks for variable names who are shorter than a configured minimum.

Loading history...
1951
	{
1952
		while (($file = readdir($dh)) !== false)
1953
		{
1954
			if (is_file($sourcedir . '/' . $file) && preg_match('~^Subscriptions-([A-Za-z\d]+)\.php$~', $file, $matches))
1955
			{
1956
				// Check this is definitely a valid gateway!
1957
				$fp = fopen($sourcedir . '/' . $file, 'rb');
0 ignored issues
show
Comprehensibility introduced by
Avoid variables with short names like $fp. Configured minimum length is 3.

Short variable names may make your code harder to understand. Variable names should be self-descriptive. This check looks for variable names who are shorter than a configured minimum.

Loading history...
1958
				$header = fread($fp, 4096);
1959
				fclose($fp);
1960
1961
				if (strpos($header, '// SMF Payment Gateway: ' . strtolower($matches[1])) !== false)
1962
				{
1963
					require_once($sourcedir . '/' . $file);
1964
1965
					$gateways[] = array(
1966
						'filename' => $file,
1967
						'code' => strtolower($matches[1]),
1968
						// Don't need anything snazzier than this yet.
1969
						'valid_version' => class_exists(strtolower($matches[1]) . '_payment') && class_exists(strtolower($matches[1]) . '_display'),
1970
						'payment_class' => strtolower($matches[1]) . '_payment',
1971
						'display_class' => strtolower($matches[1]) . '_display',
1972
					);
1973
				}
1974
			}
1975
		}
1976
	}
1977
	closedir($dh);
1978
1979
	return $gateways;
1980
}
1981
1982
?>