Completed
Pull Request — master (#88)
by Kenji
03:11
created

CI_Input::method()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %
Metric Value
dl 0
loc 6
rs 9.4286
cc 2
eloc 4
nc 2
nop 1
1
<?php
0 ignored issues
show
Coding Style Compatibility introduced by
For compatibility and reusability of your code, PSR1 recommends that a file should introduce either new symbols (like classes, functions, etc.) or have side-effects (like outputting something, or including other files), but not both at the same time. The first symbol is defined on line 51 and the first side effect is on line 38.

The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.

The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.

To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.

Loading history...
2
/**
3
 * CodeIgniter
4
 *
5
 * An open source application development framework for PHP
6
 *
7
 * This content is released under the MIT License (MIT)
8
 *
9
 * Copyright (c) 2014 - 2015, British Columbia Institute of Technology
10
 *
11
 * Permission is hereby granted, free of charge, to any person obtaining a copy
12
 * of this software and associated documentation files (the "Software"), to deal
13
 * in the Software without restriction, including without limitation the rights
14
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15
 * copies of the Software, and to permit persons to whom the Software is
16
 * furnished to do so, subject to the following conditions:
17
 *
18
 * The above copyright notice and this permission notice shall be included in
19
 * all copies or substantial portions of the Software.
20
 *
21
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
27
 * THE SOFTWARE.
28
 *
29
 * @package	CodeIgniter
30
 * @author	EllisLab Dev Team
31
 * @copyright	Copyright (c) 2008 - 2014, EllisLab, Inc. (http://ellislab.com/)
32
 * @copyright	Copyright (c) 2014 - 2015, British Columbia Institute of Technology (http://bcit.ca/)
33
 * @license	http://opensource.org/licenses/MIT	MIT License
34
 * @link	http://codeigniter.com
35
 * @since	Version 1.0.0
36
 * @filesource
37
 */
38
defined('BASEPATH') OR exit('No direct script access allowed');
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as or instead of || is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
39
40
/**
41
 * Input Class (Modified by ci-phpunit-test)
42
 *
43
 * Pre-processes global input data for security
44
 *
45
 * @package		CodeIgniter
46
 * @subpackage	Libraries
47
 * @category	Input
48
 * @author		EllisLab Dev Team
49
 * @link		http://codeigniter.com/user_guide/libraries/input.html
50
 */
51
class CI_Input {
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class must be in a namespace of at least one level to avoid collisions.

You can fix this by adding a namespace to your class:

namespace YourVendor;

class YourClass { }

When choosing a vendor namespace, try to pick something that is not too generic to avoid conflicts with other libraries.

Loading history...
52
53
	/**
54
	 * IP address of the current user
55
	 *
56
	 * @var	string
57
	 */
58
	protected $ip_address = FALSE;
59
60
	/**
61
	 * Allow GET array flag
62
	 *
63
	 * If set to FALSE, then $_GET will be set to an empty array.
64
	 *
65
	 * @var	bool
66
	 */
67
	protected $_allow_get_array = TRUE;
68
69
	/**
70
	 * Standardize new lines flag
71
	 *
72
	 * If set to TRUE, then newlines are standardized.
73
	 *
74
	 * @var	bool
75
	 */
76
	protected $_standardize_newlines;
77
78
	/**
79
	 * Enable XSS flag
80
	 *
81
	 * Determines whether the XSS filter is always active when
82
	 * GET, POST or COOKIE data is encountered.
83
	 * Set automatically based on config setting.
84
	 *
85
	 * @var	bool
86
	 */
87
	protected $_enable_xss = FALSE;
88
89
	/**
90
	 * Enable CSRF flag
91
	 *
92
	 * Enables a CSRF cookie token to be set.
93
	 * Set automatically based on config setting.
94
	 *
95
	 * @var	bool
96
	 */
97
	protected $_enable_csrf = FALSE;
98
99
	/**
100
	 * List of all HTTP request headers
101
	 *
102
	 * @var array
103
	 */
104
	protected $headers = array();
105
106
	/**
107
	 * Raw input stream data
108
	 *
109
	 * Holds a cache of php://input contents
110
	 *
111
	 * @var	string
112
	 */
113
	protected $_raw_input_stream;
114
115
	/**
116
	 * Parsed input stream data
117
	 *
118
	 * Parsed from php://input at runtime
119
	 *
120
	 * @see	CI_Input::input_stream()
121
	 * @var	array
122
	 */
123
	protected $_input_stream;
124
125
	protected $security;
126
	protected $uni;
127
128
	// --------------------------------------------------------------------
129
130
	/**
131
	 * Class constructor
132
	 *
133
	 * Determines whether to globally enable the XSS processing
134
	 * and whether to allow the $_GET array.
135
	 *
136
	 * @return	void
0 ignored issues
show
Comprehensibility Best Practice introduced by
Adding a @return annotation to constructors is generally not recommended as a constructor does not have a meaningful return value.

Adding a @return annotation to a constructor is not recommended, since a constructor does not have a meaningful return value.

Please refer to the PHP core documentation on constructors.

Loading history...
137
	 */
138
	public function __construct()
139
	{
140
		$this->_allow_get_array		= (config_item('allow_get_array') === TRUE);
141
		$this->_enable_xss		= (config_item('global_xss_filtering') === TRUE);
142
		$this->_enable_csrf		= (config_item('csrf_protection') === TRUE);
143
		$this->_standardize_newlines	= (bool) config_item('standardize_newlines');
144
145
		$this->security =& load_class('Security', 'core');
146
147
		// Do we need the UTF-8 class?
148
		if (UTF8_ENABLED === TRUE)
149
		{
150
			$this->uni =& load_class('Utf8', 'core');
151
		}
152
153
		// Sanitize global arrays
154
		$this->_sanitize_globals();
155
156
		// CSRF Protection check
157
		if ($this->_enable_csrf === TRUE && ! is_cli())
158
		{
159
			$this->security->csrf_verify();
160
		}
161
162
		log_message('info', 'Input Class Initialized');
163
	}
164
165
	// --------------------------------------------------------------------
166
167
	/**
168
	 * Fetch from array
169
	 *
170
	 * Internal method used to retrieve values from global arrays.
171
	 *
172
	 * @param	array	&$array		$_GET, $_POST, $_COOKIE, $_SERVER, etc.
173
	 * @param	mixed	$index		Index for item to be fetched from $array
174
	 * @param	bool	$xss_clean	Whether to apply XSS filtering
175
	 * @return	mixed
176
	 */
177
	protected function _fetch_from_array(&$array, $index = NULL, $xss_clean = NULL)
178
	{
179
		is_bool($xss_clean) OR $xss_clean = $this->_enable_xss;
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as or instead of || is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
180
181
		// If $index is NULL, it means that the whole $array is requested
182
		isset($index) OR $index = array_keys($array);
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as or instead of || is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
183
184
		// allow fetching multiple keys at once
185
		if (is_array($index))
186
		{
187
			$output = array();
188
			foreach ($index as $key)
189
			{
190
				$output[$key] = $this->_fetch_from_array($array, $key, $xss_clean);
191
			}
192
193
			return $output;
194
		}
195
196
		if (isset($array[$index]))
197
		{
198
			$value = $array[$index];
199
		}
200
		elseif (($count = preg_match_all('/(?:^[^\[]+)|\[[^]]*\]/', $index, $matches)) > 1) // Does the index contain array notation
201
		{
202
			$value = $array;
203
			for ($i = 0; $i < $count; $i++)
204
			{
205
				$key = trim($matches[0][$i], '[]');
206
				if ($key === '') // Empty notation will return the value as array
207
				{
208
					break;
209
				}
210
211
				if (isset($value[$key]))
212
				{
213
					$value = $value[$key];
214
				}
215
				else
216
				{
217
					return NULL;
218
				}
219
			}
220
		}
221
		else
222
		{
223
			return NULL;
224
		}
225
226
		return ($xss_clean === TRUE)
227
			? $this->security->xss_clean($value)
228
			: $value;
229
	}
230
231
	// --------------------------------------------------------------------
232
233
	/**
234
	 * Fetch an item from the GET array
235
	 *
236
	 * @param	mixed	$index		Index for item to be fetched from $_GET
237
	 * @param	bool	$xss_clean	Whether to apply XSS filtering
238
	 * @return	mixed
239
	 */
240
	public function get($index = NULL, $xss_clean = NULL)
0 ignored issues
show
Coding Style introduced by
get uses the super-global variable $_GET which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
241
	{
242
		return $this->_fetch_from_array($_GET, $index, $xss_clean);
243
	}
244
245
	// --------------------------------------------------------------------
246
247
	/**
248
	 * Fetch an item from the POST array
249
	 *
250
	 * @param	mixed	$index		Index for item to be fetched from $_POST
251
	 * @param	bool	$xss_clean	Whether to apply XSS filtering
252
	 * @return	mixed
253
	 */
254
	public function post($index = NULL, $xss_clean = NULL)
0 ignored issues
show
Coding Style introduced by
post uses the super-global variable $_POST which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
255
	{
256
		return $this->_fetch_from_array($_POST, $index, $xss_clean);
257
	}
258
259
	// --------------------------------------------------------------------
260
261
	/**
262
	 * Fetch an item from POST data with fallback to GET
263
	 *
264
	 * @param	string	$index		Index for item to be fetched from $_POST or $_GET
265
	 * @param	bool	$xss_clean	Whether to apply XSS filtering
266
	 * @return	mixed
267
	 */
268
	public function post_get($index, $xss_clean = NULL)
0 ignored issues
show
Coding Style introduced by
post_get uses the super-global variable $_POST which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
269
	{
270
		return isset($_POST[$index])
271
			? $this->post($index, $xss_clean)
272
			: $this->get($index, $xss_clean);
273
	}
274
275
	// --------------------------------------------------------------------
276
277
	/**
278
	 * Fetch an item from GET data with fallback to POST
279
	 *
280
	 * @param	string	$index		Index for item to be fetched from $_GET or $_POST
281
	 * @param	bool	$xss_clean	Whether to apply XSS filtering
282
	 * @return	mixed
283
	 */
284
	public function get_post($index, $xss_clean = NULL)
0 ignored issues
show
Coding Style introduced by
get_post uses the super-global variable $_GET which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
285
	{
286
		return isset($_GET[$index])
287
			? $this->get($index, $xss_clean)
288
			: $this->post($index, $xss_clean);
289
	}
290
291
	// --------------------------------------------------------------------
292
293
	/**
294
	 * Fetch an item from the COOKIE array
295
	 *
296
	 * @param	mixed	$index		Index for item to be fetched from $_COOKIE
297
	 * @param	bool	$xss_clean	Whether to apply XSS filtering
298
	 * @return	mixed
299
	 */
300
	public function cookie($index = NULL, $xss_clean = NULL)
0 ignored issues
show
Coding Style introduced by
cookie uses the super-global variable $_COOKIE which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
301
	{
302
		return $this->_fetch_from_array($_COOKIE, $index, $xss_clean);
303
	}
304
305
	// --------------------------------------------------------------------
306
307
	/**
308
	 * Fetch an item from the SERVER array
309
	 *
310
	 * @param	mixed	$index		Index for item to be fetched from $_SERVER
311
	 * @param	bool	$xss_clean	Whether to apply XSS filtering
312
	 * @return	mixed
313
	 */
314
	public function server($index, $xss_clean = NULL)
0 ignored issues
show
Coding Style introduced by
server uses the super-global variable $_SERVER which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
315
	{
316
		return $this->_fetch_from_array($_SERVER, $index, $xss_clean);
317
	}
318
319
	// ------------------------------------------------------------------------
320
321
	/**
322
	 * Fetch an item from the php://input stream
323
	 *
324
	 * Useful when you need to access PUT, DELETE or PATCH request data.
325
	 *
326
	 * @param	string	$index		Index for item to be fetched
327
	 * @param	bool	$xss_clean	Whether to apply XSS filtering
328
	 * @return	mixed
329
	 */
330
	public function input_stream($index = NULL, $xss_clean = NULL)
331
	{
332
		// Prior to PHP 5.6, the input stream can only be read once,
333
		// so we'll need to check if we have already done that first.
334
		if ( ! is_array($this->_input_stream))
335
		{
336
			// $this->raw_input_stream will trigger __get().
337
			parse_str($this->raw_input_stream, $this->_input_stream);
0 ignored issues
show
Bug introduced by
The property raw_input_stream does not seem to exist. Did you mean _raw_input_stream?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
338
			is_array($this->_input_stream) OR $this->_input_stream = array();
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as or instead of || is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
339
		}
340
341
		return $this->_fetch_from_array($this->_input_stream, $index, $xss_clean);
342
	}
343
344
	// ------------------------------------------------------------------------
345
346
	/**
347
	 * Set cookie
348
	 *
349
	 * Accepts an arbitrary number of parameters (up to 7) or an associative
350
	 * array in the first parameter containing all the values.
351
	 *
352
	 * @param	string|mixed[]	$name		Cookie name or an array containing parameters
353
	 * @param	string		$value		Cookie value
354
	 * @param	int		$expire		Cookie expiration time in seconds
355
	 * @param	string		$domain		Cookie domain (e.g.: '.yourdomain.com')
356
	 * @param	string		$path		Cookie path (default: '/')
357
	 * @param	string		$prefix		Cookie name prefix
358
	 * @param	bool		$secure		Whether to only transfer cookies via SSL
359
	 * @param	bool		$httponly	Whether to only makes the cookie accessible via HTTP (no javascript)
360
	 * @return	void
361
	 * 
362
	 * modified by ci-phpunit-test
363
	 */
364
	public function set_cookie($name, $value = '', $expire = '', $domain = '', $path = '/', $prefix = '', $secure = FALSE, $httponly = FALSE)
365
	{
366
		if (is_array($name))
367
		{
368
			// always leave 'name' in last place, as the loop will break otherwise, due to $$item
369
			foreach (array('value', 'expire', 'domain', 'path', 'prefix', 'secure', 'httponly', 'name') as $item)
370
			{
371
				if (isset($name[$item]))
372
				{
373
					$$item = $name[$item];
374
				}
375
			}
376
		}
377
378
		if ($prefix === '' && config_item('cookie_prefix') !== '')
379
		{
380
			$prefix = config_item('cookie_prefix');
381
		}
382
383
		if ($domain == '' && config_item('cookie_domain') != '')
384
		{
385
			$domain = config_item('cookie_domain');
386
		}
387
388
		if ($path === '/' && config_item('cookie_path') !== '/')
389
		{
390
			$path = config_item('cookie_path');
391
		}
392
393
		if ($secure === FALSE && config_item('cookie_secure') === TRUE)
394
		{
395
			$secure = config_item('cookie_secure');
396
		}
397
398
		if ($httponly === FALSE && config_item('cookie_httponly') !== FALSE)
399
		{
400
			$httponly = config_item('cookie_httponly');
401
		}
402
403
		if ( ! is_numeric($expire))
404
		{
405
			$expire = time() - 86500;
406
		}
407
		else
408
		{
409
			$expire = ($expire > 0) ? time() + $expire : 0;
410
		}
411
412
//		setcookie($prefix.$name, $value, $expire, $path, $domain, $secure, $httponly);
0 ignored issues
show
Unused Code Comprehensibility introduced by
66% 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...
413
414
		// Save cookie in Output object
415
		// added by ci-phpunit-test
416
		$CI =& get_instance();
417
		$output = $CI->output;
418
		$output->_cookies[$prefix.$name][] = [
419
			'value' => $value,
420
			'expire' => $expire,
421
			'path' => $path,
422
			'domain' => $domain,
423
			'secure' => $secure,
424
			'httponly' => $httponly,
425
		];
426
	}
427
428
	// --------------------------------------------------------------------
429
430
	/**
431
	 * Fetch the IP Address
432
	 *
433
	 * Determines and validates the visitor's IP address.
434
	 *
435
	 * @return	string	IP address
436
	 */
437
	public function ip_address()
438
	{
439
		if ($this->ip_address !== FALSE)
440
		{
441
			return $this->ip_address;
442
		}
443
444
		$proxy_ips = config_item('proxy_ips');
445
		if ( ! empty($proxy_ips) && ! is_array($proxy_ips))
446
		{
447
			$proxy_ips = explode(',', str_replace(' ', '', $proxy_ips));
448
		}
449
450
		$this->ip_address = $this->server('REMOTE_ADDR');
451
452
		if ($proxy_ips)
453
		{
454
			foreach (array('HTTP_X_FORWARDED_FOR', 'HTTP_CLIENT_IP', 'HTTP_X_CLIENT_IP', 'HTTP_X_CLUSTER_CLIENT_IP') as $header)
455
			{
456
				if (($spoof = $this->server($header)) !== NULL)
457
				{
458
					// Some proxies typically list the whole chain of IP
459
					// addresses through which the client has reached us.
460
					// e.g. client_ip, proxy_ip1, proxy_ip2, etc.
461
					sscanf($spoof, '%[^,]', $spoof);
462
463
					if ( ! $this->valid_ip($spoof))
464
					{
465
						$spoof = NULL;
466
					}
467
					else
468
					{
469
						break;
470
					}
471
				}
472
			}
473
474
			if ($spoof)
475
			{
476
				for ($i = 0, $c = count($proxy_ips); $i < $c; $i++)
0 ignored issues
show
Comprehensibility Bug introduced by
Loop incrementor ($i) jumbling with inner loop
Loading history...
477
				{
478
					// Check if we have an IP address or a subnet
479
					if (strpos($proxy_ips[$i], '/') === FALSE)
480
					{
481
						// An IP address (and not a subnet) is specified.
482
						// We can compare right away.
483
						if ($proxy_ips[$i] === $this->ip_address)
484
						{
485
							$this->ip_address = $spoof;
0 ignored issues
show
Bug introduced by
The variable $spoof does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
486
							break;
487
						}
488
489
						continue;
490
					}
491
492
					// We have a subnet ... now the heavy lifting begins
493
					isset($separator) OR $separator = $this->valid_ip($this->ip_address, 'ipv6') ? ':' : '.';
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as or instead of || is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
494
495
					// If the proxy entry doesn't match the IP protocol - skip it
496
					if (strpos($proxy_ips[$i], $separator) === FALSE)
497
					{
498
						continue;
499
					}
500
501
					// Convert the REMOTE_ADDR IP address to binary, if needed
502
					if ( ! isset($ip, $sprintf))
503
					{
504
						if ($separator === ':')
505
						{
506
							// Make sure we're have the "full" IPv6 format
507
							$ip = explode(':',
508
								str_replace('::',
509
									str_repeat(':', 9 - substr_count($this->ip_address, ':')),
510
									$this->ip_address
511
								)
512
							);
513
514
							for ($j = 0; $j < 8; $j++)
515
							{
516
								$ip[$j] = intval($ip[$j], 16);
517
							}
518
519
							$sprintf = '%016b%016b%016b%016b%016b%016b%016b%016b';
520
						}
521
						else
522
						{
523
							$ip = explode('.', $this->ip_address);
524
							$sprintf = '%08b%08b%08b%08b';
525
						}
526
527
						$ip = vsprintf($sprintf, $ip);
528
					}
529
530
					// Split the netmask length off the network address
531
					sscanf($proxy_ips[$i], '%[^/]/%d', $netaddr, $masklen);
0 ignored issues
show
Bug introduced by
The variable $masklen does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
532
533
					// Again, an IPv6 address is most likely in a compressed form
534
					if ($separator === ':')
535
					{
536
						$netaddr = explode(':', str_replace('::', str_repeat(':', 9 - substr_count($netaddr, ':')), $netaddr));
537
						for ($i = 0; $i < 8; $i++)
538
						{
539
							$netaddr[$i] = intval($netaddr[$i], 16);
540
						}
541
					}
542
					else
543
					{
544
						$netaddr = explode('.', $netaddr);
545
					}
546
547
					// Convert to binary and finally compare
548
					if (strncmp($ip, vsprintf($sprintf, $netaddr), $masklen) === 0)
549
					{
550
						$this->ip_address = $spoof;
551
						break;
552
					}
553
				}
554
			}
555
		}
556
557
		if ( ! $this->valid_ip($this->ip_address))
558
		{
559
			return $this->ip_address = '0.0.0.0';
560
		}
561
562
		return $this->ip_address;
563
	}
564
565
	// --------------------------------------------------------------------
566
567
	/**
568
	 * Validate IP Address
569
	 *
570
	 * @param	string	$ip	IP address
571
	 * @param	string	$which	IP protocol: 'ipv4' or 'ipv6'
572
	 * @return	bool
573
	 */
574
	public function valid_ip($ip, $which = '')
575
	{
576
		switch (strtolower($which))
577
		{
578
			case 'ipv4':
579
				$which = FILTER_FLAG_IPV4;
580
				break;
581
			case 'ipv6':
582
				$which = FILTER_FLAG_IPV6;
583
				break;
584
			default:
585
				$which = NULL;
586
				break;
587
		}
588
589
		return (bool) filter_var($ip, FILTER_VALIDATE_IP, $which);
590
	}
591
592
	// --------------------------------------------------------------------
593
594
	/**
595
	 * Fetch User Agent string
596
	 *
597
	 * @return	string|null	User Agent string or NULL if it doesn't exist
598
	 */
599
	public function user_agent($xss_clean = NULL)
0 ignored issues
show
Coding Style introduced by
user_agent uses the super-global variable $_SERVER which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
600
	{
601
		return $this->_fetch_from_array($_SERVER, 'HTTP_USER_AGENT', $xss_clean);
602
	}
603
604
	// --------------------------------------------------------------------
605
606
	/**
607
	 * Sanitize Globals
608
	 *
609
	 * Internal method serving for the following purposes:
610
	 *
611
	 *	- Unsets $_GET data, if query strings are not enabled
612
	 *	- Cleans POST, COOKIE and SERVER data
613
	 * 	- Standardizes newline characters to PHP_EOL
614
	 *
615
	 * @return	void
616
	 */
617
	protected function _sanitize_globals()
0 ignored issues
show
Coding Style introduced by
_sanitize_globals uses the super-global variable $_GET which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
Coding Style introduced by
_sanitize_globals uses the super-global variable $_POST which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
Coding Style introduced by
_sanitize_globals uses the super-global variable $_COOKIE which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
Coding Style introduced by
_sanitize_globals uses the super-global variable $_SERVER which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
618
	{
619
		// Is $_GET data allowed? If not we'll set the $_GET to an empty array
620 View Code Duplication
		if ($this->_allow_get_array === FALSE)
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...
621
		{
622
			$_GET = array();
623
		}
624
		elseif (is_array($_GET))
625
		{
626
			foreach ($_GET as $key => $val)
627
			{
628
				$_GET[$this->_clean_input_keys($key)] = $this->_clean_input_data($val);
629
			}
630
		}
631
632
		// Clean $_POST Data
633
		if (is_array($_POST))
634
		{
635
			foreach ($_POST as $key => $val)
636
			{
637
				$_POST[$this->_clean_input_keys($key)] = $this->_clean_input_data($val);
638
			}
639
		}
640
641
		// Clean $_COOKIE Data
642
		if (is_array($_COOKIE))
643
		{
644
			// Also get rid of specially treated cookies that might be set by a server
645
			// or silly application, that are of no use to a CI application anyway
646
			// but that when present will trip our 'Disallowed Key Characters' alarm
647
			// http://www.ietf.org/rfc/rfc2109.txt
648
			// note that the key names below are single quoted strings, and are not PHP variables
649
			unset(
650
				$_COOKIE['$Version'],
651
				$_COOKIE['$Path'],
652
				$_COOKIE['$Domain']
653
			);
654
655
			foreach ($_COOKIE as $key => $val)
656
			{
657
				if (($cookie_key = $this->_clean_input_keys($key)) !== FALSE)
658
				{
659
					$_COOKIE[$cookie_key] = $this->_clean_input_data($val);
660
				}
661
				else
662
				{
663
					unset($_COOKIE[$key]);
664
				}
665
			}
666
		}
667
668
		// Sanitize PHP_SELF
669
		$_SERVER['PHP_SELF'] = strip_tags($_SERVER['PHP_SELF']);
670
671
		log_message('debug', 'Global POST, GET and COOKIE data sanitized');
672
	}
673
674
	// --------------------------------------------------------------------
675
676
	/**
677
	 * Clean Input Data
678
	 *
679
	 * Internal method that aids in escaping data and
680
	 * standardizing newline characters to PHP_EOL.
681
	 *
682
	 * @param	string|string[]	$str	Input string(s)
683
	 * @return	string
684
	 */
685
	protected function _clean_input_data($str)
686
	{
687 View Code Duplication
		if (is_array($str))
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...
688
		{
689
			$new_array = array();
690
			foreach (array_keys($str) as $key)
691
			{
692
				$new_array[$this->_clean_input_keys($key)] = $this->_clean_input_data($str[$key]);
693
			}
694
			return $new_array;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $new_array; (array) is incompatible with the return type documented by CI_Input::_clean_input_data of type string.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
695
		}
696
697
		/* We strip slashes if magic quotes is on to keep things consistent
698
699
		   NOTE: In PHP 5.4 get_magic_quotes_gpc() will always return 0 and
700
		         it will probably not exist in future versions at all.
701
		*/
702
		if ( ! is_php('5.4') && get_magic_quotes_gpc())
703
		{
704
			$str = stripslashes($str);
705
		}
706
707
		// Clean UTF-8 if supported
708
		if (UTF8_ENABLED === TRUE)
709
		{
710
			$str = $this->uni->clean_string($str);
711
		}
712
713
		// Remove control characters
714
		$str = remove_invisible_characters($str, FALSE);
715
716
		// Standardize newlines if needed
717
		if ($this->_standardize_newlines === TRUE)
718
		{
719
			return preg_replace('/(?:\r\n|[\r\n])/', PHP_EOL, $str);
720
		}
721
722
		return $str;
723
	}
724
725
	// --------------------------------------------------------------------
726
727
	/**
728
	 * Clean Keys
729
	 *
730
	 * Internal method that helps to prevent malicious users
731
	 * from trying to exploit keys we make sure that keys are
732
	 * only named with alpha-numeric text and a few other items.
733
	 *
734
	 * @param	string	$str	Input string
735
	 * @param	bool	$fatal	Whether to terminate script exection
736
	 *				or to return FALSE if an invalid
737
	 *				key is encountered
738
	 * @return	string|bool
739
	 */
740
	protected function _clean_input_keys($str, $fatal = TRUE)
741
	{
742
		if ( ! preg_match('/^[a-z0-9:_\/|-]+$/i', $str))
743
		{
744
			if ($fatal === TRUE)
745
			{
746
				return FALSE;
747
			}
748
			else
749
			{
750
				set_status_header(503);
751
				echo 'Disallowed Key Characters.';
752
				exit(7); // EXIT_USER_INPUT
0 ignored issues
show
Coding Style Compatibility introduced by
The method _clean_input_keys() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
753
			}
754
		}
755
756
		// Clean UTF-8 if supported
757
		if (UTF8_ENABLED === TRUE)
758
		{
759
			return $this->uni->clean_string($str);
760
		}
761
762
		return $str;
763
	}
764
765
	// --------------------------------------------------------------------
766
767
	/**
768
	 * Request Headers
769
	 *
770
	 * @param	bool	$xss_clean	Whether to apply XSS filtering
771
	 * @return	array
772
	 */
773
	public function request_headers($xss_clean = FALSE)
0 ignored issues
show
Coding Style introduced by
request_headers uses the super-global variable $_SERVER which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
774
	{
775
		// If header is already defined, return it immediately
776
		if ( ! empty($this->headers))
777
		{
778
			return $this->headers;
779
		}
780
781
		// In Apache, you can simply call apache_request_headers()
782
		if (function_exists('apache_request_headers'))
783
		{
784
			return $this->headers = apache_request_headers();
785
		}
786
787
		$this->headers['Content-Type'] = isset($_SERVER['CONTENT_TYPE']) ? $_SERVER['CONTENT_TYPE'] : @getenv('CONTENT_TYPE');
788
789
		foreach ($_SERVER as $key => $val)
790
		{
791
			if (sscanf($key, 'HTTP_%s', $header) === 1)
792
			{
793
				// take SOME_HEADER and turn it into Some-Header
794
				$header = str_replace('_', ' ', strtolower($header));
795
				$header = str_replace(' ', '-', ucwords($header));
796
797
				$this->headers[$header] = $this->_fetch_from_array($_SERVER, $key, $xss_clean);
798
			}
799
		}
800
801
		return $this->headers;
802
	}
803
804
	// --------------------------------------------------------------------
805
806
	/**
807
	 * Get Request Header
808
	 *
809
	 * Returns the value of a single member of the headers class member
810
	 *
811
	 * @param	string		$index		Header name
812
	 * @param	bool		$xss_clean	Whether to apply XSS filtering
813
	 * @return	string|null	The requested header on success or NULL on failure
814
	 */
815
	public function get_request_header($index, $xss_clean = FALSE)
816
	{
817
		static $headers;
818
819
		if ( ! isset($headers))
820
		{
821
			empty($this->headers) && $this->request_headers();
822
			foreach ($this->headers as $key => $value)
823
			{
824
				$headers[strtolower($key)] = $value;
825
			}
826
		}
827
828
		$index = strtolower($index);
829
830
		if ( ! isset($headers[$index]))
831
		{
832
			return NULL;
833
		}
834
835
		return ($xss_clean === TRUE)
836
			? $this->security->xss_clean($headers[$index])
837
			: $headers[$index];
838
	}
839
840
	// --------------------------------------------------------------------
841
842
	/**
843
	 * Is AJAX request?
844
	 *
845
	 * Test to see if a request contains the HTTP_X_REQUESTED_WITH header.
846
	 *
847
	 * @return 	bool
848
	 */
849
	public function is_ajax_request()
0 ignored issues
show
Coding Style introduced by
is_ajax_request uses the super-global variable $_SERVER which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
850
	{
851
		return ( ! empty($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) === 'xmlhttprequest');
852
	}
853
854
	// --------------------------------------------------------------------
855
856
	/**
857
	 * Is CLI request?
858
	 *
859
	 * Test to see if a request was made from the command line.
860
	 *
861
	 * @deprecated	3.0.0	Use is_cli() instead
862
	 * @return	bool
863
	 */
864
	public function is_cli_request()
865
	{
866
		return is_cli();
867
	}
868
869
	// --------------------------------------------------------------------
870
871
	/**
872
	 * Get Request Method
873
	 *
874
	 * Return the request method
875
	 *
876
	 * @param	bool	$upper	Whether to return in upper or lower case
877
	 *				(default: FALSE)
878
	 * @return 	string
879
	 */
880
	public function method($upper = FALSE)
881
	{
882
		return ($upper)
883
			? strtoupper($this->server('REQUEST_METHOD'))
884
			: strtolower($this->server('REQUEST_METHOD'));
885
	}
886
887
	// ------------------------------------------------------------------------
888
889
	/**
890
	 * Magic __get()
891
	 *
892
	 * Allows read access to protected properties
893
	 *
894
	 * @param	string	$name
895
	 * @return	mixed
896
	 */
897
	public function __get($name)
898
	{
899
		if ($name === 'raw_input_stream')
900
		{
901
			isset($this->_raw_input_stream) OR $this->_raw_input_stream = file_get_contents('php://input');
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as or instead of || is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
902
			return $this->_raw_input_stream;
903
		}
904
		elseif ($name === 'ip_address')
905
		{
906
			return $this->ip_address;
907
		}
908
	}
909
910
}
911