Issues (1014)

Sources/ManageScheduledTasks.php (1 issue)

Labels
Severity
1
<?php
2
3
/**
4
 * This file concerns itself with scheduled tasks management.
5
 *
6
 * Simple Machines Forum (SMF)
7
 *
8
 * @package SMF
9
 * @author Simple Machines https://www.simplemachines.org
10
 * @copyright 2022 Simple Machines and individual contributors
11
 * @license https://www.simplemachines.org/about/smf/license.php BSD
12
 *
13
 * @version 2.1.0
14
 */
15
16
if (!defined('SMF'))
17
	die('No direct access...');
18
19
/**
20
 * Scheduled tasks management dispatcher. This function checks permissions and delegates
21
 * to the appropriate function based on the sub-action.
22
 * Everything here requires admin_forum permission.
23
 *
24
 * Uses ManageScheduledTasks template file
25
 * Uses ManageScheduledTasks language file
26
 */
27
function ManageScheduledTasks()
28
{
29
	global $context, $txt;
30
31
	isAllowedTo('admin_forum');
32
33
	loadLanguage('ManageScheduledTasks');
34
	loadTemplate('ManageScheduledTasks');
35
36
	$subActions = array(
37
		'taskedit' => 'EditTask',
38
		'tasklog' => 'TaskLog',
39
		'tasks' => 'ScheduledTasks',
40
		'settings' => 'TaskSettings',
41
	);
42
43
	// We need to find what's the action.
44
	if (isset($_REQUEST['sa']) && isset($subActions[$_REQUEST['sa']]))
45
		$context['sub_action'] = $_REQUEST['sa'];
46
	else
47
		$context['sub_action'] = 'tasks';
48
49
	// Now for the lovely tabs. That we all love.
50
	$context[$context['admin_menu_name']]['tab_data'] = array(
51
		'title' => $txt['scheduled_tasks_title'],
52
		'help' => '',
53
		'description' => $txt['maintain_info'],
54
		'tabs' => array(
55
			'tasks' => array(
56
				'description' => $txt['maintain_tasks_desc'],
57
			),
58
			'tasklog' => array(
59
				'description' => $txt['scheduled_log_desc'],
60
			),
61
			'settings' => array(
62
				'description' => $txt['scheduled_tasks_settings_desc'],
63
			),
64
		),
65
	);
66
67
	call_integration_hook('integrate_manage_scheduled_tasks', array(&$subActions));
68
69
	// Call it.
70
	call_helper($subActions[$context['sub_action']]);
71
}
72
73
/**
74
 * List all the scheduled task in place on the forum.
75
 *
76
 * @uses template_view_scheduled_tasks()
77
 */
