HttpRequest::getCurrentUrl()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
c 0
b 0
f 0
nc 1
nop 0
dl 0
loc 4
rs 10
1
<?php
2
3
/**
4
 * Koch Framework
5
 * Jens-André Koch © 2005 - onwards.
6
 *
7
 * This file is part of "Koch Framework".
8
 *
9
 * License: GNU/GPL v2 or any later version, see LICENSE file.
10
 *
11
 * This program is free software; you can redistribute it and/or modify
12
 * it under the terms of the GNU General Public License as published by
13
 * the Free Software Foundation; either version 2 of the License, or
14
 * (at your option) any later version.
15
 *
16
 * This program is distributed in the hope that it will be useful,
17
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19
 * GNU General Public License for more details.
20
 *
21
 * You should have received a copy of the GNU General Public License
22
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
23
 */
24
25
namespace Koch\Http;
26
27
/**
28
 * Koch Framework - Class for Request Handling.
29
 *
30
 * It encapsulates the access to sanitized superglobals ($_GET, $_POST, $_SERVER).
31
 * There are two ways of access (1) via methods && (2) via spl arrayaccess array handling.
32
 */
33
class HttpRequest implements HttpRequestInterface, \ArrayAccess
34
{
35
    /**
36
     * @var array Contains the cleaned Parameters.
37
     */
38
    private $post_parameters;
0 ignored issues
show
Coding Style introduced by
$post_parameters does not seem to conform to the naming convention (^[a-z][a-zA-Z0-9]*$).

This check examines a number of code elements and verifies that they conform to the given naming conventions.

You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods.

Loading history...
39
40
    /**
41
     * @var array Contains the cleaned Parameters.
42
     */
43
    private $get_parameters;
0 ignored issues
show
Coding Style introduced by
$get_parameters does not seem to conform to the naming convention (^[a-z][a-zA-Z0-9]*$).

This check examines a number of code elements and verifies that they conform to the given naming conventions.

You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods.

Loading history...
44
45
    /**
46
     * @var array Contains the cleaned Parameters.
47
     */
48
    private $cookie_parameters;
0 ignored issues
show
Coding Style introduced by
$cookie_parameters does not seem to conform to the naming convention (^[a-z][a-zA-Z0-9]*$).

This check examines a number of code elements and verifies that they conform to the given naming conventions.

You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods.

Loading history...
49
50
    /**
51
     * @var The requestmethod. Possible values are GET, POST, PUT, DELETE.
52
     */
53
    protected static $request_method;
0 ignored issues
show
Coding Style introduced by
$request_method does not seem to conform to the naming convention (^[a-z][a-zA-Z0-9]*$).

This check examines a number of code elements and verifies that they conform to the given naming conventions.

You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods.

Loading history...
54
55
    /**
56
     * @var string the base URL (protocol://server:port)
57
     */
58
    protected static $baseURL;
59
60
    /**
61
     * @var object Object with pieces of informations about the target route.
62
     */
63
    private $route;
64
65
    /**
66
     * Construct the Request Object.
67
     *
68
     * 1) Drop Superglobal $_REQUEST. Just hardcoded reminder for developers to not use it!
69
     * 2) Additional Security Checks
70
     * 3) Clear Array, Filter and Assign the $_REQUEST Global to it
71
     * 4) Detect REST Tunneling through POST and set request_method accordingly
72
     */
73
    public function __construct()
0 ignored issues
show
Coding Style introduced by
__construct uses the super-global variable $_REQUEST 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
__construct 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...
Coding Style introduced by
__construct 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
__construct 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
__construct 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...
74
    {
75
        // 1) Drop $_REQUEST and $GLOBALS. Usage is forbidden!
76
        unset($_REQUEST);
77
        //unset($GLOBALS);
78
79
        /*
80
         * 2) Additional Security Checks
81
         */
82
83
        // block XSS
84
        $_SERVER['PHP_SELF'] = htmlspecialchars($_SERVER['PHP_SELF']);
85
        if (isset($_SERVER['QUERY_STRING'])) {
86
            htmlspecialchars($_SERVER['QUERY_STRING']);
87
        }
88
89
        /*
90
         * 3) Init Parameter Arrays and Assign the GLOBALS
91
         */
92
93
        // Clear Parameters Array
94
        $this->get_parameters    = [];
95
        $this->post_parameters   = [];
96
        $this->cookie_parameters = [];
97
98
        // Assign the GLOBALS $_GET, $_POST, $_COOKIE
0 ignored issues
show
Unused Code Comprehensibility introduced by
36% 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...
99
        $this->get_parameters    = $_GET;
100
        $this->post_parameters   = $_POST;
101
        $this->cookie_parameters = $_COOKIE;
102
103
        /*
104
         * 4) Detect REST Tunneling through POST and set request_method accordingly
105
         */
106
        $this->detectRESTTunneling();
107
    }
108
109
    /**
110
     * Returns the raw POST Parameters Array.
111
     * Raw means: no validation, no filtering, no sanitization.
112
     *
113
     * @return array POST Parameters Array.
114
     */
115
    public function getPost()
116
    {
117
        return $this->post_parameters;
118
    }
119
120
    /**
121
     * Returns the HTTP POST data in raw format via Stream.
122
     *
123
     * @return string HTTP POST data (raw).
124
     */
125
    public function getPostRaw()
126
    {
127
        return file_get_contents('php://input');
128
    }
129
130
    /**
131
     * Returns the raw GET Parameters Array.
132
     * Raw means: no validation, no filtering, no sanitization.
133
     *
134
     * @return array GET Parameters Array.
135
     */
136
    public function getGet()
137
    {
138
        return $this->get_parameters;
139
    }
140
141
    /**
142
     * Returns the COOKIES Parameters Array.
143
     * Raw means: no validation, no filtering, no sanitization.
144
     *
145
     * @return array COOKIES Parameters Array.
146
     */
147
    public function getCookies()
148
    {
149
        return $this->cookie_parameters;
150
    }
151
152
    public function getServer()
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
Coding Style introduced by
getServer 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...
153
    {
154
        return $_SERVER;
155
    }
156
157
    /**
158
     * expectParameters.
159
     *
160
     * a) isset test          -  to determine if the parameter is incomming
161
     * b) exception throwing  -  if parameter is not incomming, but expected
162
     *
163
     * @todo c) validation          -  validates the incomming parameter via rules
164
     *
165
     * $parameters array structure:
166
     * $parameters = array(
167
     *  'parametername' => array (      // parametername as key for rules array
168
     *      'source',                   // (GET|POST)
169
     *      'validation-rule'
170
     * );
171
     * 'modulename' => array ('GET', 'string|lowercase')
172
     *
173
     * @example
174
     * // parameter names only
175
     * $this->expectParameters(array('modulename','language'));
176
     * // parameters, one with rules
177
     * // parameters, all with rules
178
     *
179
     * @param array $parameters
180
     */
181
    public function expectParameters(array $parameters)
182
    {
183
        foreach ($parameters as $parameter => $array_or_parametername) {
0 ignored issues
show
Coding Style introduced by
$array_or_parametername does not seem to conform to the naming convention (^[a-z][a-zA-Z0-9]*$).

This check examines a number of code elements and verifies that they conform to the given naming conventions.

You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods.

Loading history...
184
            /*
185
             * check if we have some rules to process
186
             */
187
            if (true === is_array($array_or_parametername)) {
0 ignored issues
show
Coding Style introduced by
$array_or_parametername does not seem to conform to the naming convention (^[a-z][a-zA-Z0-9]*$).

This check examines a number of code elements and verifies that they conform to the given naming conventions.

You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods.

Loading history...
188
                $array_name = $array_or_parametername[0];      // GET|POST|COOKIE
0 ignored issues
show
Coding Style introduced by
$array_name does not seem to conform to the naming convention (^[a-z][a-zA-Z0-9]*$).

This check examines a number of code elements and verifies that they conform to the given naming conventions.

You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods.

Loading history...
189
                #$validation_rules   = $array_or_parametername[1];      // some validation commands
0 ignored issues
show
Unused Code Comprehensibility introduced by
60% 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...
190
191
                /*
192
                 * ISSET or Exception
193
                 */
194
                $this->expectParameter($parameter, $array_name);
0 ignored issues
show
Coding Style introduced by
$array_name does not seem to conform to the naming convention (^[a-z][a-zA-Z0-9]*$).

This check examines a number of code elements and verifies that they conform to the given naming conventions.

You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods.

Loading history...
195
196
                /*
197
                 * VALID or Exception
198
                 */
199
                #$this->validateParameter($parameter, $validation_rules);
0 ignored issues
show
Unused Code Comprehensibility introduced by
80% 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...
200
            } else { // if(is_int($array_or_parametername))
0 ignored issues
show
Unused Code Comprehensibility introduced by
75% 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
                $this->expectParameter($array_or_parametername);
0 ignored issues
show
Coding Style introduced by
$array_or_parametername does not seem to conform to the naming convention (^[a-z][a-zA-Z0-9]*$).

This check examines a number of code elements and verifies that they conform to the given naming conventions.

You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods.

Loading history...
202
            }
203
        }
204
    }
205
206
    /**
207
     * This method ensures that all the parameters you are expecting
208
     * and which are required by your action are really incomming with the request.
209
     * It's a multiple call to issetParameter(), with the difference,
210
     * that it throws an Exception if not isset!
211
     *
212
     * a) isset test          -  to determine if the parameter is incomming
213
     * b) exception throwing  -  if parameter is not incomming, but expected
214
     *
215
     * @param string $parameter
216
     * @param string $array     (GET|POST|COOKIE)
217
     */
218
    public function expectParameter($parameter, $array = '')
219
    {
220
        // when array is not defined issetParameter will searches (POST|GET|COOKIE)
221
        if (is_string($array)) {
222
            if (false === $this->issetParameter($parameter)) {
223
                throw new \Koch\Exception\Exception('Incoming Parameter missing: "' . $parameter . '".');
224
            }
225
        } else { // when array is defined issetParameter will search the given array
226
            if (false === $this->issetParameter($parameter, $array)) {
227
                throw new \Koch\Exception\Exception(
228
                    'Incoming Parameter missing: "' . $parameter . '" in Array "' . $array . '".'
229
                );
230
            }
231
        }
232
    }
233
234
    /**
235
     * isset, checks if a certain parameter exists in the parameters array.
236
     *
237
     * @param string $parameter Name of the Parameter
238
     * @param string $array     GET, POST, COOKIE. Default = GET.
239
     * @param bool   $where     If set to true, method will return the name of the array the parameter was found in.
240
     *
241
     * @return string boolean string arrayname
0 ignored issues
show
Documentation introduced by
Should the return type not be boolean|string|null?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
242
     */
243
    public function issetParameter($parameter, $array = 'GET', $where = false)
244
    {
245
        $array = mb_strtoupper($array);
246
247
        switch ($array) {
248
            case 'GET':
249
                if (isset($this->get_parameters[$parameter])) {
250
                    return ($where === false) ? true : 'get';
0 ignored issues
show
Bug Compatibility introduced by
The expression $where === false ? true : 'get'; of type boolean|string adds the type boolean to the return on line 250 which is incompatible with the return type declared by the interface Koch\Http\HttpRequestInterface::issetParameter of type string.
Loading history...
251
                }
252
                break;
253
            case 'POST':
254
                if (isset($this->post_parameters[$parameter])) {
255
                    return ($where === false) ? true : 'post';
0 ignored issues
show
Bug Compatibility introduced by
The expression $where === false ? true : 'post'; of type boolean|string adds the type boolean to the return on line 255 which is incompatible with the return type declared by the interface Koch\Http\HttpRequestInterface::issetParameter of type string.
Loading history...
256
                }
257
                break;
258
            case 'COOKIE':
259
                if (isset($this->cookie_parameters[$parameter])) {
260
                    return ($where === false) ? true : 'cookie';
0 ignored issues
show
Bug Compatibility introduced by
The expression $where === false ? true : 'cookie'; of type boolean|string adds the type boolean to the return on line 260 which is incompatible with the return type declared by the interface Koch\Http\HttpRequestInterface::issetParameter of type string.
Loading history...
261
                }
262
                break;
263
            default:
264
                return false;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return false; (false) is incompatible with the return type declared by the interface Koch\Http\HttpRequestInterface::issetParameter 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...
265
                break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
266
        }
267
    }
268
269
    /**
270
     * get, returns a certain parameter if existing.
271
     *
272
     * @param string $parameter Name of the Parameter
273
     * @param string $array     GET, POST, COOKIE. Default = POST.
274
     * @param string $default   You can set a default value. It's returned if parametername was not found.
0 ignored issues
show
Documentation introduced by
Should the type for parameter $default not be string|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
275
     *
276
     * @return mixed data | null
277
     */
278
    public function getParameter($parameter, $array = 'POST', $default = null)
279
    {
280
        /*
281
         * check if the parameter exists in $array
282
         * the third property of issetParameter is set to true, so that we get the full and correct array name back
283
         */
284
        $parameter_array = $this->issetParameter($parameter, $array, true);
0 ignored issues
show
Coding Style introduced by
$parameter_array does not seem to conform to the naming convention (^[a-z][a-zA-Z0-9]*$).

This check examines a number of code elements and verifies that they conform to the given naming conventions.

You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods.

Loading history...
285
286
        /*
287
         * we use type hinting here to cast the string with array name to boolean
288
         */
289
        if ((bool) $parameter_array === true) {
0 ignored issues
show
Coding Style introduced by
$parameter_array does not seem to conform to the naming convention (^[a-z][a-zA-Z0-9]*$).

This check examines a number of code elements and verifies that they conform to the given naming conventions.

You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods.

Loading history...
290
            // this returns a value from the parameterarray
291
            return $this->{mb_strtolower($parameter_array) . '_parameters'}[$parameter];
0 ignored issues
show
Coding Style introduced by
$parameter_array does not seem to conform to the naming convention (^[a-z][a-zA-Z0-9]*$).

This check examines a number of code elements and verifies that they conform to the given naming conventions.

You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods.

Loading history...
292
        } elseif ($default !== null) {
293
            // this returns the default value,incomming via method property $default
294
            return $default;
295
        } else {
296
            return;
297
        }
298
    }
299
300
    /**
301
     * set, returns a certain parameter if existing.
302
     *
303
     * @param string $parameter Name of the Parameter
304
     * @param string $array     G, P, C. Default = POST.
305
     *
306
     * @return mixed data | null
307
     */
308
    public function setParameter($parameter, $array = 'POST')
309
    {
310
        if (true === $this->issetParameter($parameter, $array)) {
311
            return $this->{mb_strtolower($array) . '_parameters'}[$parameter];
312
        } else {
313
            return;
314
        }
315
    }
316
317
    /**
318
     * Shortcut to get a Parameter from $_POST.
319
     *
320
     * @param string $name Name of the Parameter
321
     *
322
     * @return mixed data | null
323
     */
324
    public function getParameterFromPost($name)
325
    {
326
        return $this->getParameter($name, 'POST');
327
    }
328
329
    /**
330
     * Shortcut to get a Parameter from $_GET.
331
     *
332
     * @param string $name Name of the Parameter
333
     *
334
     * @return mixed data | null
335
     */
336
    public function getParameterFromGet($name)
337
    {
338
        return $this->getParameter($name, 'GET');
339
    }
340
341
    /**
342
     * Shortcut to get a Parameter from $_SERVER.
343
     *
344
     * @param string $name Name of the Parameter
345
     *
346
     * @return mixed data | null
347
     */
348
    public function getParameterFromServer($name)
0 ignored issues
show
Coding Style introduced by
getParameterFromServer 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...
349
    {
350
        if (in_array($name, array_keys($_SERVER), true)) {
351
            return $_SERVER[$name];
352
        } else {
353
            return;
354
        }
355
    }
356
357
    /**
358
     * Get previously set cookies.
359
     *
360
     * @param string $name Name of the Cookie
361
     *
362
     * @return Returns an associative array containing any previously set cookies.
363
     */
364
    public function getParameterFromCookie($name)
365
    {
366
        if (isset($this->cookie_parameters[$name]) === true) {
367
            return $this->cookie_parameters($name);
0 ignored issues
show
Bug introduced by
The method cookie_parameters() does not seem to exist on object<Koch\Http\HttpRequest>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
368
        }
369
    }
370
371
    /**
372
     * Get Value of a specific http-header.
373
     *
374
     * @param string $parameter Name of the Parameter
375
     *
376
     * @return string
377
     */
378
    public static function getHeader($parameter)
0 ignored issues
show
Coding Style introduced by
getHeader 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...
379
    {
380
        $parameter = 'HTTP_' . mb_strtoupper(str_replace('-', '_', $parameter));
381
382
        if ($_SERVER[$parameter] !== null) {
383
            return $_SERVER[$parameter];
384
        }
385
386
        return;
387
    }
388
389
    /**
390
     * Determine Type of Protocol for Webpaths (http/https)
391
     * Get for $_SERVER['HTTPS'].
392
     *
393
     * @todo check $_SERVER['SSL_PROTOCOL'] + $_SERVER['HTTP_X_FORWARD_PROTO']?
394
     * @todo check -> or $_SERVER['SSL_PROTOCOL']
395
     *
396
     * @return string
397
     */
398
    public static function getServerProtocol()
399
    {
400
        if (self::isSecure()) {
401
            return 'https://';
402
        } else {
403
            return 'http://';
404
        }
405
    }
406
407
    /**
408
     * Determine Type of Protocol for Webpaths (http/https)
409
     * Get for $_SERVER['HTTPS'] with boolean return value.
410
     *
411
     * @todo check about $_SERVER['SERVER_PORT'] == 443, is this always ssl then?
412
     *
413
     * @see $this->getServerProtocol()
414
     *
415
     * @return bool
416
     */
417
    public static function isSecure()
0 ignored issues
show
Coding Style introduced by
isSecure 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...
418
    {
419
        if (isset($_SERVER['HTTPS']) && (mb_strtolower($_SERVER['HTTPS']) === 'on' or $_SERVER['HTTPS'] === '1')) {
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...
Coding Style introduced by
The if-else statement can be simplified to return isset($_SERVER['H...RVER['HTTPS'] === '1');.
Loading history...
420
            return true;
421
        } else {
422
            return false;
423
        }
424
    }
425
426
    /**
427
     * Determine Port Number for Webpaths (http/https)
428
     * Get for $_SERVER['SERVER_PORT'] and $_SERVER['SSL_PROTOCOL'].
429
     *
430
     * @return string
0 ignored issues
show
Documentation introduced by
Should the return type not be string|null?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
431
     */
432
    private static function getServerPort()
0 ignored issues
show
Coding Style introduced by
getServerPort 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...
433
    {
434
        // custom port
435
        if (self::isSecure() === false and $_SERVER['SERVER_PORT'] !== 80) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as and 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...
436
            return ':' . $_SERVER['SERVER_PORT'];
437
        }
438
439
        // custom ssl port
440
        if (self::isSecure() && $_SERVER['SERVER_PORT'] !== 443) {
441
            return ':' . $_SERVER['SERVER_PORT'];
442
        }
443
    }
444
445
    /**
446
     * Returns the base of the current URL
447
     * Format: protocol://server:port.
448
     *
449
     * The "template constant"" WWW_ROOT is later defined as getBaseURL
450
     * <form action="<?=WWW_ROOT?>/news/7" method="DELETE"/>
451
     *
452
     * @return string
453
     */
454
    public static function getBaseURL()
455
    {
456
        if (empty(self::$baseURL)) {
457
            // 1. Determine Protocol
458
            self::$baseURL = self::getServerProtocol();
459
460
            // 2. Determine Servername
461
            self::$baseURL .= self::getServerName();
462
463
            // 3. Determine Port
464
            self::$baseURL .= self::getServerPort();
465
        }
466
467
        return self::$baseURL;
468
    }
469
470
    /**
471
     * Get $_SERVER SERVER_NAME.
472
     *
473
     * @return string The name of the server host under which the current script is executing.
474
     */
475
    public static function getServerName()
0 ignored issues
show
Coding Style introduced by
getServerName 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...
476
    {
477
        return $_SERVER['SERVER_NAME'];
478
    }
479
480
    /**
481
     * Get $_SERVER REQUEST_URI.
482
     *
483
     * @return string The URI which was given in order to access this page; for instance, '/index.html'.
484
     */
485
    public static function getRequestURI()
0 ignored issues
show
Coding Style introduced by
getRequestURI 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...
486
    {
487
        if ($_SERVER['REQUEST_URI'] !== null) {
488
            return urldecode(mb_strtolower($_SERVER['REQUEST_URI']));
489
        }
490
491
        // MS-IIS and ISAPI Rewrite Filter (only on windows platforms)
492
        if (isset($_SERVER['HTTP_X_REWRITE_URL']) and stripos(PHP_OS, 'WIN') !== false) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as and 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...
493
            return urldecode(mb_strtolower($_SERVER['HTTP_X_REWRITE_URL']));
494
        }
495
496
        $p = $_SERVER['SCRIPT_NAME'];
497
        if ($_SERVER['QUERY_STRING'] !== null) {
498
            $p .= '?' . $_SERVER['QUERY_STRING'];
499
        }
500
501
        return urldecode(mb_strtolower($p));
502
    }
503
504
    /**
505
     * Get $_SERVER REMOTE_URI.
506
     *
507
     * @return string
508
     */
509
    public static function getRemoteURI()
0 ignored issues
show
Coding Style introduced by
getRemoteURI 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...
510
    {
511
        return $_SERVER['REMOTE_URI'];
512
    }
513
514
    /**
515
     * Get $_SERVER QUERY_STRING.
516
     *
517
     * @return string The query string via which the page was accessed.
518
     */
519
    public static function getQueryString()
0 ignored issues
show
Coding Style introduced by
getQueryString 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...
520
    {
521
        return $_SERVER['QUERY_STRING'];
522
    }
523
524
    /**
525
     * Get the current Url.
526
     *
527
     * @return string Returns the current URL, which is the HOST + REQUEST_URI, without index.php.
528
     */
529
    public static function getCurrentUrl()
0 ignored issues
show
Coding Style introduced by
getCurrentUrl 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...
530
    {
531
        return str_replace('/index.php', '', 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']);
532
    }
533
534
    /**
535
     * Get IP = $_SERVER REMOTE_ADDRESS.
536
     *
537
     * @return string The IP/HOST from which the user is viewing the current page.
538
     */
539
    public static function getRemoteAddress()
0 ignored issues
show
Coding Style introduced by
getRemoteAddress 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...
540
    {
541
        $ip = null;
0 ignored issues
show
Unused Code introduced by
$ip is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
542
543
        if ($_SERVER['HTTP_CLIENT_IP'] !== null) {
544
            $ip = $_SERVER['HTTP_CLIENT_IP'];
545
        } elseif ($_SERVER['HTTP_X_FORWARDED_FOR'] !== null) {
546
            $ip = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
547
            $ip = array_pop($ip);
548
        } elseif ($_SERVER['HTTP_X_REAL_IP'] !== null) {
549
            // NGINX - with natural russian config passes the IP as REAL_IP
550
            $ip = $_SERVER['HTTP_X_REAL_IP'];
551
        } elseif ($_SERVER['HTTP_FORWARDED_FOR'] !== null) {
552
            $ip = $_SERVER['HTTP_FORWARDED_FOR'];
553
        } elseif ($_SERVER['HTTP_CLIENT_IP'] !== null) {
554
            $ip = $_SERVER['HTTP_CLIENT_IP'];
555
        } elseif ($_SERVER['HTTP_X_CLUSTER_CLIENT_IP'] !== null) {
556
            $ip = $_SERVER['HTTP_X_CLUSTER_CLIENT_IP'];
557
        } elseif ($_SERVER['HTTP_FORWARDED'] !== null) {
558
            $ip = $_SERVER['HTTP_FORWARDED'];
559
        } elseif ($_SERVER['HTTP_X_FORWARDED'] !== null) {
560
            $ip = $_SERVER['HTTP_X_FORWARDED'];
561
        } else {
562
            $ip = $_SERVER['REMOTE_ADDR'];
563
        }
564
565
        if (true === self::validateIP($ip)) {
566
            return $ip;
567
        }
568
    }
569
570
    /**
571
     * Returns the User Agent ($_SERVER HTTP_USER_AGENT).
572
     *
573
     * @return string String denoting the user agent being which is accessing the page.
574
     */
575 View Code Duplication
    public static function getUserAgent()
0 ignored issues
show
Duplication introduced by
This method 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...
Coding Style introduced by
getUserAgent 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...
576
    {
577
        $ua          = strip_tags($_SERVER['HTTP_USER_AGENT']);
578
        $ua_filtered = filter_var($ua, FILTER_SANITIZE_STRING, FILTER_FLAG_STRIP_LOW | FILTER_FLAG_STRIP_HIGH);
0 ignored issues
show
Coding Style introduced by
$ua_filtered does not seem to conform to the naming convention (^[a-z][a-zA-Z0-9]*$).

This check examines a number of code elements and verifies that they conform to the given naming conventions.

You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods.

Loading history...
579
580
        return $ua_filtered;
0 ignored issues
show
Coding Style introduced by
$ua_filtered does not seem to conform to the naming convention (^[a-z][a-zA-Z0-9]*$).

This check examines a number of code elements and verifies that they conform to the given naming conventions.

You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods.

Loading history...
581
    }
582
583
    /**
584
     * Returns the Referrer ($_SERVER HTTP_REFERER).
585
     *
586
     * @return string The address of the page (if any) which referred the user agent to the current page.
587
     */
588 View Code Duplication
    public static function getReferer()
0 ignored issues
show
Duplication introduced by
This method 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...
Coding Style introduced by
getReferer 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...
589
    {
590
        if ($_SERVER['HTTP_REFERER'] !== null) {
591
            $refr          = strip_tags($_SERVER['HTTP_REFERER']);
592
            $refr_filtered = filter_var($refr, FILTER_SANITIZE_STRING, FILTER_FLAG_STRIP_LOW | FILTER_FLAG_STRIP_HIGH);
0 ignored issues
show
Coding Style introduced by
$refr_filtered does not seem to conform to the naming convention (^[a-z][a-zA-Z0-9]*$).

This check examines a number of code elements and verifies that they conform to the given naming conventions.

You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods.

Loading history...
593
        }
594
595
        return $refr_filtered;
0 ignored issues
show
Coding Style introduced by
$refr_filtered does not seem to conform to the naming convention (^[a-z][a-zA-Z0-9]*$).

This check examines a number of code elements and verifies that they conform to the given naming conventions.

You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods.

Loading history...
Bug introduced by
The variable $refr_filtered 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...
596
    }
597
598
    /**
599
     * Validates a given IP.
600
     *
601
     * @see getRemoteAddress()
602
     *
603
     * @param string $ip   The IP address to validate.
604
     * @param boolen $ipv6 Boolean true, activates ipv6 checking.
0 ignored issues
show
Documentation introduced by
Should the type for parameter $ipv6 not be false|boolen?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
605
     *
606
     * @return bool True, if IP is valid. False, otherwise.
607
     */
608
    public static function validateIP($ip, $ipv6 = false)
0 ignored issues
show
Coding Style introduced by
function validateIP() does not seem to conform to the naming convention (^(?:is|has|should|may|supports)).

This check examines a number of code elements and verifies that they conform to the given naming conventions.

You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods.

Loading history...
609
    {
610
        if (true === $ipv6) {
611
            return (bool) filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE);
612
        } else {
613
            return (bool) filter_var(
614
                $ip,
615
                FILTER_VALIDATE_IP,
616
                FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE | FILTER_FLAG_IPV4
617
            );
618
        }
619
    }
620
621
    /**
622
     * Get Route returns the static \Koch\Router\TargetRoute object.
623
     *
624
     * With php onbord tools you can't debug this.
625
     * Please use \Koch\Debug\Debug:firebug($route); to debug.
626
     * Firebug uses Reflection to show the static properties and values.
627
     *
628
     * @return object \Koch\Router\TargetRoute
629
     */
630
    public function getRoute()
631
    {
632
        return $this->route;
633
    }
634
635
    /**
636
     * Set Route Object.
637
     *
638
     * @param $route \Koch\Router\TargetRoute
639
     */
640
    public function setRoute(\Koch\Router\TargetRoute $route)
641
    {
642
        $this->route = $route;
643
    }
644
645
    /**
646
     * REST Tunneling Detection.
647
     *
648
     * This method takes care for REST (Representational State Transfer)
649
     * by tunneling PUT, DELETE through POST (principal of least power).
650
     * Ok, this is faked or spoofed REST, but lowers the power of POST
651
     * and it's short and nice in html forms.
652
     *
653
     * @todo consider allowing 'GET' through POST?
654
     *
655
     * @see https://wiki.nbic.nl/index.php/REST.inc
656
     * @see http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html
657
     */
658
    public function detectRESTTunneling()
0 ignored issues
show
Coding Style introduced by
detectRESTTunneling 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...
Coding Style introduced by
detectRESTTunneling 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...
659
    {
660
        $allowed_rest_methodnames = ['DELETE', 'PUT'];
0 ignored issues
show
Coding Style introduced by
$allowed_rest_methodnames does not seem to conform to the naming convention (^[a-z][a-zA-Z0-9]*$).

This check examines a number of code elements and verifies that they conform to the given naming conventions.

You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods.

Loading history...
661
662
        // request_method has to be POST AND GET has to to have the method GET
663
        if (isset($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] === 'POST'
664
            and $this->issetParameter('GET', 'method')) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as and 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...
665
            // check for allowed rest commands
666
            if (in_array(mb_strtoupper($_GET['method']), $allowed_rest_methodnames, true)) {
0 ignored issues
show
Coding Style introduced by
$allowed_rest_methodnames does not seem to conform to the naming convention (^[a-z][a-zA-Z0-9]*$).

This check examines a number of code elements and verifies that they conform to the given naming conventions.

You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods.

Loading history...
667
                // set the internal (tunneled) method as new REQUEST_METHOD
668
                self::setRequestMethod($_GET['method']);
669
670
                // unset the tunneled method
671
                unset($_GET['method']);
672
673
                // now strip the methodname from the QUERY_STRING and rebuild REQUEST_URI
674
675
                // rebuild the QUERY_STRING from $_GET
676
                $_SERVER['QUERY_STRING'] = http_build_query($_GET);
677
                // rebuild the REQUEST_URI
678
                $_SERVER['REQUEST_URI'] = $_SERVER['SCRIPT_NAME'];
679
                // append QUERY_STRING to REQUEST_URI if not empty
680
                if ($_SERVER['QUERY_STRING'] !== '') {
681
                    $_SERVER['REQUEST_URI'] .= '?' . $_SERVER['QUERY_STRING'];
682
                }
683
            } else {
684
                throw new \Koch\Exception\Exception(
685
                    'Request Method failure. You tried to tunnel a ' . $this->getParameter('method', 'GET')
686
                    . ' request through an HTTP POST request.'
687
                );
688
            }
689
        } elseif (isset($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] === 'GET'
690
            and $this->issetParameter('GET', 'method')) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as and 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...
691
            // NOPE, there's no tunneling through GET!
692
            throw new \Koch\Exception\Exception(
693
                'Request Method failure. You tried to tunnel a ' . $this->getParameter('method', 'GET')
694
                . ' request through an HTTP GET request.'
695
            );
696
        }
