Completed
Push — master ( 965897...6c88e7 )
by Michael
07:54 queued 04:48
created

ServerRequest::initHeaders()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 2

Importance

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