78
function ScheduledTasks()
79
{
80
	global $context, $txt, $sourcedir, $smcFunc, $scripturl;
81
82
	// Mama, setup the template first - cause it's like the most important bit, like pickle in a sandwich.
83
	// ... ironically I don't like pickle. </grudge>
84
	$context['sub_template'] = 'view_scheduled_tasks';
85
	$context['page_title'] = $txt['maintain_tasks'];
86
87
	// Saving changes?
88
	if (isset($_REQUEST['save']) && isset($_POST['enable_task']))
89
	{
90
		checkSession();
91
92
		// We'll recalculate the dates at the end!
93
		require_once($sourcedir . '/ScheduledTasks.php');
94
95
		// Enable and disable as required.
96
		$enablers = array(0);
97
		foreach ($_POST['enable_task'] as $id => $enabled)
98
			if ($enabled)
99
				$enablers[] = (int) $id;
100
101
		// Do the update!
102
		$smcFunc['db_query']('', '
103
			UPDATE {db_prefix}scheduled_tasks
104
			SET disabled = CASE WHEN id_task IN ({array_int:id_task_enable}) THEN 0 ELSE 1 END',
105
			array(
106
				'id_task_enable' => $enablers,
107
			)
108
		);
109
110
		// Update the "allow_expire_redirect" setting...
111
		$get_info = $smcFunc['db_query']('', '
112
			SELECT disabled
113
			FROM {db_prefix}scheduled_tasks
114
			WHERE task = {string:remove_redirect}',
115
			array(
116
				'remove_redirect' => 'remove_topic_redirect'
117
			)
118
		);
119
120
		$temp = $smcFunc['db_fetch_assoc']($get_info);
121
		$task_disabled = !empty($temp['disabled']) ? 0 : 1;
122
		$smcFunc['db_free_result']($get_info);
123
124
		updateSettings(array('allow_expire_redirect' => $task_disabled));
125
126
		// Pop along...
127
		CalculateNextTrigger();
128
	}
129
130
	// Want to run any of the tasks?
131
	if (isset($_REQUEST['run']) && isset($_POST['run_task']))
132
	{
133
		$task_string = '';
134
135
		// Lets figure out which ones they want to run.
136
		$tasks = array();
137
		foreach ($_POST['run_task'] as $task => $dummy)
138
			$tasks[] = (int) $task;
139
140
		// Load up the tasks.
141
		$request = $smcFunc['db_query']('', '
142
			SELECT id_task, task, callable
143
			FROM {db_prefix}scheduled_tasks
144
			WHERE id_task IN ({array_int:tasks})
145
			LIMIT {int:limit}',
146
			array(
147
				'tasks' => $tasks,
148
				'limit' => count($tasks),
149
			)
150
		);
151
152
		// Lets get it on!
153
		require_once($sourcedir . '/ScheduledTasks.php');
154
		ignore_user_abort(true);
155
		while ($row = $smcFunc['db_fetch_assoc']($request))
156
		{
157
			// What kind of task are we handling?
158
			if (!empty($row['callable']))
159
				$task_string = $row['callable'];
160
161
			// Default SMF task or old mods?
162
			elseif (function_exists('scheduled_' . $row['task']))
163
				$task_string = 'scheduled_' . $row['task'];
164
165
			// One last resource, the task name.
166
			elseif (!empty($row['task']))
167
				$task_string = $row['task'];
168
169
			$start_time = microtime(true);
170
			// The functions got to exist for us to use it.
171
			if (empty($task_string))
172
				continue;
173
174
			// Try to stop a timeout, this would be bad...
175
			@set_time_limit(300);
176
			if (function_exists('apache_reset_timeout'))
177
				@apache_reset_timeout();
178
179
			// Get the callable.
180
			$callable_task = call_helper($task_string, true);
181
182
			// Perform the task.
183
			if (!empty($callable_task))
184
				$completed = call_user_func($callable_task);
0 ignored issues
show
It seems like $callable_task can also be of type boolean; however, parameter $callback of call_user_func() does only seem to accept callable, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

184
				$completed = call_user_func(/** @scrutinizer ignore-type */ $callable_task);
Loading history...
185
186
			else
187
				$completed = false;
188
189
			// Log that we did it ;)
190
			if ($completed)
191
			{
192
				$total_time = round(microtime(true) - $start_time, 3);
193
				$smcFunc['db_insert']('',
194
					'{db_prefix}log_scheduled_tasks',
195
					array('id_task' => 'int', 'time_run' => 'int', 'time_taken' => 'float'),
196
					array($row['id_task'], time(), $total_time),
197
					array('id_task')
198
				);
199
			}
200
		}
201
		$smcFunc['db_free_result']($request);
202
203
		// If we had any errors, push them to session so we can pick them up next time to tell the user.
204
		if (!empty($context['scheduled_errors']))
205
			$_SESSION['st_error'] = $context['scheduled_errors'];
206
207
		redirectexit('action=admin;area=scheduledtasks;done');
208
	}
209
210
	if (isset($_SESSION['st_error']))
211
	{
212
		$context['scheduled_errors'] = $_SESSION['st_error'];
213
		unset ($_SESSION['st_error']);
214
	}
215
216
	$listOptions = array(
217
		'id' => 'scheduled_tasks',
218
		'title' => $txt['maintain_tasks'],
219
		'base_href' => $scripturl . '?action=admin;area=scheduledtasks',
220
		'get_items' => array(
221
			'function' => 'list_getScheduledTasks',
222
		),
223
		'columns' => array(
224
			'name' => array(
225
				'header' => array(
226
					'value' => $txt['scheduled_tasks_name'],
227
					'style' => 'width: 40%;',
228
				),
229
				'data' => array(
230
					'sprintf' => array(
231
						'format' => '
232
							<a href="' . $scripturl . '?action=admin;area=scheduledtasks;sa=taskedit;tid=%1$d">%2$s</a><br><span class="smalltext">%3$s</span>',
233
						'params' => array(
234
							'id' => false,
235
							'name' => false,
236
							'desc' => false,
237
						),
238
					),
239
				),
240
			),
241
			'next_due' => array(
242
				'header' => array(
243
					'value' => $txt['scheduled_tasks_next_time'],
244
				),
245
				'data' => array(
246
					'db' => 'next_time',
247
					'class' => 'smalltext',
248
				),
249
			),
250
			'regularity' => array(
251
				'header' => array(
252
					'value' => $txt['scheduled_tasks_regularity'],
253
				),
254
				'data' => array(
255
					'db' => 'regularity',
256
					'class' => 'smalltext',
257
				),
258
			),
259
			'run_now' => array(
260
				'header' => array(
261
					'value' => $txt['scheduled_tasks_run_now'],
262
					'style' => 'width: 12%;',
263
					'class' => 'centercol',
264
				),
265
				'data' => array(
266
					'sprintf' => array(
267
						'format' =>
268
							'<input type="checkbox" name="run_task[%1$d]" id="run_task_%1$d">',
269
						'params' => array(
270
							'id' => false,
271
						),
272
					),
273
					'class' => 'centercol',
274
				),
275
			),
276
			'enabled' => array(
277
				'header' => array(
278
					'value' => $txt['scheduled_tasks_enabled'],
279
					'style' => 'width: 6%;',
280
					'class' => 'centercol',
281
				),
282
				'data' => array(
283
					'sprintf' => array(
284
						'format' =>
285
							'<input type="hidden" name="enable_task[%1$d]" id="task_%1$d" value="0"><input type="checkbox" name="enable_task[%1$d]" id="task_check_%1$d" %2$s>',
286
						'params' => array(
287
							'id' => false,
288
							'checked_state' => false,
289
						),
290
					),
291
					'class' => 'centercol',
292
				),
293
			),
294
		),
295
		'form' => array(
296
			'href' => $scripturl . '?action=admin;area=scheduledtasks',
297
		),
298
		'additional_rows' => array(
299
			array(
300
				'position' => 'below_table_data',
301
				'value' => '
302
					<input type="submit" name="save" value="' . $txt['scheduled_tasks_save_changes'] . '" class="button">
303
					<input type="submit" name="run" value="' . $txt['scheduled_tasks_run_now'] . '" class="button">',
304
			),
305
			array(
306
				'position' => 'after_title',
307
				'value' => $txt['scheduled_tasks_time_offset'],
308
			),
309
		),
310
	);
311
312
	require_once($sourcedir . '/Subs-List.php');
313
	createList($listOptions);
314
315
	$context['sub_template'] = 'view_scheduled_tasks';
316
317
	$context['tasks_were_run'] = isset($_GET['done']);
318
}
319
320
/**
321
 * Callback function for createList() in ScheduledTasks().
322
 *
323
 * @param int $start The item to start with (not used here)
324
 * @param int $items_per_page The number of items to display per page (not used here)
325
 * @param string $sort A string indicating how to sort things (not used here)
326
 * @return array An array of information about available scheduled tasks
327
 */
