Completed
Push — release-2.1 ( e1799a...e3cf37 )
by
unknown
08:22
created

QueryString.php ➔ matchIPtoCIDR()   C

Complexity

Conditions 8
Paths 7

Size

Total Lines 34
Code Lines 25

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 8
eloc 25
nc 7
nop 2
dl 0
loc 34
rs 5.3846
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * This file does a lot of important stuff.  Mainly, this means it handles
5
 * the query string, request variables, and session management.
6
 *
7
 * Simple Machines Forum (SMF)
8
 *
9
 * @package SMF
10
 * @author Simple Machines http://www.simplemachines.org
11
 * @copyright 2018 Simple Machines and individual contributors
12
 * @license http://www.simplemachines.org/about/smf/license.php BSD
13
 *
14
 * @version 2.1 Beta 4
15
 */
16
17
if (!defined('SMF'))
18
	die('No direct access...');
19
20
/**
21
 * Clean the request variables - add html entities to GET and slashes if magic_quotes_gpc is Off.
22
 *
23
 * What it does:
24
 * - cleans the request variables (ENV, GET, POST, COOKIE, SERVER) and
25
 * - makes sure the query string was parsed correctly.
26
 * - handles the URLs passed by the queryless URLs option.
27
 * - makes sure, regardless of php.ini, everything has slashes.
28
 * - sets up $board, $topic, and $scripturl and $_REQUEST['start'].
29
 * - determines, or rather tries to determine, the client's IP.
30
 */