697
    }
698
699
    /**
700
     * Get the REQUEST METHOD (GET, HEAD, POST, PUT, DELETE).
701
     *
702
     * HEAD request is returned internally as GET.
703
     * The internally set request_method (PUT or DELETE) is returned first,
704
     * because we might have a REST-tunneling.
705
     *
706
     * @return string request method
707
     */
708
    public static function getRequestMethod()
0 ignored issues
show
Coding Style introduced by
getRequestMethod 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...
709
    {
710
        if (self::$request_method !== null) {
711
            return self::$request_method;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return self::$request_method; (Koch\Http\The) is incompatible with the return type declared by the interface Koch\Http\HttpRequestInterface::getRequestMethod 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...
712
        }
713
714
        $method = $_SERVER['REQUEST_METHOD'];
715
716
        // get method from "http method override" header
717
        if (isset($_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE'])) {
718
            return $_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE'];
719
        }
720
721
        // add support for HEAD requests, which are GET requests
722
        if ($method === 'HEAD') {
723
            $method = 'GET';
724
        }
725
726
        return $method;
727
    }
728
729
    /**
730
     * Set the REQUEST_METHOD.
731
     */
732
    public static function setRequestMethod($method)
733
    {
734
        self::$request_method = strtoupper($method);
0 ignored issues
show
Documentation Bug introduced by
It seems like strtoupper($method) of type string is incompatible with the declared type object<Koch\Http\The> of property $request_method.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
735
    }
736
737
    /**
738
     * Checks if a ajax(xhr)-request is given,
739
     * by checking X-Requested-With Header for XMLHttpRequest.
740
     *
741
     * @return bool true if the request is an XMLHttpRequest, false otherwise
742
     */
743
    public static function isAjax()
0 ignored issues
show
Coding Style introduced by
isAjax 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...
744
    {
745
        if (isset($_SERVER['X-Requested-With']) and $_SERVER['X-Requested-With'] === 'XMLHttpRequest') {
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as and 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...
746
            return true;
747
        } elseif (isset($_SERVER['HTTP_X_REQUESTED_WITH']) and $_SERVER['HTTP_X_REQUESTED_WITH'] === 'XMLHttpRequest') {
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as and 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...
748
            return true;
749
        } else {
750
            return false;
751
        }
752
    }
753
754
    /**
755
     * is(GET|POST|PUT|DELETE)
756
     * Boolean "getters" for several HttpRequest Types.
757
     * This makes request type checking in controllers easy.
758
     */
759
760
    /**
761
     * Determines, if request is of type GET.
762
     *
763
     * @return bool
764
     */
765
    public function isGet()
766
    {
767
        return self::$request_method === 'GET';
768
    }
769
770
    /**
771
     * Determines, if request is of type POST.
772
     *
773
     * @return bool
774
     */
775
    public function isPost()
776
    {
777
        return self::$request_method === 'POST';
778
    }
779
780
    /**
781
     * Determines, if request is of type PUT.
782
     *
783
     * @return bool
784
     */
785
    public function isPut()
786
    {
787
        return self::$request_method === 'PUT';
788
    }
789
790
    /**
791
     * Determines, if request is of type DELETE.
792
     *
793
     * @return bool
794
     */
795
    public function isDelete()
796
    {
797
        return self::$request_method === 'DELETE';
798
    }
799
800
    /**
801
     * Implementation of SPL ArrayAccess
802
     * only offsetExists and offsetGet are relevant.
803
     */
804
    public function offsetExists($offset)
805
    {
806
        return $this->issetParameter($offset);
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->issetParameter($offset); of type boolean|string|null adds the type string to the return on line 806 which is incompatible with the return type declared by the interface ArrayAccess::offsetExists of type boolean.
Loading history...
807
    }
808
809
    public function offsetGet($offset)
810
    {
811
        return $this->getParameter($offset);
812
    }
813
814
    // not setting request vars
815
    public function offsetSet($offset, $value)
816
    {
817
        return false;
818
    }
819
820
    // not unsetting request vars
821
    public function offsetUnset($offset)
822
    {
823
        return false;
824
    }
825
}
826