328
function list_getScheduledTasks($start, $items_per_page, $sort)
329
{
330
	global $smcFunc, $txt, $scripturl;
331
332
	$request = $smcFunc['db_query']('', '
333
		SELECT id_task, next_time, time_offset, time_regularity, time_unit, disabled, task
334
		FROM {db_prefix}scheduled_tasks',
335
		array(
336
		)
337
	);
338
	$known_tasks = array();
339
	while ($row = $smcFunc['db_fetch_assoc']($request))
340
	{
341
		// Find the next for regularity - don't offset as it's always server time!
342
		$offset = sprintf($txt['scheduled_task_reg_starting'], date('H:i', $row['time_offset']));
343
		$repeating = sprintf($txt['scheduled_task_reg_repeating'], $row['time_regularity'], $txt['scheduled_task_reg_unit_' . $row['time_unit']]);
344
345
		$known_tasks[] = array(
346
			'id' => $row['id_task'],
347
			'function' => $row['task'],
348
			'name' => isset($txt['scheduled_task_' . $row['task']]) ? $txt['scheduled_task_' . $row['task']] : $row['task'],
349
			'desc' => isset($txt['scheduled_task_desc_' . $row['task']]) ? sprintf($txt['scheduled_task_desc_' . $row['task']], $scripturl) : '',
350
			'next_time' => $row['disabled'] ? $txt['scheduled_tasks_na'] : timeformat(($row['next_time'] == 0 ? time() : $row['next_time']), true, 'server'),
351
			'disabled' => $row['disabled'],
352
			'checked_state' => $row['disabled'] ? '' : 'checked',
353
			'regularity' => $offset . ', ' . $repeating,
354
		);
355
	}
356
	$smcFunc['db_free_result']($request);
357
358
	return $known_tasks;
359
}
360
361
/**
362
 * Function for editing a task.
363
 *
364
 * @uses template_edit_scheduled_tasks()
365
 */
