Completed
Push — master ( 93f6e0...a7ea34 )
by Aydin
27:25 queued 18:55
created

Request   B

Complexity

Total Complexity 39

Size/Duplication

Total Lines 469
Duplicated Lines 0 %

Coupling/Cohesion

Components 4
Dependencies 3

Importance

Changes 2
Bugs 0 Features 1
Metric Value
wmc 39
c 2
b 0
f 1
lcom 4
cbo 3
dl 0
loc 469
rs 8.2857

24 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 20 2
A createFromGlobals() 0 12 1
A id() 0 12 3
A paramsGet() 0 4 1
A paramsPost() 0 4 1
A paramsNamed() 0 4 1
A cookies() 0 4 1
A server() 0 4 1
A headers() 0 4 1
A files() 0 4 1
A body() 0 9 2
A params() 0 21 3
A param() 0 7 2
A __isset() 0 7 1
A __get() 0 4 1
A __set() 0 4 1
A __unset() 0 4 1
A isSecure() 0 4 1
A ip() 0 4 1
A userAgent() 0 4 1
A uri() 0 4 1
A pathname() 0 9 2
B method() 0 23 5
B query() 0 23 4
1
<?php
2
/**
3
 * Klein (klein.php) - A fast & flexible router for PHP
4
 *
5
 * @author      Chris O'Hara <[email protected]>
6
 * @author      Trevor Suarez (Rican7) (contributor and v2 refactorer)
7
 * @copyright   (c) Chris O'Hara
8
 * @link        https://github.com/chriso/klein.php
9
 * @license     MIT
10
 */
11
12
namespace Klein;
13
14
use Klein\DataCollection\DataCollection;
15
use Klein\DataCollection\HeaderDataCollection;
16
use Klein\DataCollection\ServerDataCollection;
17
18
/**
19
 * Request
20
 */
