Issues (1014)

Sources/ManageSearchEngines.php (1 issue)

Labels
Severity
1
<?php
2
3
/**
4
 * This file contains all the screens that relate to search engines.
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.2
14
 */
15
16
if (!defined('SMF'))
17
	die('No direct access...');
18
19
/**
20
 * Entry point for this section.
21
 */
22
function SearchEngines()
23
{
24
	global $context, $txt, $modSettings;
25
26
	isAllowedTo('admin_forum');
27
28
	loadLanguage('Search');
29
	loadTemplate('ManageSearch');
30
31
	if (!empty($modSettings['spider_mode']))
32
	{
33
		$subActions = array(
34
			'editspiders' => 'EditSpider',
35
			'logs' => 'SpiderLogs',
36
			'settings' => 'ManageSearchEngineSettings',
37
			'spiders' => 'ViewSpiders',
38
			'stats' => 'SpiderStats',
39
		);
40
		$default = 'stats';
41
	}
42
	else
43
	{
44
		$subActions = array(
45
			'settings' => 'ManageSearchEngineSettings',
46
		);
47
		$default = 'settings';
48
	}
49
50
	// Ensure we have a valid subaction.
51
	$context['sub_action'] = isset($_REQUEST['sa']) && isset($subActions[$_REQUEST['sa']]) ? $_REQUEST['sa'] : $default;
52
53
	$context['page_title'] = $txt['search_engines'];
54
55
	// Some more tab data.
56
	$context[$context['admin_menu_name']]['tab_data'] = array(
57
		'title' => $txt['search_engines'],
58
		'description' => $txt['search_engines_description'],
59
	);
60
61
	call_integration_hook('integrate_manage_search_engines', array(&$subActions));
62
63
	// Call the function!
64
	call_helper($subActions[$context['sub_action']]);
65
}
66
67
/**
68
 * This is really just the settings page.
69
 *
70
 * @param bool $return_config Whether to return the config_vars array (used for admin search)
71
 * @return void|array Returns nothing or returns the $config_vars array if $return_config is true
72
 */