366
function EditTask()
367
{
368
	global $context, $txt, $sourcedir, $smcFunc, $scripturl;
369
370
	// Just set up some lovely context stuff.
371
	$context[$context['admin_menu_name']]['current_subsection'] = 'tasks';
372
	$context['sub_template'] = 'edit_scheduled_tasks';
373
	$context['page_title'] = $txt['scheduled_task_edit'];
374
	$context['server_time'] = timeformat(time(), false, 'server');
375
376
	// Cleaning...
377
	if (!isset($_GET['tid']))
378
		fatal_lang_error('no_access', false);
379
	$_GET['tid'] = (int) $_GET['tid'];
380
381
	// Saving?
382
	if (isset($_GET['save']))
383
	{
384
		checkSession();
385
		validateToken('admin-st');
386
387
		// We'll need this for calculating the next event.
388
		require_once($sourcedir . '/ScheduledTasks.php');
389
390
		// Do we have a valid offset?
391
		preg_match('~(\d{1,2}):(\d{1,2})~', $_POST['offset'], $matches);
392
393
		// If a half is empty then assume zero offset!
394
		if (!isset($matches[2]) || $matches[2] > 59)
395
			$matches[2] = 0;
396
		if (!isset($matches[1]) || $matches[1] > 23)
397
			$matches[1] = 0;
398
399
		// Now the offset is easy; easy peasy - except we need to offset by a few hours...
400
		$offset = $matches[1] * 3600 + $matches[2] * 60 - date('Z');
401
402
		// The other time bits are simple!
403
		$interval = max((int) $_POST['regularity'], 1);
404
		$unit = in_array(substr($_POST['unit'], 0, 1), array('m', 'h', 'd', 'w')) ? substr($_POST['unit'], 0, 1) : 'd';
405
406
		// Don't allow one minute intervals.
407
		if ($interval == 1 && $unit == 'm')
408
			$interval = 2;
409
410
		// Is it disabled?
411
		$disabled = !isset($_POST['enabled']) ? 1 : 0;
412
413
		// Do the update!
414
		$smcFunc['db_query']('', '
415
			UPDATE {db_prefix}scheduled_tasks
416
			SET disabled = {int:disabled}, time_offset = {int:time_offset}, time_unit = {string:time_unit},
417
				time_regularity = {int:time_regularity}
418
			WHERE id_task = {int:id_task}',
419
			array(
420
				'disabled' => $disabled,
421
				'time_offset' => $offset,
422
				'time_regularity' => $interval,
423
				'id_task' => $_GET['tid'],
424
				'time_unit' => $unit,
425
			)
426
		);
427
428
		// Check the next event.
429
		CalculateNextTrigger($_GET['tid'], true);
430
431
		// Return to the main list.
432
		redirectexit('action=admin;area=scheduledtasks');
433
	}
434
435
	// Load the task, understand? Que? Que?
436
	$request = $smcFunc['db_query']('', '
437
		SELECT id_task, next_time, time_offset, time_regularity, time_unit, disabled, task
438
		FROM {db_prefix}scheduled_tasks
439
		WHERE id_task = {int:id_task}',
440
		array(
441
			'id_task' => $_GET['tid'],
442
		)
443
	);
444
445
	// Should never, ever, happen!
446
	if ($smcFunc['db_num_rows']($request) == 0)
447
		fatal_lang_error('no_access', false);
448
449
	while ($row = $smcFunc['db_fetch_assoc']($request))
450
	{
451
		$context['task'] = array(
452
			'id' => $row['id_task'],
453
			'function' => $row['task'],
454
			'name' => isset($txt['scheduled_task_' . $row['task']]) ? $txt['scheduled_task_' . $row['task']] : $row['task'],
455
			'desc' => isset($txt['scheduled_task_desc_' . $row['task']]) ? sprintf($txt['scheduled_task_desc_' . $row['task']], $scripturl) : '',
456
			'next_time' => $row['disabled'] ? $txt['scheduled_tasks_na'] : timeformat($row['next_time'] == 0 ? time() : $row['next_time'], true, 'server'),
457
			'disabled' => $row['disabled'],
458
			'offset' => $row['time_offset'],
459
			'regularity' => $row['time_regularity'],
460
			'offset_formatted' => date('H:i', $row['time_offset']),
461
			'unit' => $row['time_unit'],
462
		);
463
	}
464
	$smcFunc['db_free_result']($request);
465
466
	createToken('admin-st');
467
}
468
469
/**
470
 * Show the log of all tasks that have taken place.
471
 *
472
 * Uses ManageScheduledTasks language file
473
 */
