Completed
Push — release-2.1 ( 5876a2...f30e04 )
by Mert
06:50
created

ManageErrors.php ➔ ViewErrorLog()   F

Complexity

Conditions 49
Paths > 20000

Size

Total Lines 263
Code Lines 149

Duplication

Lines 2
Ratio 0.76 %
Metric Value
cc 49
eloc 149
nc 429496.7295
nop 0
dl 2
loc 263
rs 2

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
 * The main purpose of this file is to show a list of all errors that were
5
 * logged on the forum, and allow filtering and deleting them.
6
 *
7
 * Simple Machines Forum (SMF)
8
 *
9
 * @package SMF
10
 * @author Simple Machines http://www.simplemachines.org
11
 * @copyright 2016 Simple Machines and individual contributors
12
 * @license http://www.simplemachines.org/about/smf/license.php BSD
13
 *
14
 * @version 2.1 Beta 3
15
 */
16
17
if (!defined('SMF'))
18
	die('No direct access...');
19
20
/**
21
 * View the forum's error log.
22
 * This function sets all the context up to show the error log for maintenance.
23
 * It requires the maintain_forum permission.
24
 * It is accessed from ?action=admin;area=logs;sa=errorlog.
25
 *
26
 * @uses the Errors template and error_log sub template.
27
 */