31
32
function cleanRequest()
33
{
34
	global $board, $topic, $boardurl, $scripturl, $modSettings, $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...
35
36
	// Makes it easier to refer to things this way.
37
	$scripturl = $boardurl . '/index.php';
38
39
	// What function to use to reverse magic quotes - if sybase is on we assume that the database sensibly has the right unescape function!
40
	$removeMagicQuoteFunction = ini_get('magic_quotes_sybase') || strtolower(ini_get('magic_quotes_sybase')) == 'on' ? 'unescapestring__recursive' : 'stripslashes__recursive';
41
42
	// Save some memory.. (since we don't use these anyway.)
43
	unset($GLOBALS['HTTP_POST_VARS'], $GLOBALS['HTTP_POST_VARS']);
44
	unset($GLOBALS['HTTP_POST_FILES'], $GLOBALS['HTTP_POST_FILES']);
45
46
	// These keys shouldn't be set...ever.
47
	if (isset($_REQUEST['GLOBALS']) || isset($_COOKIE['GLOBALS']))
48
		die('Invalid request variable.');
49
50
	// Same goes for numeric keys.
51
	foreach (array_merge(array_keys($_POST), array_keys($_GET), array_keys($_FILES)) as $key)
52
		if (is_numeric($key))
53
			die('Numeric request keys are invalid.');
54
55
	// Numeric keys in cookies are less of a problem. Just unset those.
56
	foreach ($_COOKIE as $key => $value)
57
		if (is_numeric($key))
58
			unset($_COOKIE[$key]);
59
60
	// Get the correct query string.  It may be in an environment variable...
61
	if (!isset($_SERVER['QUERY_STRING']))
62
		$_SERVER['QUERY_STRING'] = getenv('QUERY_STRING');
63
64
	// It seems that sticking a URL after the query string is mighty common, well, it's evil - don't.
65
	if (strpos($_SERVER['QUERY_STRING'], 'http') === 0)
66
	{
67
		header('HTTP/1.1 400 Bad Request');
68
		die;
69
	}
70
71
	// Are we going to need to parse the ; out?
72
	if (strpos(ini_get('arg_separator.input'), ';') === false && !empty($_SERVER['QUERY_STRING']))
73
	{
74
		// Get rid of the old one! You don't know where it's been!
75
		$_GET = array();
76
77
		// Was this redirected? If so, get the REDIRECT_QUERY_STRING.
78
		// Do not urldecode() the querystring.
79
		$_SERVER['QUERY_STRING'] = substr($_SERVER['QUERY_STRING'], 0, 5) === 'url=/' ? $_SERVER['REDIRECT_QUERY_STRING'] : $_SERVER['QUERY_STRING'];
80
81
		// Replace ';' with '&' and '&something&' with '&something=&'.  (this is done for compatibility...)
82
		// @todo smflib
0 ignored issues
show
Coding Style Best Practice introduced by
Comments for TODO tasks are often forgotten in the code; it might be better to use a dedicated issue tracker.
Loading history...
83
		parse_str(preg_replace('/&(\w+)(?=&|$)/', '&$1=', strtr($_SERVER['QUERY_STRING'], array(';?' => '&', ';' => '&', '%00' => '', "\0" => ''))), $_GET);
84
85
		// Magic quotes still applies with parse_str - so clean it up.
86 View Code Duplication
		if (function_exists('get_magic_quotes_gpc') && @get_magic_quotes_gpc() != 0 && empty($modSettings['integrate_magic_quotes']))
87
			$_GET = $removeMagicQuoteFunction($_GET);
88
	}
89
	elseif (strpos(ini_get('arg_separator.input'), ';') !== false)
90
	{
91 View Code Duplication
		if (function_exists('get_magic_quotes_gpc') && @get_magic_quotes_gpc() != 0 && empty($modSettings['integrate_magic_quotes']))
92
			$_GET = $removeMagicQuoteFunction($_GET);
93
94
		// Search engines will send action=profile%3Bu=1, which confuses PHP.
95
		foreach ($_GET as $k => $v)
96
		{
97
			if ((string) $v === $v && strpos($k, ';') !== false)
98
			{
99
				$temp = explode(';', $v);
100
				$_GET[$k] = $temp[0];
101
102
				for ($i = 1, $n = count($temp); $i < $n; $i++)
103
				{
104
					@list ($key, $val) = @explode('=', $temp[$i], 2);
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...
105
					if (!isset($_GET[$key]))
106
						$_GET[$key] = $val;
107
				}
108
			}
109
110
			// This helps a lot with integration!
111
			if (strpos($k, '?') === 0)
112
			{
113
				$_GET[substr($k, 1)] = $v;
114
				unset($_GET[$k]);
115
			}
116
		}
117
	}
118
119
	// There's no query string, but there is a URL... try to get the data from there.
120
	if (!empty($_SERVER['REQUEST_URI']))
121
	{
122
		// Remove the .html, assuming there is one.
123
		if (substr($_SERVER['REQUEST_URI'], strrpos($_SERVER['REQUEST_URI'], '.'), 4) == '.htm')
124
			$request = substr($_SERVER['REQUEST_URI'], 0, strrpos($_SERVER['REQUEST_URI'], '.'));
125
		else
126
			$request = $_SERVER['REQUEST_URI'];
127
128
		// @todo smflib.
0 ignored issues
show
Coding Style Best Practice introduced by
Comments for TODO tasks are often forgotten in the code; it might be better to use a dedicated issue tracker.
Loading history...
129
		// Replace 'index.php/a,b,c/d/e,f' with 'a=b,c&d=&e=f' and parse it into $_GET.
130
		if (strpos($request, basename($scripturl) . '/') !== false)
131
		{
132
			parse_str(substr(preg_replace('/&(\w+)(?=&|$)/', '&$1=', strtr(preg_replace('~/([^,/]+),~', '/$1=', substr($request, strpos($request, basename($scripturl)) + strlen(basename($scripturl)))), '/', '&')), 1), $temp);
133 View Code Duplication
			if (function_exists('get_magic_quotes_gpc') && @get_magic_quotes_gpc() != 0 && empty($modSettings['integrate_magic_quotes']))
134
				$temp = $removeMagicQuoteFunction($temp);
135
			$_GET += $temp;
136
		}
137
	}
138
139
	// If magic quotes is on we have some work...
140
	if (function_exists('get_magic_quotes_gpc') && @get_magic_quotes_gpc() != 0)
141
	{
142
		$_ENV = $removeMagicQuoteFunction($_ENV);
143
		$_POST = $removeMagicQuoteFunction($_POST);
144
		$_COOKIE = $removeMagicQuoteFunction($_COOKIE);
145
		foreach ($_FILES as $k => $dummy)
146
			if (isset($_FILES[$k]['name']))
147
				$_FILES[$k]['name'] = $removeMagicQuoteFunction($_FILES[$k]['name']);
148
	}
149
150
	// Add entities to GET.  This is kinda like the slashes on everything else.
151
	$_GET = htmlspecialchars__recursive($_GET);
152
153
	// Let's not depend on the ini settings... why even have COOKIE in there, anyway?
154
	$_REQUEST = $_POST + $_GET;
155
156
	// Make sure $board and $topic are numbers.
157
	if (isset($_REQUEST['board']))
158
	{
159
		// Make sure its a string and not something else like an array
160
		$_REQUEST['board'] = (string) $_REQUEST['board'];
161
162
		// If there's a slash in it, we've got a start value! (old, compatible links.)
163
		if (strpos($_REQUEST['board'], '/') !== false)
164
			list ($_REQUEST['board'], $_REQUEST['start']) = explode('/', $_REQUEST['board']);
165
		// Same idea, but dots.  This is the currently used format - ?board=1.0...
166
		elseif (strpos($_REQUEST['board'], '.') !== false)
167
			list ($_REQUEST['board'], $_REQUEST['start']) = explode('.', $_REQUEST['board']);
168
		// Now make absolutely sure it's a number.
169
		$board = (int) $_REQUEST['board'];
170
		$_REQUEST['start'] = isset($_REQUEST['start']) ? (int) $_REQUEST['start'] : 0;
171
172
		// This is for "Who's Online" because it might come via POST - and it should be an int here.
173
		$_GET['board'] = $board;
174
	}
175
	// Well, $board is going to be a number no matter what.
176
	else
177
		$board = 0;
178
179
	// If there's a threadid, it's probably an old YaBB SE link.  Flow with it.
180
	if (isset($_REQUEST['threadid']) && !isset($_REQUEST['topic']))
181
		$_REQUEST['topic'] = $_REQUEST['threadid'];
182
183
	// We've got topic!
184
	if (isset($_REQUEST['topic']))
185
	{
186
		// Make sure its a string and not something else like an array
187
		$_REQUEST['topic'] = (string) $_REQUEST['topic'];
188
189
		// Slash means old, beta style, formatting.  That's okay though, the link should still work.
190
		if (strpos($_REQUEST['topic'], '/') !== false)
191
			list ($_REQUEST['topic'], $_REQUEST['start']) = explode('/', $_REQUEST['topic']);
192
		// Dots are useful and fun ;).  This is ?topic=1.15.
193
		elseif (strpos($_REQUEST['topic'], '.') !== false)
194
			list ($_REQUEST['topic'], $_REQUEST['start']) = explode('.', $_REQUEST['topic']);
195
196
		// Topic should always be an integer
197
		$topic = $_GET['topic'] = $_REQUEST['topic'] = (int) $_REQUEST['topic'];
198
199
		// Start could be a lot of things...
200
		// ... empty ...
0 ignored issues
show
Unused Code Comprehensibility introduced by
50% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
201
		if (empty($_REQUEST['start']))
202
		{
203
			$_REQUEST['start'] = 0;
204
		}
205
		// ... a simple number ...
206
		elseif (is_numeric($_REQUEST['start']))
207
		{
208
			$_REQUEST['start'] = (int) $_REQUEST['start'];
209
		}
210
		// ... or a specific message ...
211 View Code Duplication
		elseif (strpos($_REQUEST['start'], 'msg') === 0)
212
		{
213
			$virtual_msg = (int) substr($_REQUEST['start'], 3);
214
			$_REQUEST['start'] = $virtual_msg === 0 ? 0 : 'msg' . $virtual_msg;
215
		}
216
		// ... or whatever is new ...
217
		elseif (strpos($_REQUEST['start'], 'new') === 0)
218
		{
219
			$_REQUEST['start'] = 'new';
220
		}
221
		// ... or since a certain time ...
222 View Code Duplication
		elseif (strpos($_REQUEST['start'], 'from') === 0)
223
		{
224
			$timestamp = (int) substr($_REQUEST['start'], 4);
225
			$_REQUEST['start'] = $timestamp === 0 ? 0 : 'from' . $timestamp;
226
		}
227
		// ... or something invalid, in which case we reset it to 0.
228
		else
229
			$_REQUEST['start'] = 0;
230
	}
231
	else
232
		$topic = 0;
233
234
	// There should be a $_REQUEST['start'], some at least.  If you need to default to other than 0, use $_GET['start'].
235
	if (empty($_REQUEST['start']) || $_REQUEST['start'] < 0 || (int) $_REQUEST['start'] > 2147473647)
236
		$_REQUEST['start'] = 0;
237
238
	// The action needs to be a string and not an array or anything else
239
	if (isset($_REQUEST['action']))
240
		$_REQUEST['action'] = (string) $_REQUEST['action'];
241
	if (isset($_GET['action']))
242
		$_GET['action'] = (string) $_GET['action'];
243
244
	// Some mail providers like to encode semicolons in activation URLs...
245
	if (!empty($_REQUEST['action']) && substr($_SERVER['QUERY_STRING'], 0, 18) == 'action=activate%3b')
246
	{
247
		header('location: ' . $scripturl . '?' . str_replace('%3b', ';', $_SERVER['QUERY_STRING']));
0 ignored issues
show
Security Response Splitting introduced by
'location: ' . $scriptur...SERVER['QUERY_STRING']) can contain request data and is used in response header context(s) leading to a potential security vulnerability.

1 path for user data to reach this point

  1. Fetching key QUERY_STRING from $_SERVER, and $_SERVER['QUERY_STRING'] is passed through str_replace()
    in Sources/QueryString.php on line 247

Response Splitting Attacks

Allowing an attacker to set a response header, opens your application to response splitting attacks; effectively allowing an attacker to send any response, he would like.

General Strategies to prevent injection

In general, it is advisable to prevent any user-data to reach this point. This can be done by white-listing certain values:

if ( ! in_array($value, array('this-is-allowed', 'and-this-too'), true)) {
    throw new \InvalidArgumentException('This input is not allowed.');
}

For numeric data, we recommend to explicitly cast the data:

$sanitized = (integer) $tainted;
Loading history...
248
		exit;
249
	}