474
function TaskLog()
475
{
476
	global $scripturl, $context, $txt, $smcFunc, $sourcedir;
477
478
	// Lets load the language just incase we are outside the Scheduled area.
479
	loadLanguage('ManageScheduledTasks');
480
481
	// Empty the log?
482
	if (!empty($_POST['removeAll']))
483
	{
484
		checkSession();
485
		validateToken('admin-tl');
486
487
		$smcFunc['db_query']('truncate_table', '
488
			TRUNCATE {db_prefix}log_scheduled_tasks',
489
			array(
490
			)
491
		);
492
	}
493
494
	// Setup the list.
495
	$listOptions = array(
496
		'id' => 'task_log',
497
		'items_per_page' => 30,
498
		'title' => $txt['scheduled_log'],
499
		'no_items_label' => $txt['scheduled_log_empty'],
500
		'base_href' => $context['admin_area'] == 'scheduledtasks' ? $scripturl . '?action=admin;area=scheduledtasks;sa=tasklog' : $scripturl . '?action=admin;area=logs;sa=tasklog',
501
		'default_sort_col' => 'date',
502
		'get_items' => array(
503
			'function' => 'list_getTaskLogEntries',
504
		),
505
		'get_count' => array(
506
			'function' => 'list_getNumTaskLogEntries',
507
		),
508
		'columns' => array(
509
			'name' => array(
510
				'header' => array(
511
					'value' => $txt['scheduled_tasks_name'],
512
				),
513
				'data' => array(
514
					'db' => 'name'
515
				),
516
			),
517
			'date' => array(
518
				'header' => array(
519
					'value' => $txt['scheduled_log_time_run'],
520
				),
521
				'data' => array(
522
					'function' => function($rowData)
523
					{
524
						return timeformat($rowData['time_run'], true);
525
					},
526
				),
527
				'sort' => array(
528
					'default' => 'lst.id_log DESC',
529
					'reverse' => 'lst.id_log',
530
				),
531
			),
532
			'time_taken' => array(
533
				'header' => array(
534
					'value' => $txt['scheduled_log_time_taken'],
535
				),
536
				'data' => array(
537
					'sprintf' => array(
538
						'format' => $txt['scheduled_log_time_taken_seconds'],
539
						'params' => array(
540
							'time_taken' => false,
541
						),
542
					),
543
				),
544
				'sort' => array(
545
					'default' => 'lst.time_taken',
546
					'reverse' => 'lst.time_taken DESC',
547
				),
548
			),
549
		),
550
		'form' => array(
551
			'href' => $context['admin_area'] == 'scheduledtasks' ? $scripturl . '?action=admin;area=scheduledtasks;sa=tasklog' : $scripturl . '?action=admin;area=logs;sa=tasklog',
552
			'token' => 'admin-tl',
553
		),
554
		'additional_rows' => array(
555
			array(
556
				'position' => 'below_table_data',
557
				'value' => '
558
					<input type="submit" name="removeAll" value="' . $txt['scheduled_log_empty_log'] . '" data-confirm="' . $txt['scheduled_log_empty_log_confirm'] . '" class="button you_sure">',
559
			),
560
			array(
561
				'position' => 'after_title',
562
				'value' => $txt['scheduled_tasks_time_offset'],
563
			),
564
		),
565
	);
566
567
	createToken('admin-tl');
568
569
	require_once($sourcedir . '/Subs-List.php');
570
	createList($listOptions);
571
572
	$context['sub_template'] = 'show_list';
573
	$context['default_list'] = 'task_log';
574
575
	// Make it all look tify.
576
	$context[$context['admin_menu_name']]['current_subsection'] = 'tasklog';
577
	$context['page_title'] = $txt['scheduled_log'];
578
}
579
580
/**
581
 * Callback function for createList() in TaskLog().
582
 *
583
 * @param int $start The item to start with (for pagination purposes)
584
 * @param int $items_per_page How many items to display per page
585
 * @param string $sort A string indicating how to sort the results
586
 * @return array An array of info about task log entries
587
 */
