Completed
Pull Request — release-2.1 (#4924)
by Jeremy
08:56
created

ManageMail.php ➔ TestMailSend()   A

Complexity

Conditions 5
Paths 6

Size

Total Lines 28

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
nc 6
nop 0
dl 0
loc 28
rs 9.1608
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * This file is all about mail, how we love it so. In particular it handles the admin side of
5
 * mail configuration, as well as reviewing the mail queue - if enabled.
6
 * @todo refactor as controller-model.
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...
7
 *
8
 * Simple Machines Forum (SMF)
9
 *
10
 * @package SMF
11
 * @author Simple Machines http://www.simplemachines.org
12
 * @copyright 2018 Simple Machines and individual contributors
13
 * @license http://www.simplemachines.org/about/smf/license.php BSD
14
 *
15
 * @version 2.1 Beta 4
16
 */
17
18
if (!defined('SMF'))
19
	die('No direct access...');
20
21
/**
22
 * Main dispatcher. This function checks permissions and passes control through to the relevant section.
23
 */
24
function ManageMail()
25
{
26
	global $context, $txt, $sourcedir;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
27
28
	// You need to be an admin to edit settings!
29
	isAllowedTo('admin_forum');
30
31
	loadLanguage('Help');
32
	loadLanguage('ManageMail');
33
34
	// We'll need the utility functions from here.
35
	require_once($sourcedir . '/ManageServer.php');
36
37
	$context['page_title'] = $txt['mailqueue_title'];
38
	$context['sub_template'] = 'show_settings';
39
40
	$subActions = array(
41
		'browse' => 'BrowseMailQueue',
42
		'clear' => 'ClearMailQueue',
43
		'settings' => 'ModifyMailSettings',
44
		'test' => 'TestMailSend',
45
	);
46
47
	// By default we want to browse
48
	$_REQUEST['sa'] = isset($_REQUEST['sa']) && isset($subActions[$_REQUEST['sa']]) ? $_REQUEST['sa'] : 'browse';
49
	$context['sub_action'] = $_REQUEST['sa'];
50
51
	// Load up all the tabs...
52
	$context[$context['admin_menu_name']]['tab_data'] = array(
53
		'title' => $txt['mailqueue_title'],
54
		'help' => '',
55
		'description' => $txt['mailqueue_desc'],
56
	);
57
58
	call_integration_hook('integrate_manage_mail', array(&$subActions));
59
60
	// Call the right function for this sub-action.
61
	call_helper($subActions[$_REQUEST['sa']]);
62
}
63
64
/**
65
 * Display the mail queue...
66
 */
67
function BrowseMailQueue()
68
{
69
	global $scripturl, $context, $txt, $smcFunc;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
70
	global $sourcedir, $modSettings;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
71
72
	// First, are we deleting something from the queue?
73
	if (isset($_REQUEST['delete']))
74
	{
75
		checkSession();
76
77
		$smcFunc['db_query']('', '
78
			DELETE FROM {db_prefix}mail_queue
79
			WHERE id_mail IN ({array_int:mail_ids})',
80
			array(
81
				'mail_ids' => $_REQUEST['delete'],
82
			)
83
		);
84
	}
85
86
	// How many items do we have?
87
	$request = $smcFunc['db_query']('', '
88
		SELECT COUNT(*) AS queue_size, MIN(time_sent) AS oldest
89
		FROM {db_prefix}mail_queue',
90
		array(
91
		)
92
	);
93
	list ($mailQueueSize, $mailOldest) = $smcFunc['db_fetch_row']($request);
94
	$smcFunc['db_free_result']($request);
95
96
	$context['oldest_mail'] = empty($mailOldest) ? $txt['mailqueue_oldest_not_available'] : time_since(time() - $mailOldest);
97
	$context['mail_queue_size'] = comma_format($mailQueueSize);
98
99
	$listOptions = array(
100
		'id' => 'mail_queue',
101
		'title' => $txt['mailqueue_browse'],
102
		'items_per_page' => $modSettings['defaultMaxListItems'],
103
		'base_href' => $scripturl . '?action=admin;area=mailqueue',
104
		'default_sort_col' => 'age',
105
		'no_items_label' => $txt['mailqueue_no_items'],
106
		'get_items' => array(
107
			'function' => 'list_getMailQueue',
108
		),
109
		'get_count' => array(
110
			'function' => 'list_getMailQueueSize',
111
		),
112
		'columns' => array(
113
			'subject' => array(
114
				'header' => array(
115
					'value' => $txt['mailqueue_subject'],
116
				),
117
				'data' => array(
118
					'function' => function($rowData) use ($smcFunc)
119
					{
120
						return $smcFunc['strlen']($rowData['subject']) > 50 ? sprintf('%1$s...', $smcFunc['htmlspecialchars']($smcFunc['substr']($rowData['subject'], 0, 47))) : $smcFunc['htmlspecialchars']($rowData['subject']);
121
					},
122
					'class' => 'smalltext',
123
				),
124
				'sort' => array(
125
					'default' => 'subject',
126
					'reverse' => 'subject DESC',
127
				),
128
			),
129
			'recipient' => array(
130
				'header' => array(
131
					'value' => $txt['mailqueue_recipient'],
132
				),
133
				'data' => array(
134
					'sprintf' => array(
135
						'format' => '<a href="mailto:%1$s">%1$s</a>',
136
						'params' => array(
137
							'recipient' => true,
138
						),
139
					),
140
					'class' => 'smalltext',
141
				),
142
				'sort' => array(
143
					'default' => 'recipient',
144
					'reverse' => 'recipient DESC',
145
				),
146
			),
147
			'priority' => array(
148
				'header' => array(
149
					'value' => $txt['mailqueue_priority'],
150
				),
151
				'data' => array(
152
					'function' => function($rowData) use ($txt)
153
					{
154
						// We probably have a text label with your priority.
155
						$txtKey = sprintf('mq_mpriority_%1$s', $rowData['priority']);
156
157
						// But if not, revert to priority 0.
158
						return isset($txt[$txtKey]) ? $txt[$txtKey] : $txt['mq_mpriority_1'];
159
					},
160
					'class' => 'smalltext',
161
				),
162
				'sort' => array(
163
					'default' => 'priority',
164
					'reverse' => 'priority DESC',
165
				),
166
			),
167
			'age' => array(
168
				'header' => array(
169
					'value' => $txt['mailqueue_age'],
170
				),
171
				'data' => array(
172
					'function' => function($rowData)
173
					{
174
						return time_since(time() - $rowData['time_sent']);
175
					},
176
					'class' => 'smalltext',
177
				),
178
				'sort' => array(
179
					'default' => 'time_sent',
180
					'reverse' => 'time_sent DESC',
181
				),
182
			),
183
			'check' => array(
184
				'header' => array(
185
					'value' => '<input type="checkbox" onclick="invertAll(this, this.form);">',
186
				),
187
				'data' => array(
188
					'function' => function($rowData)
189
					{
190
						return '<input type="checkbox" name="delete[]" value="' . $rowData['id_mail'] . '">';
191
					},
192
					'class' => 'smalltext',
193
				),
194
			),
195
		),
196
		'form' => array(
197
			'href' => $scripturl . '?action=admin;area=mailqueue',
198
			'include_start' => true,
199
			'include_sort' => true,
200
		),
201
		'additional_rows' => array(
202
			array(
203
				'position' => 'top_of_list',
204
				'value' => '<input type="submit" name="delete_redirects" value="' . $txt['quickmod_delete_selected'] . '" data-confirm="' . $txt['quickmod_confirm'] . '" class="button you_sure"><a class="button you_sure" href="' . $scripturl . '?action=admin;area=mailqueue;sa=clear;' . $context['session_var'] . '=' . $context['session_id'] . '" data-confirm="' . $txt['mailqueue_clear_list_warning'] . '">' . $txt['mailqueue_clear_list'] . '</a> ',
205
			),
206
			array(
207
				'position' => 'bottom_of_list',
208
				'value' => '<input type="submit" name="delete_redirects" value="' . $txt['quickmod_delete_selected'] . '" data-confirm="' . $txt['quickmod_confirm'] . '" class="button you_sure"><a class="button you_sure" href="' . $scripturl . '?action=admin;area=mailqueue;sa=clear;' . $context['session_var'] . '=' . $context['session_id'] . '" data-confirm="' . $txt['mailqueue_clear_list_warning'] . '">' . $txt['mailqueue_clear_list'] . '</a> ',
209
			),
210
		),
211
	);
212
213
	require_once($sourcedir . '/Subs-List.php');
214
	createList($listOptions);
215
216
	loadTemplate('ManageMail');
217
	$context['sub_template'] = 'browse';
218
}
219
220
/**
221
 * This function grabs the mail queue items from the database, according to the params given.
222
 * Callback for $listOptions['get_items'] in BrowseMailQueue()
223
 *
224
 * @param int $start The item to start with (for pagination purposes)
225
 * @param int $items_per_page How many items to show on each page
226
 * @param string $sort A string indicating how to sort the results
227
 * @return array An array with info about the mail queue items
228
 */
229
function list_getMailQueue($start, $items_per_page, $sort)
230
{
231
	global $smcFunc, $txt;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
232
233
	$request = $smcFunc['db_query']('', '
234
		SELECT
235
			id_mail, time_sent, recipient, priority, private, subject
236
		FROM {db_prefix}mail_queue
237
		ORDER BY {raw:sort}
238
		LIMIT {int:start}, {int:items_per_page}',
239
		array(
240
			'start' => $start,
241
			'sort' => $sort,
242
			'items_per_page' => $items_per_page,
243
		)
244
	);
245
	$mails = array();
246
	while ($row = $smcFunc['db_fetch_assoc']($request))
247
	{
248
		// Private PM/email subjects and similar shouldn't be shown in the mailbox area.
249
		if (!empty($row['private']))
250
			$row['subject'] = $txt['personal_message'];
251
252
		$mails[] = $row;
253
	}
254
	$smcFunc['db_free_result']($request);
255
256
	return $mails;
257
}
258
259
/**
260
 * Returns the total count of items in the mail queue.
261
 * Callback for $listOptions['get_count'] in BrowseMailQueue
262
 * @return int The total number of mail queue items
263
 */
264
function list_getMailQueueSize()
265
{
266
	global $smcFunc;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
267
268
	// How many items do we have?
269
	$request = $smcFunc['db_query']('', '
270
		SELECT COUNT(*) AS queue_size
271
		FROM {db_prefix}mail_queue',
272
		array(
273
		)
274
	);
275
	list ($mailQueueSize) = $smcFunc['db_fetch_row']($request);
276
	$smcFunc['db_free_result']($request);
277
278
	return $mailQueueSize;
279
}
280
281
/**
282
 * Allows to view and modify the mail settings.
283
 *
284
 * @param bool $return_config Whether to return the $config_vars array (used for admin search)
285
 * @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<*,array|string[]|s...g|boolean|double>>|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...
286
 */
287
function ModifyMailSettings($return_config = false)
288
{
289
	global $txt, $scripturl, $context, $modSettings, $txtBirthdayEmails;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
290
291
	loadLanguage('EmailTemplates');
292
293
	$body = $txtBirthdayEmails[(empty($modSettings['birthday_email']) ? 'happy_birthday' : $modSettings['birthday_email']) . '_body'];
294
	$subject = $txtBirthdayEmails[(empty($modSettings['birthday_email']) ? 'happy_birthday' : $modSettings['birthday_email']) . '_subject'];
295
296
	$emails = array();
297
	$processedBirthdayEmails = array();
298
	foreach ($txtBirthdayEmails as $key => $value)
299
	{
300
		$index = substr($key, 0, strrpos($key, '_'));
301
		$element = substr($key, strrpos($key, '_') + 1);
302
		$processedBirthdayEmails[$index][$element] = $value;
303
	}
304
	foreach ($processedBirthdayEmails as $index => $dummy)
305
		$emails[$index] = $index;
306
307
	$config_vars = array(
308
			// Mail queue stuff, this rocks ;)
309
			array('int', 'mail_limit', 'subtext' => $txt['zero_to_disable']),
310
			array('int', 'mail_quantity'),
311
		'',
312
			// SMTP stuff.
313
			array('select', 'mail_type', array($txt['mail_type_default'], 'SMTP', 'SMTP - STARTTLS')),
314
			array('text', 'smtp_host'),
315
			array('text', 'smtp_port'),
316
			array('text', 'smtp_username'),
317
			array('password', 'smtp_password'),
318
		'',
319
			array('select', 'birthday_email', $emails, 'value' => array('subject' => $subject, 'body' => $body), 'javascript' => 'onchange="fetch_birthday_preview()"'),
320
			'birthday_subject' => array('var_message', 'birthday_subject', 'var_message' => $processedBirthdayEmails[empty($modSettings['birthday_email']) ? 'happy_birthday' : $modSettings['birthday_email']]['subject'], 'disabled' => true, 'size' => strlen($subject) + 3),
321
			'birthday_body' => array('var_message', 'birthday_body', 'var_message' => nl2br($body), 'disabled' => true, 'size' => ceil(strlen($body) / 25)),
322
	);
323
324
	call_integration_hook('integrate_modify_mail_settings', array(&$config_vars));
325
326
	if ($return_config)
327
		return $config_vars;
328
329
	// Saving?
330
	if (isset($_GET['save']))
331
	{
332
		// Make the SMTP password a little harder to see in a backup etc.
333
		if (!empty($_POST['smtp_password'][1]))
334
		{
335
			$_POST['smtp_password'][0] = base64_encode($_POST['smtp_password'][0]);
336
			$_POST['smtp_password'][1] = base64_encode($_POST['smtp_password'][1]);
337
		}
338
		checkSession();
339
340
		// We don't want to save the subject and body previews.
341
		unset($config_vars['birthday_subject'], $config_vars['birthday_body']);
342
		call_integration_hook('integrate_save_mail_settings');
343
344
		saveDBSettings($config_vars);
345
		redirectexit('action=admin;area=mailqueue;sa=settings');
346
	}
347
348
	$context['post_url'] = $scripturl . '?action=admin;area=mailqueue;save;sa=settings';
349
	$context['settings_title'] = $txt['mailqueue_settings'];
350
351
	prepareDBSettingContext($config_vars);
352
353
	$context['settings_insert_above'] = '
354
	<script>
355
		var bDay = {';
356
357
	$i = 0;
358
	foreach ($processedBirthdayEmails as $index => $email)
359
	{
360
		$is_last = ++$i == count($processedBirthdayEmails);
361
		$context['settings_insert_above'] .= '
362
			' . $index . ': {
363
				subject: ' . JavaScriptEscape($email['subject']) . ',
364
				body: ' . JavaScriptEscape(nl2br($email['body'])) . '
365
			}' . (!$is_last ? ',' : '');
366
	}
367
	$context['settings_insert_above'] .= '
368
		};
369
		function fetch_birthday_preview()
370
		{
371
			var index = document.getElementById(\'birthday_email\').value;
372
			document.getElementById(\'birthday_subject\').innerHTML = bDay[index].subject;
373
			document.getElementById(\'birthday_body\').innerHTML = bDay[index].body;
374
		}
375
	</script>';
376
}
377
378
/**
379
 * This function clears the mail queue of all emails, and at the end redirects to browse.
380
 */
381
function ClearMailQueue()
382
{
383
	global $sourcedir, $smcFunc;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
384
385
	checkSession('get');
386
387
	// This is certainly needed!
388
	require_once($sourcedir . '/ScheduledTasks.php');
389
390
	// If we don't yet have the total to clear, find it.
391
	if (!isset($_GET['te']))
392
	{
393
		// How many items do we have?
394
		$request = $smcFunc['db_query']('', '
395
			SELECT COUNT(*) AS queue_size
396
			FROM {db_prefix}mail_queue',
397
			array(
398
			)
399
		);
400
		list ($_GET['te']) = $smcFunc['db_fetch_row']($request);
401
		$smcFunc['db_free_result']($request);
402
	}
403
	else
404
		$_GET['te'] = (int) $_GET['te'];
405
406
	$_GET['sent'] = isset($_GET['sent']) ? (int) $_GET['sent'] : 0;
407
408
	// Send 50 at a time, then go for a break...
409
	while (ReduceMailQueue(50, true, true) === true)
410
	{
411
		// Sent another 50.
412
		$_GET['sent'] += 50;
413
		pauseMailQueueClear();
414
	}
415
416
	return BrowseMailQueue();
417
}
418
419
/**
420
 * Used for pausing the mail queue.
421
 */
422
function pauseMailQueueClear()
423
{
424
	global $context, $txt, $time_start;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
425
426
	// Try get more time...
427
	@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...
428
	if (function_exists('apache_reset_timeout'))
429
		@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...
430
431
	// Have we already used our maximum time?
432
	if ((time() - $time_start) < 5)
433
		return;
434
435
	$context['continue_get_data'] = '?action=admin;area=mailqueue;sa=clear;te=' . $_GET['te'] . ';sent=' . $_GET['sent'] . ';' . $context['session_var'] . '=' . $context['session_id'];
436
	$context['page_title'] = $txt['not_done_title'];
437
	$context['continue_post_data'] = '';
438
	$context['continue_countdown'] = '2';
439
	$context['sub_template'] = 'not_done';
440
441
	// Keep browse selected.
442
	$context['selected'] = 'browse';
443
444
	// What percent through are we?
445
	$context['continue_percent'] = round(($_GET['sent'] / $_GET['te']) * 100, 1);
446
447
	// Never more than 100%!
448
	$context['continue_percent'] = min($context['continue_percent'], 100);
449
450
	obExit();
451
}
452
453
/**
454
 * Test mail sending ability.
455
 *
456
 */
457
function TestMailSend()
458
{
459
	global $scripturl, $context, $sourcedir, $user_info, $smcFunc;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
460
461
	loadLanguage('ManageMail');
462
	loadTemplate('ManageMail');
463
	$context['sub_template'] = 'mailtest';
464
	$context['base_url'] = $scripturl . '?action=admin;area=mailqueue;sa=test';
465
	$context['post_url'] = $context['base_url'] . ';save';
466
467
	// Sending the test message now.
468
	if (isset($_GET['save']))
469
	{
470
		require_once($sourcedir . '/Subs-Post.php');
471
472
		// Send to the current user, no options.
473
		$to = $user_info['email'];
0 ignored issues
show
Comprehensibility introduced by
Avoid variables with short names like $to. 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...
474
		$subject = $smcFunc['htmlspecialchars']($_POST['subject']);
475
		$message = $smcFunc['htmlspecialchars']($_POST['message']);
476
477
		$result = sendmail($to, $subject, $message, null, null, false, 0);
478
		redirectexit($context['base_url'] . ';result=' . ($result ? 'success' : 'failure'));
479
	}
480
481
	// The result.
482
	if (isset($_GET['result']))
483
		$context['result'] = ($_GET['result'] == 'success' ? 'success' : 'failure');
484
}
485
486
/**
487
 * Little utility function to calculate how long ago a time was.
488
 *
489
 * @param int $time_diff The time difference, in seconds
490
 * @return string A string indicating how many days, hours, minutes or seconds (depending on $time_diff)
491
 */
492
function time_since($time_diff)
493
{
494
	global $txt;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
495
496
	if ($time_diff < 0)
497
		$time_diff = 0;
498
499
	// Just do a bit of an if fest...
500
	if ($time_diff > 86400)
501
	{
502
		$days = round($time_diff / 86400, 1);
503
		return sprintf($days == 1 ? $txt['mq_day'] : $txt['mq_days'], $time_diff / 86400);
504
	}
505
	// Hours?
506
	elseif ($time_diff > 3600)
507
	{
508
		$hours = round($time_diff / 3600, 1);
509
		return sprintf($hours == 1 ? $txt['mq_hour'] : $txt['mq_hours'], $hours);
510
	}
511
	// Minutes?
512
	elseif ($time_diff > 60)
513
	{
514
		$minutes = (int) ($time_diff / 60);
515
		return sprintf($minutes == 1 ? $txt['mq_minute'] : $txt['mq_minutes'], $minutes);
516
	}
517
	// Otherwise must be second
518
	else
519
		return sprintf($time_diff == 1 ? $txt['mq_second'] : $txt['mq_seconds'], $time_diff);
520
}
521
522
?>