250
251
	// Make sure we have a valid REMOTE_ADDR.
252
	if (!isset($_SERVER['REMOTE_ADDR']))
253
	{
254
		$_SERVER['REMOTE_ADDR'] = '';
255
		// A new magic variable to indicate we think this is command line.
256
		$_SERVER['is_cli'] = true;
257
	}
258
	// Perhaps we have a IPv6 address.
259
	elseif (isValidIP($_SERVER['REMOTE_ADDR']))
260
	{
261
		$_SERVER['REMOTE_ADDR'] = preg_replace('~^::ffff:(\d+\.\d+\.\d+\.\d+)~', '\1', $_SERVER['REMOTE_ADDR']);
262
	}
263
264
	// Try to calculate their most likely IP for those people behind proxies (And the like).
265
	$_SERVER['BAN_CHECK_IP'] = $_SERVER['REMOTE_ADDR'];
266
267
	// If we haven't specified how to handle Reverse Proxy IP headers, lets do what we always used to do.
268
	if (!isset($modSettings['proxy_ip_header']))
269
		$modSettings['proxy_ip_header'] = 'autodetect';
270
271
	// Which headers are we going to check for Reverse Proxy IP headers?
272
	if ($modSettings['proxy_ip_header'] == 'disabled')
273
		$reverseIPheaders = array();
274
	elseif ($modSettings['proxy_ip_header'] == 'autodetect')
275
		$reverseIPheaders = array('HTTP_X_FORWARDED_FOR', 'HTTP_CLIENT_IP');
276
	else
277
		$reverseIPheaders = array($modSettings['proxy_ip_header']);
278
279
	// Find the user's IP address. (but don't let it give you 'unknown'!)
280
	foreach ($reverseIPheaders as $proxyIPheader)
