Request::flash()   A
last analyzed

Complexity

Conditions 5
Paths 4

Size

Total Lines 17
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
eloc 8
nc 4
nop 2
dl 0
loc 17
rs 9.6111
c 0
b 0
f 0
1
<?php
2
namespace Darya\Http;
3
4
/**
5
 * Darya's HTTP request representation.
6
 *
7
 * @property-read array $get
8
 * @property-read array $post
9
 * @property-read array $cookie
10
 * @property-read array $file
11
 * @property-read array $server
12
 * @property-read array $header
13
 * @method mixed get(string $key = null, mixed $default = null)
14
 * @method mixed post(string $key = null, mixed $default = null)
15
 * @method mixed cookie(string $key = null, mixed $default = null)
16
 * @method mixed file(string $key = null, mixed $default = null)
17
 * @method mixed server(string $key = null, mixed $default = null)
18
 * @method mixed header(string $key = null, mixed $default = null)
19
 *
20
 * @author Chris Andrew <[email protected]>
21
 */
22
class Request
23
{
24
	/**
25
	 * Request data types to be treated case-insensitively.
26
	 *
27
	 * @var array
28
	 */
29
	protected static $caseInsensitive = array('server', 'header');
30
31
	/**
32
	 * The request data.
33
	 *
34
	 * @var array
35
	 */
36
	protected $data = array(
37
		'get'     => array(),
38
		'post'    => array(),
39
		'cookie'  => array(),
40
		'file'    => array(),
41
		'server'  => array(),
42
		'header'  => array(),
43
		'session' => null
44
	);
45
46
	/**
47
	 * Request body content.
48
	 *
49
	 * @var string
50
	 */
51
	protected $content;
52
53
	/**
54
	 * The session that belongs to this request.
55
	 *
56
	 * @var \Darya\Http\Session
57
	 */
58
	protected $session;
59
60
	/**
61
	 * The router that matched this request.
62
	 *
63
	 * @var \Darya\Routing\Router
64
	 */
65
	public $router;
66
67
	/**
68
	 * The route that this request was matched with.
69
	 *
70
	 * @var \Darya\Routing\Route
71
	 */
72
	public $route;
73
74
	/**
75
	 * Determine whether the given data type's keys can be treated
76
	 * case-insensitively.
77
	 *
78
	 * @param string $type
79
	 * @return bool
80
	 */
81
	protected static function isCaseInsensitive($type)
82
	{
83
		return in_array($type, static::$caseInsensitive);
84
	}
85
86
	/**
87
	 * Prepare the given request data where necessary.
88
	 *
89
	 * Lowercases data type keys and the keys of `server` and `header` data so
90
	 * they can be treated case-insensitively.
91
	 *
92
	 * Any expected data types not satisfied will contain an empty array apart
93
	 * from `session`, which will be null.
94
	 *
95
	 * @param array $data
96
	 * @return array
97
	 */
98
	protected static function prepareData(array $data)
99
	{
100
		$data = array_change_key_case($data);
101
102
		foreach (array_keys($data) as $type) {
103
			if (static::isCaseInsensitive($type)) {
104
				$data[$type] = array_change_key_case($data[$type]);
105
			}
106
		}
107
108
		return array_merge(array(
109
			'get'     => array(),
110
			'post'    => array(),
111
			'cookie'  => array(),
112
			'file'    => array(),
113
			'server'  => array(),
114
			'header'  => array(),
115
			'session' => null
116
		), $data);
117
	}
118
119
120
	/**
121
	 * Parse the given URI and return its components.
122
	 *
123
	 * Any components not satisfied will be null instead of non-existent, so you
124
	 * can safely expect the keys 'scheme', 'host', 'port', 'user', 'pass',
125
	 * 'query' and 'fragment' to exist.
126
	 *
127
	 * @param string $url
128
	 * @return array
129
	 */
130
	protected static function parseUrl($url)
131
	{
132
		$components = parse_url($url);
133
134
		return array_merge(array(
135
			'scheme' => null,
136
			'host'   => null,
137
			'port'   => null,
138
			'user'   => null,
139
			'pass'   => null,
140
			'path'   => null,
141
			'query'  => null,
142
			'fragment' => null
143
		), $components ?: array());
144
	}
145
146
	/**
147
	 * Parse the given query string and return its key value pairs.
148
	 *
149
	 * @param string $query
150
	 * @return array
151
	 */
152
	protected static function parseQuery($query)
153
	{
154
		$values = array();
155
		parse_str($query, $values);
156
157
		return $values;
158
	}
159
160
	/**
161
	 * Create a new request with the given URL, method and data.
162
	 *
163
	 * @param string  $url
164
	 * @param string  $method  [optional]
165
	 * @param array   $data    [optional]
166
	 * @param Session $session [optional]
167
	 * @return Request
168
	 */
169
	public static function create($url, $method = 'GET', $data = array(), Session $session = null)
170
	{
171
		$components = static::parseUrl($url);
172
		$data = static::prepareData($data);
173
174
		$data['get'] = array_merge(
175
			$data['get'],
176
			static::parseQuery($components['query'])
177
		);
178
179
		if ($components['host']) {
180
			$data['server']['http_host'] = $components['host'];
181
			$data['server']['server_name'] = $components['host'];
182
		}
183
184
		if ($components['path']) {
185
			$data['server']['path_info'] = $components['path'];
186
			$data['server']['request_uri'] = $components['path'];
187
		}
188
189
		$data['server']['request_method'] = strtoupper($method);
190
191
		if ($components['query']) {
192
			$data['server']['request_uri'] .= '?' . $components['query'];
193
		}
194
195
		$request = new Request(
196
			$data['get'],
197
			$data['post'],
198
			$data['cookie'],
199
			$data['file'],
200
			$data['server'],
201
			$data['header']
202
		);
203
204
		$request->setSession($session);
205
206
		return $request;
207
	}
208
209
210
	/**
211
	 * Extract HTTP request headers from a given set of $_SERVER globals.
212
	 *
213
	 * @param array $server
214
	 * @return array
215
	 */
216
	public static function headersFromGlobals(array $server)
217
	{
218
		$headers = array();
219
220
		foreach ($server as $key => $value) {
221
			if (strpos($key, 'HTTP_') === 0) {
222
				$key = strtolower(substr($key, 5));
223
				$key = ucwords(str_replace('_', ' ', $key));
224
				$key = str_replace(' ', '-', $key);
225
				$headers[$key] = $value;
226
			}
227
		}
228
229
		return $headers;
230
	}
231
232
	/**
233
	 * Create a new request using PHP's super globals.
234
	 *
235
	 * @param \Darya\Http\Session $session [optional]
236
	 * @return \Darya\Http\Request
237
	 */
238
	public static function createFromGlobals(Session $session = null)
239
	{
240
		$request = Request::create($_SERVER['REQUEST_URI'], $_SERVER['REQUEST_METHOD'], array(
241
			'get'    => $_GET,
242
			'post'   => $_POST,
243
			'cookie' => $_COOKIE,
244
			'file'   => $_FILES,
245
			'server' => $_SERVER,
246
			'header' => static::headersFromGlobals($_SERVER)
247
		), $session);
248
249
		return $request;
250
	}
251
252
	/**
253
	 * Instantiate a new request with the given data.
254
	 *
255
	 * Expects request data in the same format as PHP superglobals.
256
	 *
257
	 * @param array $get
258
	 * @param array $post
259
	 * @param array $cookie
260
	 * @param array $file
261
	 * @param array $server
262
	 * @param array $header
263
	 */
264
	public function __construct(array $get, array $post, array $cookie, array $file, array $server, array $header)
265
	{
266
		$this->data = static::prepareData(compact('get', 'post', 'cookie', 'file', 'server', 'header'));
267
	}
268
269
	/**
270
	 * Determine whether this Request has a session interface.
271
	 *
272
	 * @return bool
273
	 */
274
	public function hasSession()
275
	{
276
		return !is_null($this->session);
277
	}
278
279
	/**
280
	 * Set the session interface for the request. Starts the session if it
281
	 * hasn't been already.
282
	 *
283
	 * @param \Darya\Http\Session $session
284
	 */
285
	public function setSession(Session $session = null)
286
	{
287
		if (is_object($session) && !$session->started()) {
288
			$session->start();
289
		}
290
291
		$this->session = $session;
292
		$this->data['session'] = $this->session;
293
	}
294
295
	/**
296
	 * Retrieve request data of the given type using the given key.
297
	 *
298
	 * If $key is not set, all request data of the given type will be returned.
299
	 *
300
	 * If neither $type or $key are set, all request data will be returned.
301
	 *
302
	 * If a $default value is given along with $key, it is returned if $key is
303
	 * not set in the data of the given $type.
304
	 *
305
	 * @param string $type    [optional]
306
	 * @param string $key     [optional]
307
	 * @param mixed  $default [optional]
308
	 * @return mixed
309
	 */
310
	public function data($type = null, $key = null, $default = null)
311
	{
312
		$type = strtolower($type);
0 ignored issues
show
Bug introduced by
It seems like $type can also be of type null; however, parameter $string of strtolower() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

312
		$type = strtolower(/** @scrutinizer ignore-type */ $type);
Loading history...
313
314
		if (isset($this->data[$type])) {
315
			if (static::isCaseInsensitive($type)) {
316
				$key = strtolower($key);
317
			}
318
319
			if (!empty($key)) {
320
				return isset($this->data[$type][$key]) ? $this->data[$type][$key] : $default;
321
			}
322
323
			return $this->data[$type];
324
		}
325
326
		return $this->data;
327
	}
328
329
	/**
330
	 * Dynamically retrieve all request data of the given type.
331
	 *
332
	 * @param string $property
333
	 * @return array
334
	 */
335
	public function __get($property)
336
	{
337
		return $this->data($property);
338
	}
339
340
	/**
341
	 * Dynamically retrieve request data.
342
	 *
343
	 * @param string $method
344
	 * @param array  $arguments
345
	 */
346
	public function __call($method, $arguments)
347
	{
348
		$arguments = array_merge(array($method), array_slice($arguments, 0, 2));
349
350
		return call_user_func_array(array($this, 'data'), $arguments);
351
	}
352
353
	/**
354
	 * Determine whether a given parameter is set in the request's post or get
355
	 * data.
356
	 *
357
	 * @param string $key
358
	 * @return bool
359
	 */
360
	public function has($key)
361
	{
362
		return isset($this->data['get'][$key]) || isset($this->data['post'][$key]);
363
	}
364
365
	/**
366
	 * Retrieve a parameter from either the post or get data of the request,
367
	 * checking post data if the request method is post.
368
	 *
369
	 * @param string $key
370
	 * @return mixed
371
	 */
372
	public function any($key = null)
373
	{
374
		return $this->method('post') && isset($this->data['post'][$key]) ? $this->post($key) : $this->get($key);
375
	}
376
377
	/**
378
	 * Retrieve the URI of the request.
379
	 *
380
	 * @return string
381
	 */
382
	public function uri()
383
	{
384
		return $this->server('request_uri');
385
	}
386
387
	/**
388
	 * Retrieve the hostname of the request.
389
	 *
390
	 * @return string
391
	 */
392
	public function host()
393
	{
394
		return $this->server('server_name') ?: $this->server('server_addr');
395
	}
396
397
	/**
398
	 * Retrieve the path of the request.
399
	 *
400
	 * @return string
401
	 */
402
	public function path()
403
	{
404
		$path = $this->server('path_info');
405
406
		if ($path) {
407
			return $path;
408
		}
409
410
		$components = static::parseUrl($this->uri());
411
412
		return $components['path'];
413
	}
414
415
	/**
416
	 * Retrieve the method of the request or determine whether the method of the
417
	 * request is the same as the one given.
418
	 *
419
	 * @param string $method [optional]
420
	 * @return string|bool
421
	 */
422
	public function method($method = null)
423
	{
424
		$method = strtolower($method);
0 ignored issues
show
Bug introduced by
It seems like $method can also be of type null; however, parameter $string of strtolower() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

424
		$method = strtolower(/** @scrutinizer ignore-type */ $method);
Loading history...
425
		$requestMethod = strtolower($this->server('request_method'));
426
427
		return $method ? $requestMethod == $method : $this->server('request_method');
428
	}
429
430
	/**
431
	 * Retrieve the request body.
432
	 *
433
	 * @return string
434
	 */
435
	public function body()
436
	{
437
		return $this->content();
438
	}
439
440
	/**
441
	 * Retrieve the request body.
442
	 *
443
	 * @return string
444
	 */
445
	public function content()
446
	{
447
		if ($this->content === null) {
448
			$this->content = file_get_contents('php://input');
449
		}
450
451
		return $this->content;
452
	}
453
454
	/**
455
	 * Retrieve the IP address of the client that made the request.
456
	 *
457
	 * @return string
458
	 */
459
	public function ip()
460
	{
461
		return $this->server('remote_addr');
462
	}
463
464
	/**
465
	 * Determine whether this is an ajax Request. This is determined by 'get' or
466
	 * 'post' data having an ajax parameter set or the 'X-Requested-With'
467
	 * parameter having the 'XMLHttpRequest' value.
468
	 *
469
	 * @return bool
470
	 */
471
	public function ajax()
472
	{
473
		return $this->has('ajax')
474
		|| strtolower($this->server('http_x_requested_with')) == 'xmlhttprequest'
475
		|| strtolower($this->header('x-requested-with')) == 'xmlhttprequest';
476
	}
477
478
	/**
479
	 * Flash data with the given key to the session.
480
	 *
481
	 * @param string       $key    Flash data key
482
	 * @param string|array $values A single value or set of values to add
483
	 * @return bool
484
	 */
485
	public function flash($key, $values)
486
	{
487
		if ($this->hasSession()) {
488
			$flash = $this->session->get('flash') ?: array();
489
490
			foreach ((array) $values as $value) {
491
				if (!is_null($value)) {
492
					$flash[$key][] = $value;
493
				}
494
			}
495
496
			$this->session->set('flash', $flash);
497
498
			return true;
499
		}
500
501
		return false;
502
	}
503
504
	/**
505
	 * Retrieve and clear flashed data with the given key from the session. If
506
	 * no key is given, all data is retrieved and cleared.
507
	 *
508
	 * Returns an empty array if this request has no session or flash variables
509
	 * were not found with the given key.
510
	 *
511
	 * @param string $key [optional] Flash data key
512
	 * @return array
513
	 */
514
	public function flashes($key = null)
515
	{
516
		$data = array();
517
518
		if ($this->hasSession()) {
519
			$flash = $this->session->get('flash');
520
521
			if (!empty($key)) {
522
				if (isset($flash[$key])) {
523
					$data = $flash[$key];
524
					unset($flash[$key]);
525
				}
526
			} else {
527
				$data = $flash;
528
				$flash = array();
529
			}
530
531
			$this->session->set('flash', $flash);
532
		}
533
534
		return $data;
535
	}
536
537
	/**
538
	 * Transforms post request data of the form entity[property][n] to the form
539
	 * entity[n][property].
540
	 *
541
	 * @param string $key Entity key (post parameter name)
542
	 * @return array
543
	 */
544
	public function postObjectData($key = null)
545
	{
546
		$post = $this->post($key);
547
		$data = array();
548
549
		if (is_array($post)) {
550
			foreach ($post as $field => $keys) {
551
				foreach ($keys as $key => $value) {
552
					$data[$key][$field] = $value;
553
				}
554
			}
555
		}
556
557
		return $data;
558
	}
559
}
560