21
class Request
22
{
23
24
    /**
25
     * Class properties
26
     */
27
28
    /**
29
     * Unique identifier for the request
30
     *
31
     * @type string
32
     */
33
    protected $id;
34
35
    /**
36
     * GET (query) parameters
37
     *
38
     * @type DataCollection
39
     */
40
    protected $params_get;
41
42
    /**
43
     * POST parameters
44
     *
45
     * @type DataCollection
46
     */
47
    protected $params_post;
48
49
    /**
50
     * Named parameters
51
     *
52
     * @type DataCollection
53
     */
54
    protected $params_named;
55
56
    /**
57
     * Client cookie data
58
     *
59
     * @type DataCollection
60
     */
61
    protected $cookies;
62
63
    /**
64
     * Server created attributes
65
     *
66
     * @type ServerDataCollection
67
     */
68
    protected $server;
69
70
    /**
71
     * HTTP request headers
72
     *
73
     * @type HeaderDataCollection
74
     */
75
    protected $headers;
76
77
    /**
78
     * Uploaded temporary files
79
     *
80
     * @type DataCollection
81
     */
82
    protected $files;
83
84
    /**
85
     * The request body
86
     *
87
     * @type string
88
     */
89
    protected $body;
90
91
92
    /**
93
     * Methods
94
     */
95
96
    /**
97
     * Constructor
98
     *
99
     * Create a new Request object and define all of its request data
100
     *
101
     * @param array  $params_get
102
     * @param array  $params_post
103
     * @param array  $cookies
104
     * @param array  $server
105
     * @param array  $files
106
     * @param string $body
107
     */
108
    public function __construct(
109
        array $params_get = array(),
110
        array $params_post = array(),
111
        array $cookies = array(),
112
        array $server = array(),
113
        array $files = array(),
114
        $body = null
115
    ) {
116
        // Assignment city...
117
        $this->params_get   = new DataCollection($params_get);
118
        $this->params_post  = new DataCollection($params_post);
119
        $this->cookies      = new DataCollection($cookies);
120
        $this->server       = new ServerDataCollection($server);
121
        $this->headers      = new HeaderDataCollection($this->server->getHeaders());
122
        $this->files        = new DataCollection($files);
123
        $this->body         = $body ? (string) $body : null;
124
125
        // Non-injected assignments
126
        $this->params_named = new DataCollection();
127
    }
128
129
    /**
130
     * Create a new request object using the built-in "superglobals"
131
     *
132
     * @link http://php.net/manual/en/language.variables.superglobals.php
133
     * @return Request
134
     */
135
    public static function createFromGlobals()
0 ignored issues
show
Coding Style introduced by
createFromGlobals 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
createFromGlobals 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
createFromGlobals 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
createFromGlobals 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
createFromGlobals uses the super-global variable $_FILES 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...
136
    {
137
        // Create and return a new instance of this
138
        return new static(
139
            $_GET,
140
            $_POST,
141
            $_COOKIE,
142
            $_SERVER,
143
            $_FILES,
144
            null // Let our content getter take care of the "body"
145
        );
146
    }
147
148
    /**
149
     * Gets a unique ID for the request
150
     *
151
     * Generates one on the first call
152
     *
153
     * @param boolean $hash     Whether or not to hash the ID on creation
154
     * @return string
155
     */
156
    public function id($hash = true)
157
    {
158
        if (null === $this->id) {
159
            $this->id = uniqid();
160
161
            if ($hash) {
162
                $this->id = sha1($this->id);
163
            }
164
        }
165
166
        return $this->id;
167
    }
168
169
    /**
170
     * Returns the GET parameters collection
171
     *
172
     * @return \Klein\DataCollection\DataCollection
173
     */
174
    public function paramsGet()
175
    {
176
        return $this->params_get;
177
    }
178
179
    /**
180
     * Returns the POST parameters collection
181
     *
182
     * @return \Klein\DataCollection\DataCollection
183
     */
184
    public function paramsPost()
185
    {
186
        return $this->params_post;
187
    }
188
189
    /**
190
     * Returns the named parameters collection
191
     *
192
     * @return \Klein\DataCollection\DataCollection
193
     */
194
    public function paramsNamed()
195
    {
196
        return $this->params_named;
197
    }
198
199
    /**
200
     * Returns the cookies collection
201
     *
202
     * @return \Klein\DataCollection\DataCollection
203
     */
204
    public function cookies()
205
    {
206
        return $this->cookies;
207
    }
208
209
    /**
210
     * Returns the server collection
211
     *
212
     * @return \Klein\DataCollection\DataCollection
213
     */
214
    public function server()
215
    {
216
        return $this->server;
217
    }
218
219
    /**
220
     * Returns the headers collection
221
     *
222
     * @return \Klein\DataCollection\HeaderDataCollection
223
     */
224
    public function headers()
225
    {
226
        return $this->headers;
227
    }
228
229
    /**
230
     * Returns the files collection
231
     *
232
     * @return \Klein\DataCollection\DataCollection
233
     */
234
    public function files()
235
    {
236
        return $this->files;
237
    }
238
239
    /**
240
     * Gets the request body
241
     *
242
     * @return string
243
     */
244
    public function body()
245
    {
246
        // Only get it once
247
        if (null === $this->body) {
248
            $this->body = @file_get_contents('php://input');
249
        }
250
251
        return $this->body;
252
    }
253
254
    /**
255
     * Returns all parameters (GET, POST, named, and cookies) that match the mask
256
     *
257
     * Takes an optional mask param that contains the names of any params
258
     * you'd like this method to exclude in the returned array
259
     *
260
     * @see \Klein\DataCollection\DataCollection::all()
261
     * @param array $mask               The parameter mask array
262
     * @param boolean $fill_with_nulls  Whether or not to fill the returned array
263
     *  with null values to match the given mask
264
     * @return array
265
     */
266
    public function params($mask = null, $fill_with_nulls = true)
267
    {
268
        /*
269
         * Make sure that each key in the mask has at least a
270
         * null value, since the user will expect the key to exist
271
         */
272
        if (null !== $mask && $fill_with_nulls) {
273
            $attributes = array_fill_keys($mask, null);
274
        } else {
275
            $attributes = array();
276
        }
277
278
        // Merge our params in the get, post, cookies, named order
279
        return array_merge(
280
            $attributes,
281
            $this->params_get->all($mask, false),
282
            $this->params_post->all($mask, false),
283
            $this->cookies->all($mask, false),
284
            $this->params_named->all($mask, false) // Add our named params last
285
        );
286
    }
287
288
    /**
289
     * Return a request parameter, or $default if it doesn't exist
290
     *
291
     * @param string $key       The name of the parameter to return
292
     * @param mixed $default    The default value of the parameter if it contains no value
293
     * @return string
294
     */
295
    public function param($key, $default = null)
296
    {
297
        // Get all of our request params
298
        $params = $this->params();
299
300
        return isset($params[$key]) ? $params[$key] : $default;
301
    }
302
303
    /**
304
     * Magic "__isset" method
305
     *
306
     * Allows the ability to arbitrarily check the existence of a parameter
307
     * from this instance while treating it as an instance property
308
     *
309
     * @param string $param     The name of the parameter
310
     * @return boolean
311
     */
312
    public function __isset($param)
313
    {
314
        // Get all of our request params
315
        $params = $this->params();
316
317
        return isset($params[$param]);
318
    }
319
320
    /**
321
     * Magic "__get" method
322
     *
323
     * Allows the ability to arbitrarily request a parameter from this instance
324
     * while treating it as an instance property
325
     *
326
     * @param string $param     The name of the parameter
327
     * @return string
328
     */
329
    public function __get($param)
330
    {
331
        return $this->param($param);
332
    }
333
334
    /**
335
     * Magic "__set" method
336
     *
337
     * Allows the ability to arbitrarily set a parameter from this instance
338
     * while treating it as an instance property
339
     *
340
     * NOTE: This currently sets the "named" parameters, since that's the
341
     * one collection that we have the most sane control over
342
     *
343
     * @param string $param     The name of the parameter
344
     * @param mixed $value      The value of the parameter
345
     * @return void
346
     */
347
    public function __set($param, $value)
348
    {
349
        $this->params_named->set($param, $value);
350
    }
351
352
    /**
353
     * Magic "__unset" method
354
     *
355
     * Allows the ability to arbitrarily remove a parameter from this instance
356
     * while treating it as an instance property
357
     *
358
     * @param string $param     The name of the parameter
359
     * @return void
360
     */
361
    public function __unset($param)
362
    {
363
        $this->params_named->remove($param);
364
    }
365
366
    /**
367
     * Is the request secure?
368
     *
369
     * @return boolean
370
     */
371
    public function isSecure()
372
    {
373
        return ($this->server->get('HTTPS') == true);
374
    }
375
376
    /**
377
     * Gets the request IP address
378
     *
379
     * @return string
380
     */
381
    public function ip()
382
    {
383
        return $this->server->get('REMOTE_ADDR');
384
    }
385
386
    /**
387
     * Gets the request user agent
388
     *
389
     * @return string
390
     */
391
    public function userAgent()
392
    {
393
        return $this->headers->get('USER_AGENT');
394
    }
395
396
    /**
397
     * Gets the request URI
398
     *
399
     * @return string
400
     */
401
    public function uri()
402
    {
403
        return $this->server->get('REQUEST_URI', '/');
404
    }
405
406
    /**
407
     * Get the request's pathname
408
     *
409
     * @return string
410
     */
411
    public function pathname()
412
    {
413
        $uri = $this->uri();
414
415
        // Strip the query string from the URI
416
        $uri = strstr($uri, '?', true) ?: $uri;
417
418
        return $uri;
419
    }
420
421
    /**
422
     * Gets the request method, or checks it against $is
423
     *
424
     * <code>
425
     * // POST request example
426
     * $request->method() // returns 'POST'
427
     * $request->method('post') // returns true
428
     * $request->method('get') // returns false
429
     * </code>
430
     * 
431
     * @param string $is				The method to check the current request method against
432
     * @param boolean $allow_override	Whether or not to allow HTTP method overriding via header or params
433
     * @return string|boolean
434
     */
435
    public function method($is = null, $allow_override = true)
436
    {
437
        $method = $this->server->get('REQUEST_METHOD', 'GET');
438
439
        // Override
440
        if ($allow_override && $method === 'POST') {
441
            // For legacy servers, override the HTTP method with the X-HTTP-Method-Override header or _method parameter
442
            if ($this->server->exists('X_HTTP_METHOD_OVERRIDE')) {
443
                $method = $this->server->get('X_HTTP_METHOD_OVERRIDE', $method);
444
            } else {
445
                $method = $this->param('_method', $method);
446
            }
447
448
            $method = strtoupper($method);
449
        }
450
451
        // We're doing a check
452
        if (null !== $is) {
453
            return strcasecmp($method, $is) === 0;
454
        }
455
456
        return $method;
457
    }
458
459
    /**
460
     * Adds to or modifies the current query string
461
     *
462
     * @param string $key   The name of the query param
463
     * @param mixed $value  The value of the query param
464
     * @return string
465
     */
466
    public function query($key, $value = null)
467
    {
468
        $query = array();
469
470
        parse_str(
471
            $this->server()->get('QUERY_STRING'),
472
            $query
473
        );
474
475
        if (is_array($key)) {
476
            $query = array_merge($query, $key);
477
        } else {
478
            $query[$key] = $value;
479
        }
480
481
        $request_uri = $this->uri();
482
483
        if (strpos($request_uri, '?') !== false) {
484
            $request_uri = strstr($request_uri, '?', true);
485
        }
486
487
        return $request_uri . (!empty($query) ? '?' . http_build_query($query) : null);
488
    }
489
}
490