28
function ViewErrorLog()
29
{
30
	global $scripturl, $txt, $context, $modSettings, $user_profile, $filter, $smcFunc;
31
32
	// Viewing contents of a file?
33
	if (isset($_GET['file']))
34
		return ViewFile();
35
36
	// Check for the administrative permission to do this.
37
	isAllowedTo('admin_forum');
38
39
	// Templates, etc...
40
	loadLanguage('ManageMaintenance');
41
	loadTemplate('Errors');
42
43
	// You can filter by any of the following columns:
44
	$filters = array(
45
		'id_member' => $txt['username'],
46
		'ip' => $txt['ip_address'],
47
		'session' => $txt['session'],
48
		'url' => $txt['error_url'],
49
		'message' => $txt['error_message'],
50
		'error_type' => $txt['error_type'],
51
		'file' => $txt['file'],
52
		'line' => $txt['line'],
53
	);
54
55
	// Set up the filtering...
56
	if (isset($_GET['value'], $_GET['filter']) && isset($filters[$_GET['filter']]))
57
		$filter = array(
58
			'variable' => $_GET['filter'],
59
			'value' => array(
60
				'sql' => in_array($_GET['filter'], array('message', 'url', 'file')) ? base64_decode(strtr($_GET['value'], array(' ' => '+'))) : $smcFunc['db_escape_wildcard_string']($_GET['value']),
61
			),
62
			'href' => ';filter=' . $_GET['filter'] . ';value=' . $_GET['value'],
63
			'entity' => $filters[$_GET['filter']]
64
		);
65
66
	// Deleting, are we?
67
	if (isset($_POST['delall']) || isset($_POST['delete']))
68
		deleteErrors();
69
70
	// Just how many errors are there?
71
	$result = $smcFunc['db_query']('', '
72
		SELECT COUNT(*)
73
		FROM {db_prefix}log_errors' . (isset($filter) ? '
74
		WHERE ' . $filter['variable'] . ' LIKE {string:filter}' : ''),
75
		array(
76
			'filter' => isset($filter) ? $filter['value']['sql'] : '',
77
		)
78
	);
79
	list ($num_errors) = $smcFunc['db_fetch_row']($result);
80
	$smcFunc['db_free_result']($result);
81
82
	// If this filter is empty...
83
	if ($num_errors == 0 && isset($filter))
84
		redirectexit('action=admin;area=logs;sa=errorlog' . (isset($_REQUEST['desc']) ? ';desc' : ''));
85
86
	// Clean up start.
87 View Code Duplication
	if (!isset($_GET['start']) || $_GET['start'] < 0)
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
88
		$_GET['start'] = 0;
89
90
	// Do we want to reverse error listing?
91
	$context['sort_direction'] = isset($_REQUEST['desc']) ? 'down' : 'up';
92
93
	// Set the page listing up.
94
	$context['page_index'] = constructPageIndex($scripturl . '?action=admin;area=logs;sa=errorlog' . ($context['sort_direction'] == 'down' ? ';desc' : '') . (isset($filter) ? $filter['href'] : ''), $_GET['start'], $num_errors, $modSettings['defaultMaxListItems']);
95
	$context['start'] = $_GET['start'];
96
97
	// Update the error count
98
	if (!isset($filter))
99
		$context['num_errors'] = $num_errors;
100
	else
101
	{
102
		// We want all errors, not just the number of filtered messages...
103
		$query = $smcFunc['db_query']('', '
104
			SELECT COUNT(id_error)
105
			FROM {db_prefix}log_errors',
106
			array()
107
		);
108
109
		list($context['num_errors']) = $smcFunc['db_fetch_row']($query);
110
		$smcFunc['db_free_result']($query);
111
	}
112
113
	// Find and sort out the errors.
114
	$request = $smcFunc['db_query']('', '
115
		SELECT id_error, id_member, ip, url, log_time, message, session, error_type, file, line
116
		FROM {db_prefix}log_errors' . (isset($filter) ? '
117
		WHERE ' . $filter['variable'] . ' LIKE {string:filter}' : '') . '
118
		ORDER BY id_error ' . ($context['sort_direction'] == 'down' ? 'DESC' : '') . '
119
		LIMIT {int:start}, {int:max}',
120
		array(
121
			'filter' => isset($filter) ? $filter['value']['sql'] : '',
122
			'start' => $_GET['start'],
123
			'max' => $modSettings['defaultMaxListItems'],
124
		)
125
	);
126
	$context['errors'] = array();
127
	$members = array();
128
129
	for ($i = 0; $row = $smcFunc['db_fetch_assoc']($request); $i ++)
130
	{
131
		$search_message = preg_replace('~&lt;span class=&quot;remove&quot;&gt;(.+?)&lt;/span&gt;~', '%', $smcFunc['db_escape_wildcard_string']($row['message']));
132
		if ($search_message == $filter['value']['sql'])
133
			$search_message = $smcFunc['db_escape_wildcard_string']($row['message']);
134
		$show_message = strtr(strtr(preg_replace('~&lt;span class=&quot;remove&quot;&gt;(.+?)&lt;/span&gt;~', '$1', $row['message']), array("\r" => '', '<br>' => "\n", '<' => '&lt;', '>' => '&gt;', '"' => '&quot;')), array("\n" => '<br>'));
135
136
		$context['errors'][$row['id_error']] = array(
137
			'member' => array(
138
				'id' => $row['id_member'],
139
				'ip' => inet_dtop($row['ip']),
140
				'session' => $row['session']
141
			),
142
			'time' => timeformat($row['log_time']),
143
			'timestamp' => $row['log_time'],
144
			'url' => array(
145
				'html' => $smcFunc['htmlspecialchars'](strpos($row['url'], 'cron.php') === false ? (substr($row['url'], 0, 1) == '?' ? $scripturl : '') . $row['url'] : $row['url']),
146
				'href' => base64_encode($smcFunc['db_escape_wildcard_string']($row['url']))
147
			),
148
			'message' => array(
149
				'html' => $show_message,
150
				'href' => base64_encode($search_message)
151
			),
152
			'id' => $row['id_error'],
153
			'error_type' => array(
154
				'type' => $row['error_type'],
155
				'name' => isset($txt['errortype_'.$row['error_type']]) ? $txt['errortype_'.$row['error_type']] : $row['error_type'],
156
			),
157
			'file' => array(),
158
		);
159
		if (!empty($row['file']) && !empty($row['line']))
160
		{
161
			// Eval'd files rarely point to the right location and cause havoc for linking, so don't link them.
162
			$linkfile = strpos($row['file'], 'eval') === false || strpos($row['file'], '?') === false; // De Morgan's Law.  Want this true unless both are present.
163
164
			$context['errors'][$row['id_error']]['file'] = array(
165
				'file' => $row['file'],
166
				'line' => $row['line'],
167
				'href' => $scripturl . '?action=admin;area=logs;sa=errorlog;file=' . base64_encode($row['file']) . ';line=' . $row['line'],
168
				'link' => $linkfile ? '<a href="' . $scripturl . '?action=admin;area=logs;sa=errorlog;file=' . base64_encode($row['file']) . ';line=' . $row['line'] . '" onclick="return reqWin(this.href, 600, 480, false);">' . $row['file'] . '</a>' : $row['file'],
169
				'search' => base64_encode($row['file']),
170
			);
171
		}
172
173
		// Make a list of members to load later.
174
		$members[$row['id_member']] = $row['id_member'];
175
	}
176
	$smcFunc['db_free_result']($request);
177
178
	// Load the member data.
179
	if (!empty($members))
180
	{
181
		// Get some additional member info...
182
		$request = $smcFunc['db_query']('', '
183
			SELECT id_member, member_name, real_name
184
			FROM {db_prefix}members
185
			WHERE id_member IN ({array_int:member_list})
186
			LIMIT {int:members}',
187
			array(
188
				'member_list' => $members,
189
				'members' => count($members),
190
			)
191
		);
192
		while ($row = $smcFunc['db_fetch_assoc']($request))
193
			$members[$row['id_member']] = $row;
194
		$smcFunc['db_free_result']($request);
195
196
		// This is a guest...
197
		$members[0] = array(
198
			'id_member' => 0,
199
			'member_name' => '',
200
			'real_name' => $txt['guest_title']
201
		);
202
203
		// Go through each error and tack the data on.
204
		foreach ($context['errors'] as $id => $dummy)
205
		{
206
			$memID = $context['errors'][$id]['member']['id'];
207
			$context['errors'][$id]['member']['username'] = $members[$memID]['member_name'];
208
			$context['errors'][$id]['member']['name'] = $members[$memID]['real_name'];
209
			$context['errors'][$id]['member']['href'] = empty($memID) ? '' : $scripturl . '?action=profile;u=' . $memID;
210
			$context['errors'][$id]['member']['link'] = empty($memID) ? $txt['guest_title'] : '<a href="' . $scripturl . '?action=profile;u=' . $memID . '">' . $context['errors'][$id]['member']['name'] . '</a>';
211
		}
212
	}
213
214
	// Filtering anything?
215
	if (isset($filter))
216
	{
217
		$context['filter'] = &$filter;
218
219
		// Set the filtering context.
220
		if ($filter['variable'] == 'id_member')
221
		{
222
			$id = $filter['value']['sql'];
223
			loadMemberData($id, false, 'minimal');
224
			$context['filter']['value']['html'] = '<a href="' . $scripturl . '?action=profile;u=' . $id . '">' . $user_profile[$id]['real_name'] . '</a>';
225
		}
226
		elseif ($filter['variable'] == 'url')
227
			$context['filter']['value']['html'] = '\'' . strtr($smcFunc['htmlspecialchars']((substr($filter['value']['sql'], 0, 1) == '?' ? $scripturl : '') . $filter['value']['sql']), array('\_' => '_')) . '\'';
228
		elseif ($filter['variable'] == 'message')
229
		{
230
			$context['filter']['value']['html'] = '\'' . strtr($smcFunc['htmlspecialchars']($filter['value']['sql']), array("\n" => '<br>', '&lt;br /&gt;' => '<br>', "\t" => '&nbsp;&nbsp;&nbsp;', '\_' => '_', '\\%' => '%', '\\\\' => '\\')) . '\'';
231
			$context['filter']['value']['html'] = preg_replace('~&amp;lt;span class=&amp;quot;remove&amp;quot;&amp;gt;(.+?)&amp;lt;/span&amp;gt;~', '$1', $context['filter']['value']['html']);
232
		}
233
		elseif ($filter['variable'] == 'error_type')
234
		{
235
			$context['filter']['value']['html'] = '\'' . strtr($smcFunc['htmlspecialchars']($filter['value']['sql']), array("\n" => '<br>', '&lt;br /&gt;' => '<br>', "\t" => '&nbsp;&nbsp;&nbsp;', '\_' => '_', '\\%' => '%', '\\\\' => '\\')) . '\'';
236
		}
237
		else
238
			$context['filter']['value']['html'] = &$filter['value']['sql'];
239
	}
240
241
	$context['error_types'] = array();
242
243
	$context['error_types']['all'] = array(
244
		'label' => $txt['errortype_all'],
245
		'description' => isset($txt['errortype_all_desc']) ? $txt['errortype_all_desc'] : '',
246
		'url' => $scripturl . '?action=admin;area=logs;sa=errorlog' . ($context['sort_direction'] == 'down' ? ';desc' : ''),
247
		'is_selected' => empty($filter),
248
	);
249
250
	$sum = 0;
251
	// What type of errors do we have and how many do we have?
252
	$request = $smcFunc['db_query']('', '
253
		SELECT error_type, COUNT(*) AS num_errors
254
		FROM {db_prefix}log_errors
255
		GROUP BY error_type
256
		ORDER BY error_type = {string:critical_type} DESC, error_type ASC',
257
		array(
258
			'critical_type' => 'critical',
259
		)
260
	);
261
	while ($row = $smcFunc['db_fetch_assoc']($request))
262
	{
263
		// Total errors so far?
264
		$sum += $row['num_errors'];
265
266
		$context['error_types'][$sum] = array(
267
			'label' => (isset($txt['errortype_' . $row['error_type']]) ? $txt['errortype_' . $row['error_type']] : $row['error_type']) . ' (' . $row['num_errors'] . ')',
268
			'description' => isset($txt['errortype_' . $row['error_type'] . '_desc']) ? $txt['errortype_' . $row['error_type'] . '_desc'] : '',
269
			'url' => $scripturl . '?action=admin;area=logs;sa=errorlog' . ($context['sort_direction'] == 'down' ? ';desc' : '') . ';filter=error_type;value=' . $row['error_type'],
270
			'is_selected' => isset($filter) && $filter['value']['sql'] == $smcFunc['db_escape_wildcard_string']($row['error_type']),
271
		);
272
	}
273
	$smcFunc['db_free_result']($request);
274
275
	// Update the all errors tab with the total number of errors
276
	$context['error_types']['all']['label'] .= ' (' . $sum . ')';
277
278
	// Finally, work out what is the last tab!
279
	if (isset($context['error_types'][$sum]))
280
		$context['error_types'][$sum]['is_last'] = true;
281
	else
282
		$context['error_types']['all']['is_last'] = true;
283
284
	// And this is pretty basic ;).
285
	$context['page_title'] = $txt['errlog'];
286
	$context['has_filter'] = isset($filter);
287
	$context['sub_template'] = 'error_log';
288
289
	createToken('admin-el');
290
}
291
292
/**
293
 * Delete all or some of the errors in the error log.
294
 * It applies any necessary filters to deletion.
295
 * This should only be called by ViewErrorLog().
296
 * It attempts to TRUNCATE the table to reset the auto_increment.
297
 * Redirects back to the error log when done.
298
 */