281
	{
282
		// Ignore if this is not set.
283
		if (!isset($_SERVER[$proxyIPheader]))
284
			continue;
285
286
		if (!empty($modSettings['proxy_ip_servers']))
287
		{
288
			foreach (explode(',', $modSettings['proxy_ip_servers']) as $proxy)
289
				if ($proxy == $_SERVER['REMOTE_ADDR'] || matchIPtoCIDR($_SERVER['REMOTE_ADDR'], $proxy))
290
					continue;
291
		}
292
293
		// If there are commas, get the last one.. probably.
294
		if (strpos($_SERVER[$proxyIPheader], ',') !== false)
295
		{
296
			$ips = array_reverse(explode(', ', $_SERVER[$proxyIPheader]));
297
298
			// Go through each IP...
299
			foreach ($ips as $i => $ip)
300
			{
301
				// Make sure it's in a valid range...
302
				if (preg_match('~^((0|10|172\.(1[6-9]|2[0-9]|3[01])|192\.168|255|127)\.|unknown|::1|fe80::|fc00::)~', $ip) != 0 && preg_match('~^((0|10|172\.(1[6-9]|2[0-9]|3[01])|192\.168|255|127)\.|unknown|::1|fe80::|fc00::)~', $_SERVER['REMOTE_ADDR']) == 0)
303
				{
304 View Code Duplication
					if (!isValidIPv6($_SERVER[$proxyIPheader]) || preg_match('~::ffff:\d+\.\d+\.\d+\.\d+~', $_SERVER[$proxyIPheader]) !== 0)
305
					{
306
						$_SERVER[$proxyIPheader] = preg_replace('~^::ffff:(\d+\.\d+\.\d+\.\d+)~', '\1', $_SERVER[$proxyIPheader]);
307
308
						// Just incase we have a legacy IPv4 address.
309
						// @ TODO: Convert to IPv6.
0 ignored issues
show
Coding Style Best Practice introduced by
Comments for TODO tasks are often forgotten in the code; it might be better to use a dedicated issue tracker.
Loading history...
310
						if (preg_match('~^((([1]?\d)?\d|2[0-4]\d|25[0-5])\.){3}(([1]?\d)?\d|2[0-4]\d|25[0-5])$~', $_SERVER[$proxyIPheader]) === 0)
311
							continue;
312
					}
313
314
					continue;
315
				}
316
317
				// Otherwise, we've got an IP!
318
				$_SERVER['BAN_CHECK_IP'] = trim($ip);
319
				break;
320
			}
321
		}
322
		// Otherwise just use the only one.
323
		elseif (preg_match('~^((0|10|172\.(1[6-9]|2[0-9]|3[01])|192\.168|255|127)\.|unknown|::1|fe80::|fc00::)~', $_SERVER[$proxyIPheader]) == 0 || preg_match('~^((0|10|172\.(1[6-9]|2[0-9]|3[01])|192\.168|255|127)\.|unknown|::1|fe80::|fc00::)~', $_SERVER['REMOTE_ADDR']) != 0)
324
			$_SERVER['BAN_CHECK_IP'] = $_SERVER[$proxyIPheader];
325 View Code Duplication
		elseif (!isValidIPv6($_SERVER[$proxyIPheader]) || preg_match('~::ffff:\d+\.\d+\.\d+\.\d+~', $_SERVER[$proxyIPheader]) !== 0)
326
		{
327
			$_SERVER[$proxyIPheader] = preg_replace('~^::ffff:(\d+\.\d+\.\d+\.\d+)~', '\1', $_SERVER[$proxyIPheader]);
328
329
			// Just incase we have a legacy IPv4 address.
330
			// @ TODO: Convert to IPv6.
0 ignored issues
show
Coding Style Best Practice introduced by
Comments for TODO tasks are often forgotten in the code; it might be better to use a dedicated issue tracker.
Loading history...
331
			if (preg_match('~^((([1]?\d)?\d|2[0-4]\d|25[0-5])\.){3}(([1]?\d)?\d|2[0-4]\d|25[0-5])$~', $_SERVER[$proxyIPheader]) === 0)
332
				continue;
333
		}
334
	}
335
336
	// Make sure we know the URL of the current request.
337
	if (empty($_SERVER['REQUEST_URI']))
338
		$_SERVER['REQUEST_URL'] = $scripturl . (!empty($_SERVER['QUERY_STRING']) ? '?' . $_SERVER['QUERY_STRING'] : '');
339
	elseif (preg_match('~^([^/]+//[^/]+)~', $scripturl, $match) == 1)
340
		$_SERVER['REQUEST_URL'] = $match[1] . $_SERVER['REQUEST_URI'];
341
	else
342
		$_SERVER['REQUEST_URL'] = $_SERVER['REQUEST_URI'];
343
344
	// And make sure HTTP_USER_AGENT is set.
345
	$_SERVER['HTTP_USER_AGENT'] = isset($_SERVER['HTTP_USER_AGENT']) ? (isset($smcFunc['htmlspecialchars']) ? $smcFunc['htmlspecialchars']($smcFunc['db_unescape_string']($_SERVER['HTTP_USER_AGENT']), ENT_QUOTES) : htmlspecialchars($smcFunc['db_unescape_string']($_SERVER['HTTP_USER_AGENT']), ENT_QUOTES)) : '';
346
347
	// Some final checking.
348
	if (!isValidIP($_SERVER['BAN_CHECK_IP']))
349
		$_SERVER['BAN_CHECK_IP'] = '';
350
	if ($_SERVER['REMOTE_ADDR'] == 'unknown')
351
		$_SERVER['REMOTE_ADDR'] = '';
352
}
353
354
/**
355
 * Validates a IPv6 address. returns true if it is ipv6.
356
 *
357
 * @param string $ip The ip address to be validated
358
 * @return boolean Whether the specified IP is a valid IPv6 address
359
 */
360
function isValidIPv6($ip)
0 ignored issues
show
Comprehensibility introduced by
Avoid variables with short names like $ip. 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...
361
{
362
	//looking for :
363
	if (strpos($ip, ':') === false)
364
		return false;
365
366
	//check valid address
367
	return filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6);
368
}
369
370
/**
371
 * Expands a IPv6 address to its full form.
372
 *
373
 * @param string $addr The IPv6 address
374
 * @param bool $strict_check Whether to check the length of the expanded address for compliance
375
 * @return string|bool The expanded IPv6 address or false if $strict_check is true and the result isn't valid
376
 */