588
function list_getTaskLogEntries($start, $items_per_page, $sort)
589
{
590
	global $smcFunc, $txt;
591
592
	$request = $smcFunc['db_query']('', '
593
		SELECT lst.id_log, lst.id_task, lst.time_run, lst.time_taken, st.task
594
		FROM {db_prefix}log_scheduled_tasks AS lst
595
			INNER JOIN {db_prefix}scheduled_tasks AS st ON (st.id_task = lst.id_task)
596
		ORDER BY {raw:sort}
597
		LIMIT {int:start}, {int:items}',
598
		array(
599
			'sort' => $sort,
600
			'start' => $start,
601
			'items' => $items_per_page,
602
		)
603
	);
604
	$log_entries = array();
605
	while ($row = $smcFunc['db_fetch_assoc']($request))
606
		$log_entries[] = array(
607
			'id' => $row['id_log'],
608
			'name' => isset($txt['scheduled_task_' . $row['task']]) ? $txt['scheduled_task_' . $row['task']] : $row['task'],
609
			'time_run' => $row['time_run'],
610
			'time_taken' => $row['time_taken'],
611
		);
612
	$smcFunc['db_free_result']($request);
613
614
	return $log_entries;
615
}
616
617
/**
618
 * Callback function for createList() in TaskLog().
619
 *
620
 * @return int The number of log entries
621
 */
622
function list_getNumTaskLogEntries()
623
{
624
	global $smcFunc;
625
626
	$request = $smcFunc['db_query']('', '
627
		SELECT COUNT(*)
628
		FROM {db_prefix}log_scheduled_tasks',
629
		array(
630
		)
631
	);
632
	list ($num_entries) = $smcFunc['db_fetch_row']($request);
633
	$smcFunc['db_free_result']($request);
634
635
	return $num_entries;
636
}
637
638
/**
639
 * This handles settings related to scheduled tasks
640
 *
641
 * @param bool $return_config Whether or not to return the config vars. Used in the admin search.
642
 * @return void|array If return_config is true, returns the array of $config_vars
643
 */
644
function TaskSettings($return_config = false)
645
{
646
	global $sourcedir, $txt, $context, $scripturl;
647
648
	// We will need the utility functions from here.
649
	require_once($sourcedir . '/ManageServer.php');
650
651
	loadLanguage('Help');
652
653
	$config_vars = array(
654
		array('check', 'cron_is_real_cron', 'subtext' => $txt['cron_is_real_cron_desc'], 'help' => 'cron_is_real_cron'),
655
	);
656
657
	call_integration_hook('integrate_scheduled_tasks_settings', array(&$config_vars));
658
659
	if ($return_config)
660
		return $config_vars;
661
662
	// Set up the template.
663
	$context['page_title'] = $txt['scheduled_tasks_settings'];
664
	$context['sub_template'] = 'show_settings';
665
666
	$context['post_url'] = $scripturl . '?action=admin;area=scheduledtasks;save;sa=settings';
667
	$context['settings_title'] = $txt['scheduled_tasks_settings'];
668
669
	// Saving?
670
	if (isset($_GET['save']))
671
	{
672
		checkSession();
673
674
		$save_vars = $config_vars;
675
676
		call_integration_hook('integrate_save_scheduled_tasks_settings', array(&$save_vars));
677
678
		saveDBSettings($save_vars);
679
680
		$_SESSION['adm-save'] = true;
681
682
		redirectexit('action=admin;area=scheduledtasks;sa=settings');
683
	}
684
685
	prepareDBSettingContext($config_vars);
686
}
687
688
?>