299
function deleteErrors()
300
{
301
	global $filter, $smcFunc;
302
303
	// Make sure the session exists and is correct; otherwise, might be a hacker.
304
	checkSession();
305
	validateToken('admin-el');
306
307
	// Delete all or just some?
308
	if (isset($_POST['delall']) && !isset($filter))
309
		$smcFunc['db_query']('truncate_table', '
310
			TRUNCATE {db_prefix}log_errors',
311
			array(
312
			)
313
		);
314
	// Deleting all with a filter?
315
	elseif (isset($_POST['delall']) && isset($filter))
316
		$smcFunc['db_query']('', '
317
			DELETE FROM {db_prefix}log_errors
318
			WHERE ' . $filter['variable'] . ' LIKE {string:filter}',
319
			array(
320
				'filter' => $filter['value']['sql'],
321
			)
322
		);
323
	// Just specific errors?
324
	elseif (!empty($_POST['delete']))
325
	{
326
		$smcFunc['db_query']('', '
327
			DELETE FROM {db_prefix}log_errors
328
			WHERE id_error IN ({array_int:error_list})',
329
			array(
330
				'error_list' => array_unique($_POST['delete']),
331
			)
332
		);
333
334
		// Go back to where we were.
335
		redirectexit('action=admin;area=logs;sa=errorlog' . (isset($_REQUEST['desc']) ? ';desc' : '') . ';start=' . $_GET['start'] . (isset($filter) ? ';filter=' . $_GET['filter'] . ';value=' . $_GET['value'] : ''));
336
	}
337
338
	// Back to the error log!
339
	redirectexit('action=admin;area=logs;sa=errorlog' . (isset($_REQUEST['desc']) ? ';desc' : ''));
340
}
341
342
/**
343
 * View a file specified in $_REQUEST['file'], with php highlighting on it
344
 * Preconditions:
345
 *  - file must be readable,
346
 *  - full file path must be base64 encoded,
347
 *  - user must have admin_forum permission.
348
 * The line number number is specified by $_REQUEST['line']...
349
 * The function will try to get the 20 lines before and after the specified line.
350
 */