73
function ManageSearchEngineSettings($return_config = false)
74
{
75
	global $context, $txt, $scripturl, $sourcedir, $smcFunc;
76
77
	$config_vars = array(
78
		// How much detail?
79
		array('select', 'spider_mode', 'subtext' => $txt['spider_mode_note'], array($txt['spider_mode_off'], $txt['spider_mode_standard'], $txt['spider_mode_high'], $txt['spider_mode_vhigh']), 'onchange' => 'disableFields();'),
80
		'spider_group' => array('select', 'spider_group', 'subtext' => $txt['spider_group_note'], array($txt['spider_group_none'], $txt['membergroups_members'])),
81
		array('select', 'show_spider_online', array($txt['show_spider_online_no'], $txt['show_spider_online_summary'], $txt['show_spider_online_detail'], $txt['show_spider_online_detail_admin'])),
82
	);
83
84
	// Set up a message.
85
	$context['settings_message'] = sprintf($txt['spider_settings_desc'], $scripturl . '?action=admin;area=logs;sa=settings;' . $context['session_var'] . '=' . $context['session_id']);
86
87
	// Do some javascript.
88
	$javascript_function = '
89
		function disableFields()
90
		{
91
			disabledState = document.getElementById(\'spider_mode\').value == 0;';
92
93
	foreach ($config_vars as $variable)
94
		if ($variable[1] != 'spider_mode')
95
			$javascript_function .= '
96
			if (document.getElementById(\'' . $variable[1] . '\'))
97
				document.getElementById(\'' . $variable[1] . '\').disabled = disabledState;';
98
99
	$javascript_function .= '
100
		}
101
		disableFields();';
102
103
	call_integration_hook('integrate_modify_search_engine_settings', array(&$config_vars));
104
105
	if ($return_config)
106
		return $config_vars;
107
108
	// We need to load the groups for the spider group thingy.
109
	$request = $smcFunc['db_query']('', '
110
		SELECT id_group, group_name
111
		FROM {db_prefix}membergroups
112
		WHERE id_group != {int:admin_group}
113
			AND id_group != {int:moderator_group}',
114
		array(
115
			'admin_group' => 1,
116
			'moderator_group' => 3,
117
		)
118
	);
119
	while ($row = $smcFunc['db_fetch_assoc']($request))
120
		$config_vars['spider_group'][2][$row['id_group']] = $row['group_name'];
121
	$smcFunc['db_free_result']($request);
122
123
	// Make sure it's valid - note that regular members are given id_group = 1 which is reversed in Load.php - no admins here!
124
	if (isset($_POST['spider_group']) && !isset($config_vars['spider_group'][2][$_POST['spider_group']]))
125
		$_POST['spider_group'] = 0;
126
127
	// We'll want this for our easy save.
128
	require_once($sourcedir . '/ManageServer.php');
129
130
	// Setup the template.
131
	$context['page_title'] = $txt['settings'];
132
	$context['sub_template'] = 'show_settings';
133
134
	// Are we saving them - are we??
135
	if (isset($_GET['save']))
136
	{
137
		checkSession();
138
139
		call_integration_hook('integrate_save_search_engine_settings');
140
		saveDBSettings($config_vars);
141
		recacheSpiderNames();
142
		$_SESSION['adm-save'] = true;
143
		redirectexit('action=admin;area=sengines;sa=settings');
144
	}
145
146
	// Final settings...
147
	$context['post_url'] = $scripturl . '?action=admin;area=sengines;save;sa=settings';
148
	$context['settings_title'] = $txt['settings'];
149
	addInlineJavaScript($javascript_function, true);
150
151
	// Prepare the settings...
152
	prepareDBSettingContext($config_vars);
153
}
154
155
/**
156
 * View a list of all the spiders we know about.
157
 */
158
function ViewSpiders()
159
{
160
	global $context, $txt, $sourcedir, $scripturl, $smcFunc, $modSettings;
161
162
	if (!isset($_SESSION['spider_stat']) || $_SESSION['spider_stat'] < time() - 60)
163
	{
164
		consolidateSpiderStats();
165
		$_SESSION['spider_stat'] = time();
166
	}
167
168
	// Are we adding a new one?
169
	if (!empty($_POST['addSpider']))
170
		return EditSpider();
0 ignored issues
show
Are you sure the usage of EditSpider() is correct as it seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
171
	// User pressed the 'remove selection button'.
172
	elseif (!empty($_POST['removeSpiders']) && !empty($_POST['remove']) && is_array($_POST['remove']))
173
	{
174
		checkSession();
175
		validateToken('admin-ser');
176
177
		// Make sure every entry is a proper integer.
178
		foreach ($_POST['remove'] as $index => $spider_id)
179
			$_POST['remove'][(int) $index] = (int) $spider_id;
180
181
		// Delete them all!
182
		$smcFunc['db_query']('', '
183
			DELETE FROM {db_prefix}spiders
184
			WHERE id_spider IN ({array_int:remove_list})',
185
			array(
186
				'remove_list' => $_POST['remove'],
187
			)
188
		);
189
		$smcFunc['db_query']('', '
190
			DELETE FROM {db_prefix}log_spider_hits
191
			WHERE id_spider IN ({array_int:remove_list})',
192
			array(
193
				'remove_list' => $_POST['remove'],
194
			)
195
		);
196
		$smcFunc['db_query']('', '
197
			DELETE FROM {db_prefix}log_spider_stats
198
			WHERE id_spider IN ({array_int:remove_list})',
199
			array(
200
				'remove_list' => $_POST['remove'],
201
			)
202
		);
203
204
		cache_put_data('spider_search', null, 300);
205
		recacheSpiderNames();
206
	}
207
208
	// Get the last seens.
209
	$request = $smcFunc['db_query']('', '
210
		SELECT id_spider, MAX(last_seen) AS last_seen_time
211
		FROM {db_prefix}log_spider_stats
212
		GROUP BY id_spider',
213
		array(
214
		)
215
	);
216
217
	$context['spider_last_seen'] = array();
218
	while ($row = $smcFunc['db_fetch_assoc']($request))
219
		$context['spider_last_seen'][$row['id_spider']] = $row['last_seen_time'];
220
	$smcFunc['db_free_result']($request);
221
222
	createToken('admin-ser');
223
	$listOptions = array(
224
		'id' => 'spider_list',
225
		'title' => $txt['spiders'],
226
		'items_per_page' => $modSettings['defaultMaxListItems'],
227
		'base_href' => $scripturl . '?action=admin;area=sengines;sa=spiders',
228
		'default_sort_col' => 'name',
229
		'get_items' => array(
230
			'function' => 'list_getSpiders',
231
		),
232
		'get_count' => array(
233
			'function' => 'list_getNumSpiders',
234
		),
235
		'no_items_label' => $txt['spiders_no_entries'],
236
		'columns' => array(
237
			'name' => array(
238
				'header' => array(
239
					'value' => $txt['spider_name'],
240
				),
241
				'data' => array(
242
					'function' => function($rowData) use ($smcFunc, $scripturl)
243
					{
244
						return sprintf('<a href="%1$s?action=admin;area=sengines;sa=editspiders;sid=%2$d">%3$s</a>', $scripturl, $rowData['id_spider'], $smcFunc['htmlspecialchars']($rowData['spider_name']));
245
					},
246
				),
247
				'sort' => array(
248
					'default' => 'spider_name DESC',
249
					'reverse' => 'spider_name',
250
				),
251
			),
252
			'last_seen' => array(
253
				'header' => array(
254
					'value' => $txt['spider_last_seen'],
255
				),
256
				'data' => array(
257
					'function' => function($rowData) use ($context, $txt)
258
					{
259
						return isset($context['spider_last_seen'][$rowData['id_spider']]) ? timeformat($context['spider_last_seen'][$rowData['id_spider']]) : $txt['spider_last_never'];
260
					},
261
				),
262
			),
263
			'user_agent' => array(
264
				'header' => array(
265
					'value' => $txt['spider_agent'],
266
				),
267
				'data' => array(
268
					'db_htmlsafe' => 'user_agent',
269
				),
270
				'sort' => array(
271
					'default' => 'user_agent',
272
					'reverse' => 'user_agent DESC',
273
				),
274
			),
275
			'ip_info' => array(
276
				'header' => array(
277
					'value' => $txt['spider_ip_info'],
278
				),
279
				'data' => array(
280
					'db_htmlsafe' => 'ip_info',
281
					'class' => 'smalltext',
282
				),
283
				'sort' => array(
284
					'default' => 'ip_info',
285
					'reverse' => 'ip_info DESC',
286
				),
287
			),
288
			'check' => array(
289
				'header' => array(
290
					'value' => '<input type="checkbox" onclick="invertAll(this, this.form);">',
291
					'class' => 'centercol',
292
				),
293
				'data' => array(
294
					'sprintf' => array(
295
						'format' => '<input type="checkbox" name="remove[]" value="%1$d">',
296
						'params' => array(
297
							'id_spider' => false,
298
						),
299
					),
300
					'class' => 'centercol',
301
				),
302
			),
303
		),
304
		'form' => array(
305
			'href' => $scripturl . '?action=admin;area=sengines;sa=spiders',
306
			'token' => 'admin-ser',
307
		),
308
		'additional_rows' => array(
309
			array(
310
				'position' => 'bottom_of_list',
311
				'value' => '
312
					<input type="submit" name="removeSpiders" value="' . $txt['spiders_remove_selected'] . '" data-confirm="' . $txt['spider_remove_selected_confirm'] . '" class="button you_sure">
313
					<input type="submit" name="addSpider" value="' . $txt['spiders_add'] . '" class="button">
314
				',
315
			),
316
		),
317
	);
318
319
	require_once($sourcedir . '/Subs-List.php');
320
	createList($listOptions);
321
322
	$context['sub_template'] = 'show_list';
323
	$context['default_list'] = 'spider_list';
324
}
325
326
/**
327
 * Callback function for createList()
328
 *
329
 * @param int $start The item to start with (for pagination purposes)
330
 * @param int $items_per_page The number of items to show per page
331
 * @param string $sort A string indicating how to sort the results
332
 * @return array An array of information about known spiders
333
 */
334
function list_getSpiders($start, $items_per_page, $sort)
335
{
336
	global $smcFunc;
337
338
	$request = $smcFunc['db_query']('', '
339
		SELECT id_spider, spider_name, user_agent, ip_info
340
		FROM {db_prefix}spiders
341
		ORDER BY {raw:sort}
342
		LIMIT {int:start}, {int:items}',
343
		array(
344
			'sort' => $sort,
345
			'start' => $start,
346
			'items' => $items_per_page,
347
		)
348
	);
349
	$spiders = array();
350
	while ($row = $smcFunc['db_fetch_assoc']($request))
351
		$spiders[$row['id_spider']] = $row;
352
	$smcFunc['db_free_result']($request);
353
354
	return $spiders;
355
}
356
357
/**
358
 * Callback function for createList()
359
 *
360
 * @return int The number of known spiders
361
 */
362
function list_getNumSpiders()
363
{
364
	global $smcFunc;
365
366
	$request = $smcFunc['db_query']('', '
367
		SELECT COUNT(*) AS num_spiders
368
		FROM {db_prefix}spiders',
369
		array(
370
		)
371
	);
372
	list ($numSpiders) = $smcFunc['db_fetch_row']($request);
373
	$smcFunc['db_free_result']($request);
374
375
	return $numSpiders;
376
}
377
378
/**
379
 * Here we can add, and edit, spider info!
380
 */
381
function EditSpider()
382
{
383
	global $context, $smcFunc, $txt;
384
385
	// Some standard stuff.
386
	$context['id_spider'] = !empty($_GET['sid']) ? (int) $_GET['sid'] : 0;
387
	$context['page_title'] = $context['id_spider'] ? $txt['spiders_edit'] : $txt['spiders_add'];
388
	$context['sub_template'] = 'spider_edit';
389
390
	// Are we saving?
391
	if (!empty($_POST['save']))
392
	{
393
		checkSession();
394
		validateToken('admin-ses');
395
396
		foreach (array('spider_name', 'spider_agent') as $key)
397
			$_POST[$key] = trim($smcFunc['normalize']($_POST[$key]));
398
399
		$ips = array();
400
		// Check the IP range is valid.
401
		$ip_sets = explode(',', $_POST['spider_ip']);
402
		foreach ($ip_sets as $set)
403
		{
404
			$test = ip2range(trim($set));
405
			if (!empty($test))
406
				$ips[] = $set;
407
		}
408
		$ips = implode(',', $ips);
409
410
		// Goes in as it is...
411
		if ($context['id_spider'])
412
			$smcFunc['db_query']('', '
413
				UPDATE {db_prefix}spiders
414
				SET spider_name = {string:spider_name}, user_agent = {string:spider_agent},
415
					ip_info = {string:ip_info}
416
				WHERE id_spider = {int:current_spider}',
417
				array(
418
					'current_spider' => $context['id_spider'],
419
					'spider_name' => $_POST['spider_name'],
420
					'spider_agent' => $_POST['spider_agent'],
421
					'ip_info' => $ips,
422
				)
423
			);
424
		else
425
			$smcFunc['db_insert']('insert',
426
				'{db_prefix}spiders',
427
				array(
428
					'spider_name' => 'string', 'user_agent' => 'string', 'ip_info' => 'string',
429
				),
430
				array(
431
					$_POST['spider_name'], $_POST['spider_agent'], $ips,
432
				),
433
				array('id_spider')
434
			);
435
436
		cache_put_data('spider_search', null);
437
		recacheSpiderNames();
438
439
		redirectexit('action=admin;area=sengines;sa=spiders');
440
	}
441
442
	// The default is new.
443
	$context['spider'] = array(
444
		'id' => 0,
445
		'name' => '',
446
		'agent' => '',
447
		'ip_info' => '',
448
	);
449
450
	// An edit?
451
	if ($context['id_spider'])
452
	{
453
		$request = $smcFunc['db_query']('', '
454
			SELECT id_spider, spider_name, user_agent, ip_info
455
			FROM {db_prefix}spiders
456
			WHERE id_spider = {int:current_spider}',
457
			array(
458
				'current_spider' => $context['id_spider'],
459
			)
460
		);
461
		if ($row = $smcFunc['db_fetch_assoc']($request))
462
			$context['spider'] = array(
463
				'id' => $row['id_spider'],
464
				'name' => $row['spider_name'],
465
				'agent' => $row['user_agent'],
466
				'ip_info' => $row['ip_info'],
467
			);
468
		$smcFunc['db_free_result']($request);
469
	}
470
471
	createToken('admin-ses');
472
}
473
474
/**
475
 * Do we think the current user is a spider?
476
 *
477
 * @todo Should this not be... you know... in a different file?
478
 * @return int The ID of the spider if it's known or 0 if it isn't known/isn't a spider
479
 */
480
function SpiderCheck()
481
{
482
	global $modSettings, $smcFunc;
483
484
	if (isset($_SESSION['id_robot']))
485
		unset($_SESSION['id_robot']);
486
	$_SESSION['robot_check'] = time();
487
488
	// We cache the spider data for ten minutes if we can.
489
	if (($spider_data = cache_get_data('spider_search', 600)) === null)
490
	{
491
		$request = $smcFunc['db_query']('', '
492
			SELECT id_spider, user_agent, ip_info
493
			FROM {db_prefix}spiders
494
			ORDER BY LENGTH(user_agent) DESC',
495
			array(
496
			)
497
		);
498
		$spider_data = array();
499
		while ($row = $smcFunc['db_fetch_assoc']($request))
500
			$spider_data[] = $row;
501
		$smcFunc['db_free_result']($request);
502
503
		cache_put_data('spider_search', $spider_data, 600);
504
	}
505
506
	if (empty($spider_data))
507
		return false;
508
509
	// Only do these bits once.
510
	$ci_user_agent = strtolower($_SERVER['HTTP_USER_AGENT']);
511
512
	foreach ($spider_data as $spider)
513
	{
514
		// User agent is easy.
515
		if (!empty($spider['user_agent']) && strpos($ci_user_agent, strtolower($spider['user_agent'])) !== false)
516
			$_SESSION['id_robot'] = $spider['id_spider'];
517
		// IP stuff is harder.
518
		elseif ($_SERVER['REMOTE_ADDR'])
519
		{
520
			$ips = explode(',', $spider['ip_info']);
521
			foreach ($ips as $ip)
522
			{
523
				if ($ip === '')
524
					continue;
525
526
				$ip = ip2range($ip);
527
				if (!empty($ip))
528
				{
529
					if (inet_ptod($ip['low']) <= inet_ptod($_SERVER['REMOTE_ADDR']) && inet_ptod($ip['high']) >= inet_ptod($_SERVER['REMOTE_ADDR']))
530
						$_SESSION['id_robot'] = $spider['id_spider'];
531
				}
532
			}
533
		}
534
535
		if (isset($_SESSION['id_robot']))
536
			break;
537
	}
538
539
	// If this is low server tracking then log the spider here as opposed to the main logging function.
540
	if (!empty($modSettings['spider_mode']) && $modSettings['spider_mode'] == 1 && !empty($_SESSION['id_robot']))
541
		logSpider();
542
543
	return !empty($_SESSION['id_robot']) ? $_SESSION['id_robot'] : 0;
544
}
545
546
/**
547
 * Log the spider presence online.
548
 *
549
 * @todo Different file?
550
 */
551
function logSpider()
552
{
553
	global $smcFunc, $modSettings, $context;
554
555
	if (empty($modSettings['spider_mode']) || empty($_SESSION['id_robot']))
556
		return;
557
558
	// Attempt to update today's entry.
559
	if ($modSettings['spider_mode'] == 1)
560
	{
561
		$date = smf_strftime('%Y-%m-%d', time());
562
		$smcFunc['db_query']('', '
563
			UPDATE {db_prefix}log_spider_stats
564
			SET last_seen = {int:current_time}, page_hits = page_hits + 1
565
			WHERE id_spider = {int:current_spider}
566
				AND stat_date = {date:current_date}',
567
			array(
568
				'current_date' => $date,
569
				'current_time' => time(),
570
				'current_spider' => $_SESSION['id_robot'],
571
			)
572
		);
573
574
		// Nothing updated?
575
		if ($smcFunc['db_affected_rows']() == 0)
576
		{
577
			$smcFunc['db_insert']('ignore',
578
				'{db_prefix}log_spider_stats',
579
				array(
580
					'id_spider' => 'int', 'last_seen' => 'int', 'stat_date' => 'date', 'page_hits' => 'int',
581
				),
582
				array(
583
					$_SESSION['id_robot'], time(), $date, 1,
584
				),
585
				array('id_spider', 'stat_date')
586
			);
587
		}
588
	}
589
	// If we're tracking better stats than track, better stats - we sort out the today thing later.
590
	else
591
	{
592
		if ($modSettings['spider_mode'] > 2)
593
		{
594
			$url = $_GET + array('USER_AGENT' => $_SERVER['HTTP_USER_AGENT']);
595
			unset($url['sesc'], $url[$context['session_var']]);
596
			$url = $smcFunc['json_encode']($url);
597
		}
598
		else
599
			$url = '';
600
601
		$smcFunc['db_insert']('insert',
602
			'{db_prefix}log_spider_hits',
603
			array('id_spider' => 'int', 'log_time' => 'int', 'url' => 'string'),
604
			array($_SESSION['id_robot'], time(), $url),
605
			array()
606
		);
607
	}
608
}
609
610
/**
611
 * This function takes any unprocessed hits and turns them into stats.
612
 */
613
function consolidateSpiderStats()
614
{
615
	global $smcFunc;
616
617
	$request = $smcFunc['db_query']('', '
618
		SELECT id_spider, MAX(log_time) AS last_seen, COUNT(*) AS num_hits
619
		FROM {db_prefix}log_spider_hits
620
		WHERE processed = {int:not_processed}
621
		GROUP BY id_spider, MONTH(log_time), DAYOFMONTH(log_time)',
622
		array(
623
			'not_processed' => 0,
624
		)
625
	);
626
	$spider_hits = array();
627
	while ($row = $smcFunc['db_fetch_assoc']($request))
628
		$spider_hits[] = $row;
629
	$smcFunc['db_free_result']($request);
630
631
	if (empty($spider_hits))
632
		return;
633
634
	// Attempt to update the master data.
635
	$stat_inserts = array();
636
	foreach ($spider_hits as $stat)
637
	{
638
		// We assume the max date is within the right day.
639
		$date = smf_strftime('%Y-%m-%d', $stat['last_seen']);
640
		$smcFunc['db_query']('', '
641
			UPDATE {db_prefix}log_spider_stats
642
			SET page_hits = page_hits + {int:hits},
643
				last_seen = CASE WHEN last_seen > {int:last_seen} THEN last_seen ELSE {int:last_seen} END
644
			WHERE id_spider = {int:current_spider}
645
				AND stat_date = {date:last_seen_date}',
646
			array(
647
				'last_seen_date' => $date,
648
				'last_seen' => $stat['last_seen'],
649
				'current_spider' => $stat['id_spider'],
650
				'hits' => $stat['num_hits'],
651
			)
652
		);
653
		if ($smcFunc['db_affected_rows']() == 0)
654
			$stat_inserts[] = array($date, $stat['id_spider'], $stat['num_hits'], $stat['last_seen']);
655
	}
656
657
	// New stats?
658
	if (!empty($stat_inserts))
659
		$smcFunc['db_insert']('ignore',
660
			'{db_prefix}log_spider_stats',
661
			array('stat_date' => 'date', 'id_spider' => 'int', 'page_hits' => 'int', 'last_seen' => 'int'),
662
			$stat_inserts,
663
			array('stat_date', 'id_spider')
664
		);
665
666
	// All processed.
667
	$smcFunc['db_query']('', '
668
		UPDATE {db_prefix}log_spider_hits
669
		SET processed = {int:is_processed}
670
		WHERE processed = {int:not_processed}',
671
		array(
672
			'is_processed' => 1,
673
			'not_processed' => 0,
674
		)
675
	);
676
}
677
678
/**
679
 * See what spiders have been up to.
680
 */
681
function SpiderLogs()
682
{
683
	global $context, $txt, $sourcedir, $scripturl, $smcFunc, $modSettings;
684
685
	// Load the template and language just incase.
686
	loadLanguage('Search');
687
	loadTemplate('ManageSearch');
688
689
	// Did they want to delete some entries?
690
	if ((!empty($_POST['delete_entries']) && isset($_POST['older'])) || !empty($_POST['removeAll']))
691
	{
692
		checkSession();
693
		validateToken('admin-sl');
694
695
		if (!empty($_POST['delete_entries']) && isset($_POST['older']))
696
		{
697
			$deleteTime = time() - (((int) $_POST['older']) * 24 * 60 * 60);
698
699
			// Delete the entires.
700
			$smcFunc['db_query']('', '
701
				DELETE FROM {db_prefix}log_spider_hits
702
				WHERE log_time < {int:delete_period}',
703
				array(
704
					'delete_period' => $deleteTime,
705
				)
706
			);
707
		}
708
		else
709
		{
710
			// Deleting all of them
711
			$smcFunc['db_query']('', '
712
				TRUNCATE TABLE {db_prefix}log_spider_hits',
713
				array()
714
			);
715
		}
716
	}
717
718
	$listOptions = array(
719
		'id' => 'spider_logs',
720
		'items_per_page' => $modSettings['defaultMaxListItems'],
721
		'title' => $txt['spider_logs'],
722
		'no_items_label' => $txt['spider_logs_empty'],
723
		'base_href' => $context['admin_area'] == 'sengines' ? $scripturl . '?action=admin;area=sengines;sa=logs' : $scripturl . '?action=admin;area=logs;sa=spiderlog',
724
		'default_sort_col' => 'log_time',
725
		'get_items' => array(
726
			'function' => 'list_getSpiderLogs',
727
		),
728
		'get_count' => array(
729
			'function' => 'list_getNumSpiderLogs',
730
		),
731
		'columns' => array(
732
			'name' => array(
733
				'header' => array(
734
					'value' => $txt['spider'],
735
				),
736
				'data' => array(
737
					'db' => 'spider_name',
738
				),
739
				'sort' => array(
740
					'default' => 's.spider_name',
741
					'reverse' => 's.spider_name DESC',
742
				),
743
			),
744
			'log_time' => array(
745
				'header' => array(
746
					'value' => $txt['spider_time'],
747
				),
748
				'data' => array(
749
					'function' => function($rowData)
750
					{
751
						return timeformat($rowData['log_time']);
752
					},
753
				),
754
				'sort' => array(
755
					'default' => 'sl.id_hit DESC',
756
					'reverse' => 'sl.id_hit',
757
				),
758
			),
759
			'viewing' => array(
760
				'header' => array(
761
					'value' => $txt['spider_viewing'],
762
				),
763
				'data' => array(
764
					'db' => 'url',
765
				),
766
			),
767
		),
768
		'form' => array(
769
			'token' => 'admin-sl',
770
			'href' => $scripturl . '?action=admin;area=sengines;sa=logs',
771
		),
772
		'additional_rows' => array(
773
			array(
774
				'position' => 'after_title',
775
				'value' => $txt['spider_logs_info'],
776
			),
777
			array(
778
				'position' => 'below_table_data',
779
				'value' => '<input type="submit" name="removeAll" value="' . $txt['spider_log_empty_log'] . '" data-confirm="' . $txt['spider_log_empty_log_confirm'] . '" class="button you_sure">',
780
			),
781
		),
782
	);
783
784
	createToken('admin-sl');
785
786
	require_once($sourcedir . '/Subs-List.php');
787
	createList($listOptions);
788
789
	// Now determine the actions of the URLs.
790
	if (!empty($context['spider_logs']['rows']))
791
	{
792
		$urls = array();
793
794
		// Grab the current /url.
795
		foreach ($context['spider_logs']['rows'] as $k => $row)
796
		{
797
			// Feature disabled?
798
			if (empty($row['data']['viewing']['value']) && isset($modSettings['spider_mode']) && $modSettings['spider_mode'] < 3)
799
				$context['spider_logs']['rows'][$k]['viewing']['value'] = '<em>' . $txt['spider_disabled'] . '</em>';
800
			else
801
				$urls[$k] = array($row['data']['viewing']['value'], -1);
802
		}
803
804
		// Now stick in the new URLs.
805
		require_once($sourcedir . '/Who.php');
806
		$urls = determineActions($urls, 'whospider_');
807
		foreach ($urls as $k => $new_url)
808
		{
809
			if (is_array($new_url))
810
			{
811
				$context['spider_logs']['rows'][$k]['data']['viewing']['value'] = $txt[$new_url['label']];
812
				$context['spider_logs']['rows'][$k]['data']['viewing']['class'] = $new_url['class'];
813
			} else
814
				$context['spider_logs']['rows'][$k]['data']['viewing']['value'] = $new_url;
815
		}
816
	}
817
818
	$context['page_title'] = $txt['spider_logs'];
819
	$context['sub_template'] = 'show_spider_logs';
820
	$context['default_list'] = 'spider_logs';
821
}
822
823
/**
824
 * Callback function for createList()
825
 *
826
 * @param int $start The item to start with (for pagination purposes)
827
 * @param int $items_per_page How many items to show per page
828
 * @param string $sort A string indicating how to sort the results
829
 * @return array An array of spider log data
830
 */
831
function list_getSpiderLogs($start, $items_per_page, $sort)
832
{
833
	global $smcFunc;
834
835
	$request = $smcFunc['db_query']('', '
836
		SELECT sl.id_spider, sl.url, sl.log_time, s.spider_name
837
		FROM {db_prefix}log_spider_hits AS sl
838
			INNER JOIN {db_prefix}spiders AS s ON (s.id_spider = sl.id_spider)
839
		ORDER BY {raw:sort}
840
		LIMIT {int:start}, {int:items}',
841
		array(
842
			'sort' => $sort,
843
			'start' => $start,
844
			'items' => $items_per_page,
845
		)
846
	);
847
	$spider_logs = array();
848
	while ($row = $smcFunc['db_fetch_assoc']($request))
849
		$spider_logs[] = $row;
850
	$smcFunc['db_free_result']($request);
851
852
	return $spider_logs;
853
}
854
855
/**
856
 * Callback function for createList()
857
 *
858
 * @return int The number of spider log entries
859
 */
860
function list_getNumSpiderLogs()
861
{
862
	global $smcFunc;
863
864
	$request = $smcFunc['db_query']('', '
865
		SELECT COUNT(*) AS num_logs
866
		FROM {db_prefix}log_spider_hits',
867
		array(
868
		)
869
	);
870
	list ($numLogs) = $smcFunc['db_fetch_row']($request);
871
	$smcFunc['db_free_result']($request);
872
873
	return $numLogs;
874
}
875
876
/**
877
 * Show the spider statistics.
878
 */
879
function SpiderStats()
880
{
881
	global $context, $txt, $sourcedir, $scripturl, $smcFunc, $modSettings;
882
883
	// Force an update of the stats every 60 seconds.
884
	if (!isset($_SESSION['spider_stat']) || $_SESSION['spider_stat'] < time() - 60)
885
	{
886
		consolidateSpiderStats();
887
		$_SESSION['spider_stat'] = time();
888
	}
889
890
	// Are we cleaning up some old stats?
891
	if (!empty($_POST['delete_entries']) && isset($_POST['older']))
892
	{
893
		checkSession();
894
		validateToken('admin-ss');
895
896
		$deleteTime = time() - (((int) $_POST['older']) * 24 * 60 * 60);
897
898
		// Delete the entires.
899
		$smcFunc['db_query']('', '
900
			DELETE FROM {db_prefix}log_spider_stats
901
			WHERE last_seen < {int:delete_period}',
902
			array(
903
				'delete_period' => $deleteTime,
904
			)
905
		);
906
	}
907
908
	// Get the earliest and latest dates.
909
	$request = $smcFunc['db_query']('', '
910
		SELECT MIN(stat_date) AS first_date, MAX(stat_date) AS last_date
911
		FROM {db_prefix}log_spider_stats',
912
		array(
913
		)
914
	);
915
916
	list ($min_date, $max_date) = $smcFunc['db_fetch_row']($request);
917
	$smcFunc['db_free_result']($request);
918
919
	$min_year = (int) substr($min_date, 0, 4);
920
	$max_year = (int) substr($max_date, 0, 4);
921
	$min_month = (int) substr($min_date, 5, 2);
922
	$max_month = (int) substr($max_date, 5, 2);
923
924
	// Prepare the dates for the drop down.
925
	$date_choices = array();
926
	for ($y = $min_year; $y <= $max_year; $y++)
927
		for ($m = 1; $m <= 12; $m++)
928
		{
929
			// This doesn't count?
930
			if ($y == $min_year && $m < $min_month)
931
				continue;
932
			if ($y == $max_year && $m > $max_month)
933
				break;
934
935
			$date_choices[$y . $m] = $txt['months_short'][$m] . ' ' . $y;
936
		}
937
938
	// What are we currently viewing?
939
	$current_date = isset($_REQUEST['new_date']) && isset($date_choices[$_REQUEST['new_date']]) ? $_REQUEST['new_date'] : $max_date;
940
941
	// Prepare the HTML.
942
	if (!empty($date_choices))
943
	{
944
		$date_select = '
945
		' . $txt['spider_stats_select_month'] . ':
946
		<select name="new_date" onchange="document.spider_stat_list.submit();">';
947
948
		foreach ($date_choices as $id => $text)
949
			$date_select .= '
950
			<option value="' . $id . '"' . ($current_date == $id ? ' selected' : '') . '>' . $text . '</option>';
951
952
		$date_select .= '
953
		</select>
954
		<noscript>
955
			<input type="submit" name="go" value="' . $txt['go'] . '" class="button">
956
		</noscript>';
957
	}
958
959
	// If we manually jumped to a date work out the offset.
960
	if (isset($_REQUEST['new_date']))
961
	{
962
		$date_query = sprintf('%04d-%02d-01', substr($current_date, 0, 4), substr($current_date, 4));
963
964
		$request = $smcFunc['db_query']('', '
965
			SELECT COUNT(*) AS offset
966
			FROM {db_prefix}log_spider_stats
967
			WHERE stat_date < {date:date_being_viewed}',
968
			array(
969
				'date_being_viewed' => $date_query,
970
			)
971
		);
972
		list ($_REQUEST['start']) = $smcFunc['db_fetch_row']($request);
973
		$smcFunc['db_free_result']($request);
974
	}
975
976
	$listOptions = array(
977
		'id' => 'spider_stat_list',
978
		'title' => $txt['spider_stats'],
979
		'items_per_page' => $modSettings['defaultMaxListItems'],
980
		'base_href' => $scripturl . '?action=admin;area=sengines;sa=stats',
981
		'default_sort_col' => 'stat_date',
982
		'get_items' => array(
983
			'function' => 'list_getSpiderStats',
984
		),
985
		'get_count' => array(
986
			'function' => 'list_getNumSpiderStats',
987
		),
988
		'no_items_label' => $txt['spider_stats_no_entries'],
989
		'columns' => array(
990
			'stat_date' => array(
991
				'header' => array(
992
					'value' => $txt['date'],
993
				),
994
				'data' => array(
995
					'db' => 'stat_date',
996
				),
997
				'sort' => array(
998
					'default' => 'stat_date',
999
					'reverse' => 'stat_date DESC',
1000
				),
1001
			),
1002
			'name' => array(
1003
				'header' => array(
1004
					'value' => $txt['spider_name'],
1005
				),
1006
				'data' => array(
1007
					'db' => 'spider_name',
1008
				),
1009
				'sort' => array(
1010
					'default' => 's.spider_name',
1011
					'reverse' => 's.spider_name DESC',
1012
				),
1013
			),
1014
			'page_hits' => array(
1015
				'header' => array(
1016
					'value' => $txt['spider_stats_page_hits'],
1017
				),
1018
				'data' => array(
1019
					'db' => 'page_hits',
1020
				),
1021
				'sort' => array(
1022
					'default' => 'ss.page_hits',
1023
					'reverse' => 'ss.page_hits DESC',
1024
				),
1025
			),
1026
		),
1027
		'form' => array(
1028
			'href' => $scripturl . '?action=admin;area=sengines;sa=stats',
1029
			'name' => 'spider_stat_list',
1030
		),
1031
		'additional_rows' => empty($date_select) ? array() : array(
1032
			array(
1033
				'position' => 'below_table_data',
1034
				'value' => $date_select,
1035
				'style' => 'text-align: right;',
1036
			),
1037
		),
1038
	);
1039
1040
	createToken('admin-ss');
1041
1042
	require_once($sourcedir . '/Subs-List.php');
1043
	createList($listOptions);
1044
1045
	$context['sub_template'] = 'show_spider_stats';
1046
	$context['default_list'] = 'spider_stat_list';
1047
}
1048
1049
/**
1050
 * Callback function for createList()
1051
 * Get a list of spider stats from the log_spider table
1052
 *
1053
 * @param int $start The item to start with (for pagination purposes)
1054
 * @param int $items_per_page The number of items to show per page
1055
 * @param string $sort A string indicating how to sort the results
1056
 * @return array An array of spider statistics info
1057
 */
1058
function list_getSpiderStats($start, $items_per_page, $sort)
1059
{
1060
	global $smcFunc;
1061
1062
	$request = $smcFunc['db_query']('', '
1063
		SELECT ss.id_spider, ss.stat_date, ss.page_hits, s.spider_name
1064
		FROM {db_prefix}log_spider_stats AS ss
1065
			INNER JOIN {db_prefix}spiders AS s ON (s.id_spider = ss.id_spider)
1066
		ORDER BY {raw:sort}
1067
		LIMIT {int:start}, {int:items}',
1068
		array(
1069
			'sort' => $sort,
1070
			'start' => $start,
1071
			'items' => $items_per_page,
1072
		)
1073
	);
1074
	$spider_stats = array();
1075
	while ($row = $smcFunc['db_fetch_assoc']($request))
1076
		$spider_stats[] = $row;
1077
	$smcFunc['db_free_result']($request);
1078
1079
	return $spider_stats;
1080
}
1081
1082
/**
1083
 * Callback function for createList()
1084
 * Get the number of spider stat rows from the log spider stats table
1085
 *
1086
 * @return int The number of rows in the log_spider_stats table
1087
 */
1088
function list_getNumSpiderStats()
1089
{
1090
	global $smcFunc;
1091
1092
	$request = $smcFunc['db_query']('', '
1093
		SELECT COUNT(*) AS num_stats
1094
		FROM {db_prefix}log_spider_stats',
1095
		array(
1096
		)
1097
	);
1098
	list ($numStats) = $smcFunc['db_fetch_row']($request);
1099
	$smcFunc['db_free_result']($request);
1100
1101
	return $numStats;
1102
}
1103
1104
/**
1105
 * Recache spider names?
1106
 */
1107
function recacheSpiderNames()
1108
{
1109
	global $smcFunc;
1110
1111
	$request = $smcFunc['db_query']('', '
1112
		SELECT id_spider, spider_name
1113
		FROM {db_prefix}spiders',
1114
		array()
1115
	);
1116
	$spiders = array();
1117
	while ($row = $smcFunc['db_fetch_assoc']($request))
1118
		$spiders[$row['id_spider']] = $row['spider_name'];
1119
	$smcFunc['db_free_result']($request);
1120
1121
	updateSettings(array('spider_name_cache' => $smcFunc['json_encode']($spiders)));
1122
}
1123
1124
?>