377
function expandIPv6($addr, $strict_check = true)
378
{
379
	static $converted = array();
380
381
	// Check if we have done this already.
382
	if (isset($converted[$addr]))
383
		return $converted[$addr];
384
385
	// Check if there are segments missing, insert if necessary.
386
	if (strpos($addr, '::') !== false)
387
	{
388
		$part = explode('::', $addr);
389
		$part[0] = explode(':', $part[0]);
390
		$part[1] = explode(':', $part[1]);
391
		$missing = array();
392
393
		for ($i = 0; $i < (8 - (count($part[0]) + count($part[1]))); $i++)
394
			array_push($missing, '0000');
395
396
		$part = array_merge($part[0], $missing, $part[1]);
397
	}
398
	else
399
		$part = explode(':', $addr);
400
401
	// Pad each segment until it has 4 digits.
402
	foreach ($part as &$p)
403
		while (strlen($p) < 4)
404
			$p = '0' . $p;
405
406
	unset($p);
407
408
	// Join segments.
409
	$result = implode(':', $part);
410
411
	// Save this incase of repeated use.
412
	$converted[$addr] = $result;
413
414
	// Quick check to make sure the length is as expected.
415
	if (!$strict_check || strlen($result) == 39)
416
		return $result;
417
	else
418
		return false;
419
}
420
421
422
/**
423
 * Detect if a IP is in a CIDR address
424
 * - returns true or false
425
 *
426
 * @param string $ip_address IP address to check
427
 * @param string $cidr_address CIDR address to verify
428
 * @return bool Whether the IP matches the CIDR
429
*/
430
function matchIPtoCIDR($ip_address, $cidr_address)
431
{
432
    list ($cidr_network, $cidr_subnetmask) = preg_split('/', $cidr_address);
433
	
434
	//v6?
435
	if ((strpos($cidr_network, ':') !== false))
436
	{
437
		if (!filter_var($ip_address, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) || !filter_var($cidr_network, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6))
438
				return false;
439
440
		$ip_address = inet_pton($ip_address);
441
		$cidr_network = inet_pton($cidr_network);
442
		$binMask = str_repeat("f", $cidr_subnetmask / 4);
0 ignored issues
show
Coding Style Comprehensibility introduced by
The string literal f does not require double quotes, as per coding-style, please use single quotes.

PHP provides two ways to mark string literals. Either with single quotes 'literal' or with double quotes "literal". The difference between these is that string literals in double quotes may contain variables with are evaluated at run-time as well as escape sequences.

String literals in single quotes on the other hand are evaluated very literally and the only two characters that needs escaping in the literal are the single quote itself (\') and the backslash (\\). Every other character is displayed as is.

Double quoted string literals may contain other variables or more complex escape sequences.

<?php

$singleQuoted = 'Value';
$doubleQuoted = "\tSingle is $singleQuoted";

print $doubleQuoted;

will print an indented: Single is Value

If your string literal does not contain variables or escape sequences, it should be defined using single quotes to make that fact clear.

For more information on PHP string literals and available escape sequences see the PHP core documentation.

Loading history...
443
		switch ($cidr_subnetmask % 4) {
444
		  case 0:
445
			break;
446
		  case 1:
447
			$binMask .= "8";
0 ignored issues
show
Coding Style Comprehensibility introduced by
The string literal 8 does not require double quotes, as per coding-style, please use single quotes.

PHP provides two ways to mark string literals. Either with single quotes 'literal' or with double quotes "literal". The difference between these is that string literals in double quotes may contain variables with are evaluated at run-time as well as escape sequences.

String literals in single quotes on the other hand are evaluated very literally and the only two characters that needs escaping in the literal are the single quote itself (\') and the backslash (\\). Every other character is displayed as is.

Double quoted string literals may contain other variables or more complex escape sequences.

<?php

$singleQuoted = 'Value';
$doubleQuoted = "\tSingle is $singleQuoted";

print $doubleQuoted;

will print an indented: Single is Value

If your string literal does not contain variables or escape sequences, it should be defined using single quotes to make that fact clear.

For more information on PHP string literals and available escape sequences see the PHP core documentation.

Loading history...
448
			break;
449
		  case 2:
450
			$binMask .= "c";
0 ignored issues
show
Coding Style Comprehensibility introduced by
The string literal c does not require double quotes, as per coding-style, please use single quotes.

PHP provides two ways to mark string literals. Either with single quotes 'literal' or with double quotes "literal". The difference between these is that string literals in double quotes may contain variables with are evaluated at run-time as well as escape sequences.

String literals in single quotes on the other hand are evaluated very literally and the only two characters that needs escaping in the literal are the single quote itself (\') and the backslash (\\). Every other character is displayed as is.

Double quoted string literals may contain other variables or more complex escape sequences.

<?php

$singleQuoted = 'Value';
$doubleQuoted = "\tSingle is $singleQuoted";

print $doubleQuoted;

will print an indented: Single is Value

If your string literal does not contain variables or escape sequences, it should be defined using single quotes to make that fact clear.

For more information on PHP string literals and available escape sequences see the PHP core documentation.

Loading history...
451
			break;
452
		  case 3:
453
			$binMask .= "e";
0 ignored issues
show
Coding Style Comprehensibility introduced by
The string literal e does not require double quotes, as per coding-style, please use single quotes.

PHP provides two ways to mark string literals. Either with single quotes 'literal' or with double quotes "literal". The difference between these is that string literals in double quotes may contain variables with are evaluated at run-time as well as escape sequences.

String literals in single quotes on the other hand are evaluated very literally and the only two characters that needs escaping in the literal are the single quote itself (\') and the backslash (\\). Every other character is displayed as is.

Double quoted string literals may contain other variables or more complex escape sequences.

<?php

$singleQuoted = 'Value';
$doubleQuoted = "\tSingle is $singleQuoted";

print $doubleQuoted;

will print an indented: Single is Value

If your string literal does not contain variables or escape sequences, it should be defined using single quotes to make that fact clear.

For more information on PHP string literals and available escape sequences see the PHP core documentation.

Loading history...
454
			break;
455
		}
456
		$binMask = str_pad($binMask, 32, '0');
457
		$binMask = pack("H*" , $binMask);
0 ignored issues
show
Coding Style Comprehensibility introduced by
The string literal H* does not require double quotes, as per coding-style, please use single quotes.

PHP provides two ways to mark string literals. Either with single quotes 'literal' or with double quotes "literal". The difference between these is that string literals in double quotes may contain variables with are evaluated at run-time as well as escape sequences.

String literals in single quotes on the other hand are evaluated very literally and the only two characters that needs escaping in the literal are the single quote itself (\') and the backslash (\\). Every other character is displayed as is.

Double quoted string literals may contain other variables or more complex escape sequences.

<?php

$singleQuoted = 'Value';
$doubleQuoted = "\tSingle is $singleQuoted";

print $doubleQuoted;

will print an indented: Single is Value

If your string literal does not contain variables or escape sequences, it should be defined using single quotes to make that fact clear.

For more information on PHP string literals and available escape sequences see the PHP core documentation.

Loading history...
458
459
		return ($ip_address & $binMask) == $cidr_network;
460
	}
461
	else
462
		return (ip2long($ip_address) & (~((1 << (32 - $cidr_subnetmask)) - 1))) == ip2long($cidr_network);
463
}
464
465
/**
466
 * Adds slashes to the array/variable.
467
 * What it does:
468
 * - returns the var, as an array or string, with escapes as required.
469
 * - importantly escapes all keys and values!
470
 * - calls itself recursively if necessary.
471
 *
472
 * @param array|string $var A string or array of strings to escape
473
 * @return array|string The escaped string or array of escaped strings
474
 */
475 View Code Duplication
function escapestring__recursive($var)
0 ignored issues
show
Duplication introduced by
This function seems to be duplicated in your project.

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

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

Loading history...
476
{
477
	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...
478
479
	if (!is_array($var))
480
		return $smcFunc['db_escape_string']($var);
481
482
	// Reindex the array with slashes.
483
	$new_var = array();
484
485
	// Add slashes to every element, even the indexes!
486
	foreach ($var as $k => $v)
487
		$new_var[$smcFunc['db_escape_string']($k)] = escapestring__recursive($v);
488
489
	return $new_var;
490
}
491
492
/**
493
 * Adds html entities to the array/variable.  Uses two underscores to guard against overloading.
494
 * What it does:
495
 * - adds entities (&quot;, &lt;, &gt;) to the array or string var.
496
 * - importantly, does not effect keys, only values.
497
 * - calls itself recursively if necessary.
498
 *
499
 * @param array|string $var The string or array of strings to add entites to
500
 * @param int $level Which level we're at within the array (if called recursively)
501
 * @return array|string The string or array of strings with entities added
502
 */
503
function htmlspecialchars__recursive($var, $level = 0)
504
{
505
	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...
506
507
	if (!is_array($var))
508
		return isset($smcFunc['htmlspecialchars']) ? $smcFunc['htmlspecialchars']($var, ENT_QUOTES) : htmlspecialchars($var, ENT_QUOTES);
509
510
	// Add the htmlspecialchars to every element.
511
	foreach ($var as $k => $v)
512
		$var[$k] = $level > 25 ? null : htmlspecialchars__recursive($v, $level + 1);
513
514
	return $var;
515
}
516
517
/**
518
 * Removes url stuff from the array/variable.  Uses two underscores to guard against overloading.
519
 * What it does:
520
 * - takes off url encoding (%20, etc.) from the array or string var.
521
 * - importantly, does it to keys too!
522
 * - calls itself recursively if there are any sub arrays.
523
 *
524
 * @param array|string $var The string or array of strings to decode
525
 * @param int $level Which level we're at within the array (if called recursively)
526
 * @return array|string The decoded string or array of decoded strings
527
 */
528 View Code Duplication
function urldecode__recursive($var, $level = 0)
0 ignored issues
show
Duplication introduced by
This function seems to be duplicated in your project.

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

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

Loading history...
529
{
530
	if (!is_array($var))
531
		return urldecode($var);
532
533
	// Reindex the array...
534
	$new_var = array();
535
536
	// Add the htmlspecialchars to every element.
537
	foreach ($var as $k => $v)
538
		$new_var[urldecode($k)] = $level > 25 ? null : urldecode__recursive($v, $level + 1);
539
540
	return $new_var;
541
}
542
/**
543
 * Unescapes any array or variable.  Uses two underscores to guard against overloading.
544
 * What it does:
545
 * - unescapes, recursively, from the array or string var.
546
 * - effects both keys and values of arrays.
547
 * - calls itself recursively to handle arrays of arrays.
548
 *
549
 * @param array|string $var The string or array of strings to unescape
550
 * @return array|string The unescaped string or array of unescaped strings
551
 */
552 View Code Duplication
function unescapestring__recursive($var)
0 ignored issues
show
Duplication introduced by
This function seems to be duplicated in your project.

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

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

Loading history...
553
{
554
	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...
555
556
	if (!is_array($var))
557
		return $smcFunc['db_unescape_string']($var);
558
559
	// Reindex the array without slashes, this time.
560
	$new_var = array();
561
562
	// Strip the slashes from every element.
563
	foreach ($var as $k => $v)
564
		$new_var[$smcFunc['db_unescape_string']($k)] = unescapestring__recursive($v);
565
566
	return $new_var;
567
}
568
569
/**
570
 * Remove slashes recursively.  Uses two underscores to guard against overloading.
571
 * What it does:
572
 * - removes slashes, recursively, from the array or string var.
573
 * - effects both keys and values of arrays.
574
 * - calls itself recursively to handle arrays of arrays.
575
 *
576
 * @param array|string $var The string or array of strings to strip slashes from
577
 * @param int $level = 0 What level we're at within the array (if called recursively)
578
 * @return array|string The string or array of strings with slashes stripped
579
 */
580 View Code Duplication
function stripslashes__recursive($var, $level = 0)
0 ignored issues
show
Duplication introduced by
This function seems to be duplicated in your project.

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

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

Loading history...
581
{
582
	if (!is_array($var))
583
		return stripslashes($var);
584
585
	// Reindex the array without slashes, this time.
586
	$new_var = array();
587
588
	// Strip the slashes from every element.
589
	foreach ($var as $k => $v)
590
		$new_var[stripslashes($k)] = $level > 25 ? null : stripslashes__recursive($v, $level + 1);
591
592
	return $new_var;
593
}
594
595
/**
596
 * Trim a string including the HTML space, character 160.  Uses two underscores to guard against overloading.
597
 * What it does:
598
 * - trims a string or an the var array using html characters as well.
599
 * - does not effect keys, only values.
600
 * - may call itself recursively if needed.
601
 *
602
 * @param array|string $var The string or array of strings to trim
603
 * @param int $level = 0 How deep we're at within the array (if called recursively)
604
 * @return array|string The trimmed string or array of trimmed strings
605
 */
606
function htmltrim__recursive($var, $level = 0)
607
{
608
	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...
609
610
	// Remove spaces (32), tabs (9), returns (13, 10, and 11), nulls (0), and hard spaces. (160)
0 ignored issues
show
Unused Code Comprehensibility introduced by
52% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
611
	if (!is_array($var))
612
		return isset($smcFunc) ? $smcFunc['htmltrim']($var) : trim($var, ' ' . "\t\n\r\x0B" . '\0' . "\xA0");
613
614
	// Go through all the elements and remove the whitespace.
615
	foreach ($var as $k => $v)
616
		$var[$k] = $level > 25 ? null : htmltrim__recursive($v, $level + 1);
617
618
	return $var;
619
}
620
621
/**
622
 * Clean up the XML to make sure it doesn't contain invalid characters.
623
 * What it does:
624
 * - removes invalid XML characters to assure the input string being
625
 * - parsed properly.
626
 *
627
 * @param string $string The string to clean
628
 * @return string The cleaned string
629
 */
630
function cleanXml($string)
631
{
632
	global $context;
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...
633
634
	// https://www.w3.org/TR/2000/REC-xml-20001006#NT-Char
635
	return preg_replace('~[\x00-\x08\x0B\x0C\x0E-\x19' . ($context['utf8'] ? '\x{FFFE}\x{FFFF}' : '') . ']~' . ($context['utf8'] ? 'u' : ''), '', $string);
636
}
637
638
/**
639
 * Escapes (replaces) characters in strings to make them safe for use in javascript
640
 *
641
 * @param string $string The string to escape
642
 * @return string The escaped string
643
 */
644
function JavaScriptEscape($string)
645
{
646
	global $scripturl;
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...
647
648
	return '\'' . strtr($string, array(
649
		"\r" => '',
650
		"\n" => '\\n',
651
		"\t" => '\\t',
652
		'\\' => '\\\\',
653
		'\'' => '\\\'',
654
		'</' => '<\' + \'/',
655
		'<script' => '<scri\'+\'pt',
656
		'<body>' => '<bo\'+\'dy>',
657
		'<a href' => '<a hr\'+\'ef',
658
		$scripturl => '\' + smf_scripturl + \'',
659
	)) . '\'';
660
}
661
662
/**
663
 * Rewrite URLs to include the session ID.
664
 * What it does:
665
 * - rewrites the URLs outputted to have the session ID, if the user
666
 *   is not accepting cookies and is using a standard web browser.
667
 * - handles rewriting URLs for the queryless URLs option.
668
 * - can be turned off entirely by setting $scripturl to an empty
669
 *   string, ''. (it wouldn't work well like that anyway.)
670
 * - because of bugs in certain builds of PHP, does not function in
671
 *   versions lower than 4.3.0 - please upgrade if this hurts you.
672
 *
673
 * @param string $buffer The unmodified output buffer
674
 * @return string The modified buffer
675
 */
676
function ob_sessrewrite($buffer)
677
{
678
	global $scripturl, $modSettings, $context;
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...
679
680
	// If $scripturl is set to nothing, or the SID is not defined (SSI?) just quit.
681
	if ($scripturl == '' || !defined('SID'))
682
		return $buffer;
683
684
	// Do nothing if the session is cookied, or they are a crawler - guests are caught by redirectexit().  This doesn't work below PHP 4.3.0, because it makes the output buffer bigger.
685
	// @todo smflib
0 ignored issues
show
Coding Style Best Practice introduced by
Comments for TODO tasks are often forgotten in the code; it might be better to use a dedicated issue tracker.
Loading history...
686
	if (empty($_COOKIE) && SID != '' && !isBrowser('possibly_robot'))
687
		$buffer = preg_replace('/(?<!<link rel="canonical" href=)"' . preg_quote($scripturl, '/') . '(?!\?' . preg_quote(SID, '/') . ')\\??/', '"' . $scripturl . '?' . SID . '&amp;', $buffer);
688
	// Debugging templates, are we?
689 View Code Duplication
	elseif (isset($_GET['debug']))
690
		$buffer = preg_replace('/(?<!<link rel="canonical" href=)"' . preg_quote($scripturl, '/') . '\\??/', '"' . $scripturl . '?debug;', $buffer);
691
692
	// This should work even in 4.2.x, just not CGI without cgi.fix_pathinfo.
693
	if (!empty($modSettings['queryless_urls']) && (!$context['server']['is_cgi'] || ini_get('cgi.fix_pathinfo') == 1 || @get_cfg_var('cgi.fix_pathinfo') == 1) && ($context['server']['is_apache'] || $context['server']['is_lighttpd'] || $context['server']['is_litespeed']))
694
	{
695
		// Let's do something special for session ids!
696
		if (defined('SID') && SID != '')
697
			$buffer = preg_replace_callback('~"' . preg_quote($scripturl, '~') . '\?(?:' . SID . '(?:;|&|&amp;))((?:board|topic)=[^#"]+?)(#[^"]*?)?"~', function($m)
0 ignored issues
show
Comprehensibility introduced by
Avoid variables with short names like $m. 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...
698
			{
699
				global $scripturl; return '"' . $scripturl . "/" . strtr("$m[1]", '&;=', '//,') . ".html?" . SID . (isset($m[2]) ? $m[2] : "") . '"';
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...
Coding Style Comprehensibility introduced by
The string literal / does not require double quotes, as per coding-style, please use single quotes.

PHP provides two ways to mark string literals. Either with single quotes 'literal' or with double quotes "literal". The difference between these is that string literals in double quotes may contain variables with are evaluated at run-time as well as escape sequences.

String literals in single quotes on the other hand are evaluated very literally and the only two characters that needs escaping in the literal are the single quote itself (\') and the backslash (\\). Every other character is displayed as is.

Double quoted string literals may contain other variables or more complex escape sequences.

<?php

$singleQuoted = 'Value';
$doubleQuoted = "\tSingle is $singleQuoted";

print $doubleQuoted;

will print an indented: Single is Value

If your string literal does not contain variables or escape sequences, it should be defined using single quotes to make that fact clear.

For more information on PHP string literals and available escape sequences see the PHP core documentation.

Loading history...
Coding Style Best Practice introduced by
As per coding-style, please use concatenation or sprintf for the variable $m instead of interpolation.

It is generally a best practice as it is often more readable to use concatenation instead of interpolation for variables inside strings.

// Instead of
$x = "foo $bar $baz";

// Better use either
$x = "foo " . $bar . " " . $baz;
$x = sprintf("foo %s %s", $bar, $baz);
Loading history...
Coding Style Comprehensibility introduced by
The string literal .html? does not require double quotes, as per coding-style, please use single quotes.

PHP provides two ways to mark string literals. Either with single quotes 'literal' or with double quotes "literal". The difference between these is that string literals in double quotes may contain variables with are evaluated at run-time as well as escape sequences.

String literals in single quotes on the other hand are evaluated very literally and the only two characters that needs escaping in the literal are the single quote itself (\') and the backslash (\\). Every other character is displayed as is.

Double quoted string literals may contain other variables or more complex escape sequences.

<?php

$singleQuoted = 'Value';
$doubleQuoted = "\tSingle is $singleQuoted";

print $doubleQuoted;

will print an indented: Single is Value

If your string literal does not contain variables or escape sequences, it should be defined using single quotes to make that fact clear.

For more information on PHP string literals and available escape sequences see the PHP core documentation.

Loading history...
Coding Style Comprehensibility introduced by
The string literal does not require double quotes, as per coding-style, please use single quotes.

PHP provides two ways to mark string literals. Either with single quotes 'literal' or with double quotes "literal". The difference between these is that string literals in double quotes may contain variables with are evaluated at run-time as well as escape sequences.

String literals in single quotes on the other hand are evaluated very literally and the only two characters that needs escaping in the literal are the single quote itself (\') and the backslash (\\). Every other character is displayed as is.

Double quoted string literals may contain other variables or more complex escape sequences.

<?php

$singleQuoted = 'Value';
$doubleQuoted = "\tSingle is $singleQuoted";

print $doubleQuoted;

will print an indented: Single is Value

If your string literal does not contain variables or escape sequences, it should be defined using single quotes to make that fact clear.

For more information on PHP string literals and available escape sequences see the PHP core documentation.

Loading history...
Coding Style introduced by
It is generally recommended to place each PHP statement on a line by itself.

Let’s take a look at an example:

// Bad
$a = 5; $b = 6; $c = 7;

// Good
$a = 5;
$b = 6;
$c = 7;
Loading history...
700
			}, $buffer);
701 View Code Duplication
		else
702
			$buffer = preg_replace_callback('~"' . preg_quote($scripturl, '~') . '\?((?:board|topic)=[^#"]+?)(#[^"]*?)?"~', function($m)
703
			{
704
				global $scripturl; return '"' . $scripturl . '/' . strtr("$m[1]", '&;=', '//,') . '.html' . (isset($m[2]) ? $m[2] : "") . '"';
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...
Coding Style Best Practice introduced by
As per coding-style, please use concatenation or sprintf for the variable $m instead of interpolation.

It is generally a best practice as it is often more readable to use concatenation instead of interpolation for variables inside strings.

// Instead of
$x = "foo $bar $baz";

// Better use either
$x = "foo " . $bar . " " . $baz;
$x = sprintf("foo %s %s", $bar, $baz);
Loading history...
Coding Style Comprehensibility introduced by
The string literal does not require double quotes, as per coding-style, please use single quotes.

PHP provides two ways to mark string literals. Either with single quotes 'literal' or with double quotes "literal". The difference between these is that string literals in double quotes may contain variables with are evaluated at run-time as well as escape sequences.

String literals in single quotes on the other hand are evaluated very literally and the only two characters that needs escaping in the literal are the single quote itself (\') and the backslash (\\). Every other character is displayed as is.

Double quoted string literals may contain other variables or more complex escape sequences.

<?php

$singleQuoted = 'Value';
$doubleQuoted = "\tSingle is $singleQuoted";

print $doubleQuoted;

will print an indented: Single is Value

If your string literal does not contain variables or escape sequences, it should be defined using single quotes to make that fact clear.

For more information on PHP string literals and available escape sequences see the PHP core documentation.

Loading history...
Coding Style introduced by
It is generally recommended to place each PHP statement on a line by itself.

Let’s take a look at an example:

// Bad
$a = 5; $b = 6; $c = 7;

// Good
$a = 5;
$b = 6;
$c = 7;
Loading history...
705
			}, $buffer);
706
	}
707
708
	// Return the changed buffer.
709
	return $buffer;
710
}
711
712
?>