351
function ViewFile()
352
{
353
	global $context, $boarddir, $sourcedir, $cachedir, $smcFunc;
354
355
	// Check for the administrative permission to do this.
356
	isAllowedTo('admin_forum');
357
358
	// Decode the file and get the line
359
	$file = realpath(base64_decode($_REQUEST['file']));
360
	$real_board = realpath($boarddir);
361
	$real_source = realpath($sourcedir);
362
	$real_cache = realpath($cachedir);
363
	$basename = strtolower(basename($file));
364
	$ext = strrchr($basename, '.');
365
	$line = isset($_REQUEST['line']) ? (int) $_REQUEST['line'] : 0;
366
367
	// Make sure the file we are looking for is one they are allowed to look at
368
	if ($ext != '.php' || (strpos($file, $real_board) === false && strpos($file, $real_source) === false) || ($basename == 'settings.php' || $basename == 'settings_bak.php') || strpos($file, $real_cache) !== false || !is_readable($file))
369
		fatal_lang_error('error_bad_file', true, array($smcFunc['htmlspecialchars']($file)));
0 ignored issues
show
Documentation introduced by
true is of type boolean, but the function expects a string.

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...
370
371
	// get the min and max lines
372
	$min = $line - 20 <= 0 ? 1 : $line - 20;
373
	$max = $line + 21; // One additional line to make everything work out correctly
374
375
	if ($max <= 0 || $min >= $max)
376
		fatal_lang_error('error_bad_line');
377
378
	$file_data = explode('<br />', highlight_php_code($smcFunc['htmlspecialchars'](implode('', file($file)))));
379
380
	// We don't want to slice off too many so lets make sure we stop at the last one
381
	$max = min($max, max(array_keys($file_data)));
382
383
	$file_data = array_slice($file_data, $min-1, $max - $min);
384
385
	$context['file_data'] = array(
386
		'contents' => $file_data,
387
		'min' => $min,
388
		'target' => $line,
389
		'file' => strtr($file, array('"' => '\\"')),
390
	);
391
392
	loadTemplate('Errors');
393
	$context['template_layers'] = array();
394
	$context['sub_template'] = 'show_file';
395
396
}
397
398
?>
0 ignored issues
show
Best Practice introduced by
It is not recommended to use PHP's closing tag ?> in files other than templates.

Using a closing tag in PHP files that only contain PHP code is not recommended as you might accidentally add whitespace after the closing tag which would then be output by PHP. This can cause severe problems, for example headers cannot be sent anymore.

A simple precaution is to leave off the closing tag as it is not required, and it also has no negative effects whatsoever.

Loading history...