Passed
Push — master ( f2c292...30766b )
by Berend
03:12
created

ServerRequest::getParsedBody()   B

Complexity

Conditions 7
Paths 4

Size

Total Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 7

Importance

Changes 0
Metric Value
dl 0
loc 13
ccs 8
cts 8
cp 1
rs 8.8333
c 0
b 0
f 0
cc 7
nc 4
nop 0
crap 7
1
<?php
2
3
/**
4
 * This file is part of the miBadger package.
5
 *
6
 * @author Michael Webbers <[email protected]>
7
 * @license http://opensource.org/licenses/Apache-2.0 Apache v2 License
8
 */
9
10
namespace miBadger\Http;
11
12
use Psr\Http\Message\ServerRequestInterface;
13
use Psr\Http\Message\StreamInterface;
14
use Psr\Http\Message\UriInterface;
15
16
/**
17
 * The server request class
18
 *
19
 * @see http://www.php-fig.org/psr/psr-7/
20
 * @since 1.0.0
21
 */
22
class ServerRequest extends Request implements ServerRequestInterface
23
{
24
	/** @var array The server parameters. */
25
	private $serverParams;
26
27
	/** @var array The cookie parameters. */
28
	private $cookieParams;
29
30
	/** @var array The query parameters. */
31
	private $queryParams;
32
33
	/** @var array The post parameters. */
34
	private $postParams;
35
36
	/** @var array The files parameters. */
37
	private $filesParams;
38
39
	/** @var array The uploaded files. */
40
	private $uploadedFiles;
41
42
	/** @var null|array|object The parsed body. */
43
	private $parsedBody;
44
45
	/** @var array The attributes. */
46
	private $attributes;
47
48
	/**
49
	 * Construct a Request object with the given method, uri, version, headers & body.
50
	 *
51
	 * @global array $_SERVER The server parameters.
52
	 * @global array $_COOKIE The cookie parameters.
53
	 * @global array $_GET The query parameters.
54
	 * @global array $_POST The post parameters.
55
	 * @global array $_FILES The files parameters.
56
	 *
57
	 * @param string $method = ''
58
	 * @param UriInterface|null $uri = null
59
	 * @param string $version = self::DEFAULT_VERSION
60
	 * @param array $headers = []
61
	 * @param StreamInterface|null $body = null
62
	 */
63 19
	public function __construct($method = '', UriInterface $uri = null, $version = self::DEFAULT_VERSION, array $headers = [], StreamInterface $body = null)
64
	{
65 19
		if ($body === null) {
66 19
			$body = new Stream(fopen('php://input', 'r'));
67
		}
68
69 19
		$this->serverParams = $_SERVER;
70 19
		$this->cookieParams = $_COOKIE;
71 19
		$this->queryParams = $this->initQueryParams($this->serverParams);
72 19
		$this->postParams = $_POST;
73 19
		$this->filesParams = $_FILES;
74 19
		$this->uploadedFiles = $this->initUploadedFiles($this->filesParams);
75 19
		$this->attributes = [];
76
77 19
		parent::__construct($this->initMethod($method), $this->initUri($uri), $version, $this->initHeaders($headers), $body);
78 19
	}
79
80
	/**
81
	 * Initialize the method.
82
	 *
83
	 * @param string $method
84
	 * @return string the method.
85
	 */
86 19
	private function initMethod($method)
87
	{
88 19
		return $method === '' && isset($this->getServerParams()['REQUEST_METHOD']) ? $this->getServerParams()['REQUEST_METHOD'] : $method;
89
	}
90
91
	/**
92
	 * Initialize the URI.
93
	 *
94
	 * @param UriInterface|null $uri
95
	 * @return UriInterface the URI.
96
	 */
97 19
	private function initUri($uri)
98
	{
99 19
		if ($uri !== null) {
100 1
			return $uri;
101
		}
102
103 19
		$scheme = isset($this->getServerParams()['HTTPS']) ? 'https://' : 'http://';
104 19
		$host = isset($this->getServerParams()['HTTP_HOST']) ? $scheme . $this->getServerParams()['HTTP_HOST'] : '';
105 19
		$path = isset($this->getServerParams()['REQUEST_URI']) ? $this->getServerParams()['REQUEST_URI'] : '';
106
107 19
		return new URI($host . $path);
108
	}
109
110
	/**
111
	 * Initialize the headers.
112
	 *
113
	 * @param array $headers
114
	 * @return array the headers.
115
	 */
116 19
	private function initHeaders($headers)
117
	{
118 19
		return $headers ?: getallheaders();
119
	}
120
121
	/**
122
	 * Initialize the headers.
123
	 *
124
	 * @param string $serverParams
125
	 * @return array the headers.
126
	 */
127 19
	private function initQueryParams($serverParams)
128
	{
129 19
		$result = [];
130
131 19
		if (isset($serverParams['REQUEST_URI']) && ($query = parse_url($serverParams['REQUEST_URI'], \PHP_URL_QUERY))) {
132 19
			parse_str($query, $result);
133
		}
134
135 19
		return $result ?? [];
136
	}
137
138
	/**
139
	 * Initialize the uploaded files.
140
	 *
141
	 * @param array $files
142
	 * @return array the uploaded files.
143
	 */
144 19
	private function initUploadedFiles(array $files)
145
	{
146 19
		$result = [];
147
148 19
		foreach ($files as $key => $value) {
149 19
			$result[$key] = $this->parseUploadedFiles($value);
150
		}
151
152 19
		return $result;
153
	}
154
155
	/**
156
	 * Parse uploaded files.
157
	 *
158
	 * @param array $files
159
	 * @return UploadedFile|array uploaded files.
160
	 */
161 19
	private function parseUploadedFiles($files)
162
	{
163
		// Empty
164 19
		$first = reset($files);
165
166
		// Single
167 19
		if (!is_array($first)) {
168 19
			return $this->parseSingleUploadedFiles($files);
169
		}
170
171
		// Multiple
172 19
		if (count(array_filter(array_keys($first), 'is_string')) === 0) {
173 19
			return $this->parseMultipleUploadedFiles($files);
174
		}
175
176
		// Namespace
177 19
		return $this->initUploadedFiles($files);
178
	}
179
180
	/**
181
	 * Parse single uploaded file.
182
	 *
183
	 * @param array $file
184
	 * @return UploadedFile single uploaded file.
185
	 */
186 19
	private function parseSingleUploadedFiles(array $file)
187
	{
188 19
		return new UploadedFile($file['name'], $file['type'], $file['tmp_name'], $file['error'], $file['size']);
189
	}
190
191
	/**
192
	 * Parse multiple uploaded files.
193
	 *
194
	 * @param array $files
195
	 * @return UploadedFiles[] multiple uploaded files.
196
	 */
197 19
	private function parseMultipleUploadedFiles(array $files)
198
	{
199 19
		$count = count($files['name']);
200 19
		$result = [];
201
202 19
		for ($i = 0; $i < $count; $i++) {
203 19
			$result[] = new UploadedFile($files['name'][$i], $files['type'][$i], $files['tmp_name'][$i], $files['error'][$i], $files['size'][$i]);
204
		}
205
206 19
		return $result;
207
	}
208
209
	/**
210
	 * {@inheritdoc}
211
	 */
212 19
	public function getServerParams()
213
	{
214 19
		return $this->serverParams;
215
	}
216
217
	/**
218
	 * {@inheritdoc}
219
	 */
220 1
	public function getCookieParams()
221
	{
222 1
		return $this->cookieParams;
223
	}
224
225
	/**
226
	 * Set the cookie params.
227
	 *
228
	 * @param array $cookieParams
229
	 * @return $this
230
	 */
231 1
	private function setCookieParams(array $cookieParams)
232
	{
233 1
		$this->cookieParams = $cookieParams;
234
235 1
		return $this;
236
	}
237
238
	/**
239
	 * {@inheritdoc}
240
	 */
241 1
	public function withCookieParams(array $cookieParams)
242
	{
243 1
		$result = clone $this;
244
245 1
		return $result->setCookieParams($cookieParams);
246
	}
247
248
	/**
249
	 * {@inheritdoc}
250
	 */
251 3
	public function getQueryParams()
252
	{
253 3
		return $this->queryParams;
254
	}
255
256
	/**
257
	 * Set the query params.
258
	 *
259
	 * @param array $queryParams
260
	 * @return $this
261
	 */
262 1
	private function setQueryParams(array $queryParams)
263
	{
264 1
		$this->queryParams = $queryParams;
265
266 1
		return $this;
267
	}
268
269
	/**
270
	 * {@inheritdoc}
271
	 */
272 1
	public function withQueryParams(array $queryParams)
273
	{
274 1
		$result = clone $this;
275
276 1
		return $result->setQueryParams($queryParams);
277
	}
278
279
	/**
280
	 * {@inheritdoc}
281
	 */
282 2
	public function getUploadedFiles()
283
	{
284 2
		return $this->uploadedFiles;
285
	}
286
287
	/**
288
	 * Set the uploaded files.
289
	 *
290
	 * @param array $uploadedFiles
291
	 * @return $this
292
	 */
293 1
	private function setUploadedFiles(array $uploadedFiles)
294
	{
295 1
		$this->uploadedFiles = $uploadedFiles;
296
297 1
		return $this;
298
	}
299
300
	/**
301
	 * {@inheritdoc}
302
	 */
303 1
	public function withUploadedFiles(array $uploadedFiles)
304
	{
305 1
		$result = clone $this;
306
307 1
		return $result->setUploadedFiles($uploadedFiles);
308
	}
309
310
	/**
311
	 * {@inheritdoc}
312
	 */
313 6
	public function getParsedBody()
314
	{
315 6
		if ($this->parsedBody !== null) {
316 1
			return $this->parsedBody;
317
		}
318 5
		if ($this->getMethod() === 'POST' && ($this->hasContentType('application/x-www-form-urlencoded') || $this->hasContentType('multipart/form-data'))) {
319 3
			return $this->postParams;
320
		}
321 2
		if ($this->hasContentType('application/json') || $this->hasContentType('text/plain')) {
322 1
			return json_decode((string) $this->getBody(), true);
323
		}
324 1
		return null;
325
	}
326
327
328
	/**
329
	 * Checks if a content type header exists with the given content type.
330
	 *
331
	 * @param string $contentType
332
	 * @return bool true if a content type header exists with the given content type.
333
	 */
334 5
	private function hasContentType($contentType)
335
	{
336 5
		foreach ($this->getHeader('Content-Type') as $key => $value) {
337 4
			if (mb_substr($value, 0, strlen($contentType)) == $contentType) {
338 4
				return true;
339
			}
340
		}
341
342 2
		return false;
343
	}
344
345
	/**
346
	 * Set the parsed body.
347
	 *
348
	 * @param null|array|object $parsedBody
349
	 * @return $this
350
	 */
351 1
	private function setParsedBody($parsedBody)
352
	{
353 1
		$this->parsedBody = $parsedBody;
354
355 1
		return $this;
356
	}
357
358
	/**
359
	 * {@inheritdoc}
360
	 */
361 1
	public function withParsedBody($parsedBody)
362
	{
363 1
		$result = clone $this;
364
365 1
		return $result->setParsedBody($parsedBody);
366
	}
367
368
	/**
369
	 * {@inheritdoc}
370
	 */
371 1
	public function getAttributes()
372
	{
373 1
		return $this->attributes;
374
	}
375
376
	/**
377
	 * {@inheritdoc}
378
	 */
379 3
	public function getAttribute($name, $default = null)
380
	{
381 3
		return isset($this->attributes[$name]) ? $this->attributes[$name] : $default;
382
	}
383
384
	/**
385
	 * Set the attribute.
386
	 *
387
	 * @param string $name
388
	 * @param mixed $value
389
	 * @return $this
390
	 */
391 1
	private function setAttribute($name, $value)
392
	{
393 1
		$this->attributes[$name] = $value;
394
395 1
		return $this;
396
	}
397
398
	/**
399
	 * {@inheritdoc}
400
	 */
401 1
	public function withAttribute($name, $value)
402
	{
403 1
		$result = clone $this;
404
405 1
		return $result->setAttribute($name, $value);
406
	}
407
408
	/**
409
	 * Remove the attribute.
410
	 *
411
	 * @param string $name
412
	 * @return $this
413
	 */
414 1
	private function removeAttribute($name)
415
	{
416 1
		unset($this->attributes[$name]);
417
418 1
		return $this;
419
	}
420
421
	/**
422
	 * {@inheritdoc}
423
	 */
424 1
	public function withoutAttribute($name)
425
	{
426 1
		$result = clone $this;
427
428 1
		return $result->removeAttribute($name);
429
	}
430
}
431