Issues (23)

Security Analysis    no request data  

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

src/Http/Request.php (3 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
/**
3
 * Veto.
4
 * PHP Microframework.
5
 *
6
 * @author Damien Walsh <[email protected]>
7
 * @copyright Damien Walsh 2013-2014
8
 * @version 0.1
9
 * @package veto
10
 */
11
namespace Veto\Http;
12
13
use Psr\Http\Message\RequestInterface;
14
use Psr\Http\Message\StreamInterface;
15
use Psr\Http\Message\UriInterface;
16
use Veto\Collection\Bag;
17
18
/**
19
 * Request
20
 * @since 0.1
21
 */
22
class Request implements RequestInterface
23
{
24
    /**
25
     * The HTTP protocol version
26
     *
27
     * @var string
28
     */
29
    protected $protocolVersion;
30
31
    /**
32
     * The HTTP method
33
     *
34
     * @var string
35
     */
36
    protected $method;
37
38
    /**
39
     * The URI
40
     *
41
     * @var UriInterface
42
     */
43
    protected $uri;
44
45
    /**
46
     * The target of the request
47
     *
48
     * @var string
49
     */
50
    protected $requestTarget;
51
52
    /**
53
     * The query string parameters
54
     *
55
     * @var Bag
56
     */
57
    protected $queryParams;
58
59
    /**
60
     * The server environment variables
61
     *
62
     * @var Bag
63
     */
64
    protected $serverParams;
65
66
    /**
67
     * The cookies
68
     *
69
     * @var Bag
70
     */
71
    protected $cookies;
72
73
    /**
74
     * The headers
75
     *
76
     * @var HeaderBag
77
     */
78
    protected $headers;
79
80
    /**
81
     * The request parameters
82
     *
83
     * @var Bag
84
     */
85
    protected $parameters;
86
87
    /**
88
     * The request body
89
     *
90
     * @var StreamInterface
91
     */
92
    protected $body;
93
94
    /**
95
     * Create new HTTP request
96
     *
97
     * @param string $method The request method
98
     * @param UriInterface $uri The request URI object
99
     * @param HeaderBag $headers The request headers collection
100
     * @param Bag $cookies The request cookies collection
101
     * @param Bag $serverParams The server environment variables
102
     * @param StreamInterface $body The request body object
103
     */
104
    public function __construct(
105
        $method,
106
        UriInterface $uri,
107
        HeaderBag $headers,
108
        Bag $cookies,
109
        Bag $serverParams,
110
        StreamInterface $body
111
    ) {
112
        $this->method = $method;
113
        $this->uri = $uri;
114
        $this->headers = $headers;
115
        $this->cookies = $cookies;
116
        $this->serverParams = $serverParams;
117
        $this->parameters = new Bag();
118
        $this->queryParams = new Bag();
119
        $this->body = $body;
120
    }
121
122
    /**
123
     * Deep-copy any associated objects when cloning.
124
     */
125
    public function __clone()
126
    {
127
        $this->headers = clone $this->headers;
128
        $this->cookies = clone $this->cookies;
129
        $this->parameters = clone $this->parameters;
130
        $this->body = clone $this->body;
131
        $this->queryParams = clone $this->queryParams;
132
        $this->serverParams = clone $this->serverParams;
133
        $this->uri = clone $this->uri;
134
    }
135
136
    /**
137
     * Helper method to create a new request based on the provided environment Bag.
138
     *
139
     * @param Bag $environment
140
     * @return Request
141
     */
142
    public static function createFromEnvironment(Bag $environment)
143
    {
144
        $method = $environment->get('REQUEST_METHOD');
145
        $uri = Uri::createFromEnvironment($environment);
146
        $headers = HeaderBag::createFromEnvironment($environment);
147
        $body = new MessageBody(fopen('php://input', 'r'));
148
149
        return new self($method, $uri, $headers, new Bag(), $environment, $body);
150
    }
151
152
    /**
153
     * Retrieves the HTTP protocol version as a string.
154
     *
155
     * The string MUST contain only the HTTP version number (e.g., "1.1", "1.0").
156
     *
157
     * @return string HTTP protocol version.
158
     */
159
    public function getProtocolVersion()
160
    {
161
        return $this->protocolVersion;
162
    }
163
164
    /**
165
     * Create a new instance with the specified HTTP protocol version.
166
     *
167
     * The version string MUST contain only the HTTP version number (e.g.,
168
     * "1.1", "1.0").
169
     *
170
     * This method MUST be implemented in such a way as to retain the
171
     * immutability of the message, and MUST return a new instance that has the
172
     * new protocol version.
173
     *
174
     * @param string $version HTTP protocol version
175
     * @return self
176
     */
177
    public function withProtocolVersion($version)
178
    {
179
        $clone = clone $this;
180
        $clone->protocolVersion = $version;
181
182
        return $clone;
183
    }
184
185
    /**
186
     * Checks if a header exists by the given case-insensitive name.
187
     *
188
     * @param string $name Case-insensitive header field name.
189
     * @return bool Returns true if any header names match the given header
190
     *     name using a case-insensitive string comparison. Returns false if
191
     *     no matching header name is found in the message.
192
     */
193
    public function hasHeader($name)
194
    {
195
        return $this->headers->has($name);
196
    }
197
198
    /**
199
     * Create a new instance with the provided header, replacing any existing
200
     * values of any headers with the same case-insensitive name.
201
     *
202
     * While header names are case-insensitive, the casing of the header will
203
     * be preserved by this function, and returned from getHeaders().
204
     *
205
     * This method MUST be implemented in such a way as to retain the
206
     * immutability of the message, and MUST return a new instance that has the
207
     * new and/or updated header and value.
208
     *
209
     * @param string $name Case-insensitive header field name.
210
     * @param string|string[] $value Header value(s).
211
     * @return self
212
     * @throws \InvalidArgumentException for invalid header names or values.
213
     */
214 View Code Duplication
    public function withHeader($name, $value)
0 ignored issues
show
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...
215
    {
216
        $clone = clone $this;
217
        $clone->headers = new HeaderBag();
218
        $clone->headers->add($name, $value);
219
220
        return $clone;
221
    }
222
223
    /**
224
     * Creates a new instance, with the specified header appended with the
225
     * given value.
226
     *
227
     * Existing values for the specified header will be maintained. The new
228
     * value(s) will be appended to the existing list. If the header did not
229
     * exist previously, it will be added.
230
     *
231
     * This method MUST be implemented in such a way as to retain the
232
     * immutability of the message, and MUST return a new instance that has the
233
     * new header and/or value.
234
     *
235
     * @param string $name Case-insensitive header field name to add.
236
     * @param string|string[] $value Header value(s).
237
     * @return self
238
     * @throws \InvalidArgumentException for invalid header names or values.
239
     */
240
    public function withAddedHeader($name, $value)
241
    {
242
        $clone = clone $this;
243
        $clone->headers->add($name, $value);
244
245
        return $clone;
246
    }
247
248
    /**
249
     * Creates a new instance, without the specified header.
250
     *
251
     * Header resolution MUST be done without case-sensitivity.
252
     *
253
     * This method MUST be implemented in such a way as to retain the
254
     * immutability of the message, and MUST return a new instance that removes
255
     * the named header.
256
     *
257
     * @param string $name Case-insensitive header field name to remove.
258
     * @return self
259
     */
260
    public function withoutHeader($name)
261
    {
262
        $clone = clone $this;
263
        $clone->headers->remove($name);
264
265
        return $clone;
266
    }
267
268
    /**
269
     * Gets the body of the message.
270
     *
271
     * @return StreamInterface Returns the body as a stream.
272
     */
273
    public function getBody()
274
    {
275
        return $this->body;
276
    }
277
278
    /**
279
     * Create a new instance, with the specified message body.
280
     *
281
     * The body MUST be a StreamInterface object.
282
     *
283
     * This method MUST be implemented in such a way as to retain the
284
     * immutability of the message, and MUST return a new instance that has the
285
     * new body stream.
286
     *
287
     * @param StreamInterface $body Body.
288
     * @return self
289
     * @throws \InvalidArgumentException When the body is not valid.
290
     */
291
    public function withBody(StreamInterface $body)
292
    {
293
        $clone = clone $this;
294
        $clone->body = $body;
295
296
        return $clone;
297
    }
298
299
    /**
300
     * Extends MessageInterface::getHeaders() to provide request-specific
301
     * behavior.
302
     *
303
     * Retrieves all message headers.
304
     *
305
     * This method acts exactly like MessageInterface::getHeaders(), with one
306
     * behavioral change: if the Host header has not been previously set, the
307
     * method MUST attempt to pull the host segment of the composed URI, if
308
     * present.
309
     *
310
     * @see MessageInterface::getHeaders()
311
     * @see UriInterface::getHost()
312
     * @return array Returns an associative array of the message's headers. Each
313
     *     key MUST be a header name, and each value MUST be an array of strings.
314
     */
315
    public function getHeaders()
316
    {
317
        return $this->headers->all();
318
    }
319
320
    /**
321
     * Extends MessageInterface::getHeader() to provide request-specific
322
     * behavior.
323
     *
324
     * This method acts exactly like MessageInterface::getHeader(), with
325
     * one behavioral change: if the Host header is requested, but has
326
     * not been previously set, the method MUST attempt to pull the host
327
     * segment of the composed URI, if present.
328
     *
329
     * @see MessageInterface::getHeader()
330
     * @see UriInterface::getHost()
331
     * @param string $name Case-insensitive header field name.
332
     * @return string
333
     */
334
    public function getHeader($name)
335
    {
336
        return implode(',', $this->headers->get($name));
0 ignored issues
show
Bug Best Practice introduced by
The return type of return implode(',', $this->headers->get($name)); (string) is incompatible with the return type declared by the interface Psr\Http\Message\RequestInterface::getHeader 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...
337
    }
338
339
    /**
340
     * Extends MessageInterface::getHeaderLines() to provide request-specific
341
     * behavior.
342
     *
343
     * This method returns all of the header values of the given
344
     * case-insensitive header name as a string concatenated together using
345
     * a comma.
346
     *
347
     * This method acts exactly like MessageInterface::getHeaderLines(), with
348
     * one behavioral change: if the Host header is requested, but has
349
     * not been previously set, the method MUST attempt to pull the host
350
     * component of the composed URI, if present.
351
     *
352
     * @see MessageInterface::getHeaderLine()
353
     * @see UriInterface::getHost()
354
     * @param string $name Case-insensitive header field name.
355
     * @return string|null A string of values as provided for the given header
356
     *    concatenated together using a comma. If the header does not appear in
357
     *    the message, this method MUST return a null value.
358
     */
359
    public function getHeaderLine($name)
360
    {
361
        return $this->headers->get($name);
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $this->headers->get($name); (array) is incompatible with the return type declared by the interface Psr\Http\Message\RequestInterface::getHeaderLine of type string|null.

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...
362
    }
363
364
    /**
365
     * Retrieves the message's request target.
366
     *
367
     * Retrieves the message's request-target either as it will appear (for
368
     * clients), as it appeared at request (for servers), or as it was
369
     * specified for the instance (see withRequestTarget()).
370
     *
371
     * In most cases, this will be the origin-form of the composed URI,
372
     * unless a value was provided to the concrete implementation (see
373
     * withRequestTarget() below).
374
     *
375
     * If no URI is available, and no request-target has been specifically
376
     * provided, this method MUST return the string "/".
377
     *
378
     * @return string
379
     */
380
    public function getRequestTarget()
381
    {
382
        if ($this->requestTarget) {
383
            return $this->requestTarget;
384
        }
385
386
        if ($this->uri === null) {
387
            return '/';
388
        }
389
390
        $path = $this->uri->getPath();
391
        $query = $this->uri->getQuery();
392
        if ($query) {
393
            $path .= '?' . $query;
394
        }
395
396
        $this->requestTarget = $path;
397
398
        return $this->requestTarget;
399
    }
400
401
    /**
402
     * Create a new instance with a specific request-target.
403
     *
404
     * If the request needs a non-origin-form request-target — e.g., for
405
     * specifying an absolute-form, authority-form, or asterisk-form —
406
     * this method may be used to create an instance with the specified
407
     * request-target, verbatim.
408
     *
409
     * This method MUST be implemented in such a way as to retain the
410
     * immutability of the message, and MUST return a new instance that has the
411
     * changed request target.
412
     *
413
     * @link http://tools.ietf.org/html/rfc7230#section-2.7 (for the various
414
     *     request-target forms allowed in request messages)
415
     * @param mixed $requestTarget
416
     * @return self
417
     */
418
    public function withRequestTarget($requestTarget)
419
    {
420
        if (preg_match('#\s#', $requestTarget)) {
421
            throw new \InvalidArgumentException(
422
                'Invalid request target provided; must be a string and cannot contain whitespace'
423
            );
424
        }
425
426
        $clone = clone $this;
427
        $clone->requestTarget = $requestTarget;
428
429
        return $clone;
430
    }
431
432
    /**
433
     * Retrieves the HTTP method of the request.
434
     *
435
     * @return string Returns the request method.
436
     */
437
    public function getMethod()
438
    {
439
        $overrideMethod = $this->getHeader('X-Http-Method-Override');
440
441
        return $overrideMethod ? $overrideMethod : $this->method;
442
    }
443
444
    /**
445
     * Create a new instance with the provided HTTP method.
446
     *
447
     * While HTTP method names are typically all uppercase characters, HTTP
448
     * method names are case-sensitive and thus implementations SHOULD NOT
449
     * modify the given string.
450
     *
451
     * This method MUST be implemented in such a way as to retain the
452
     * immutability of the message, and MUST return a new instance that has the
453
     * changed request method.
454
     *
455
     * @param string $method Case-insensitive method.
456
     * @return self
457
     * @throws \InvalidArgumentException for invalid HTTP methods.
458
     */
459
    public function withMethod($method)
460
    {
461
        $clone = clone $this;
462
        $clone->method = $method;
463
464
        return $clone;
465
    }
466
467
    /**
468
     * Retrieves the URI instance.
469
     *
470
     * This method MUST return a UriInterface instance.
471
     *
472
     * @link http://tools.ietf.org/html/rfc3986#section-4.3
473
     * @return UriInterface Returns a UriInterface instance
474
     *     representing the URI of the request, if any.
475
     */
476
    public function getUri()
477
    {
478
        return $this->uri;
479
    }
480
481
    /**
482
     * Returns an instance with the provided URI.
483
     *
484
     * This method will update the Host header of the returned request by
485
     * default if the URI contains a host component. If the URI does not
486
     * contain a host component, any pre-existing Host header will be carried
487
     * over to the returned request.
488
     *
489
     * You can opt-in to preserving the original state of the Host header by
490
     * setting `$preserveHost` to `true`. When `$preserveHost` is set to
491
     * `true`, the returned request will not update the Host header of the
492
     * returned message -- even if the message contains no Host header. This
493
     * means that a call to `getHeader('Host')` on the original request MUST
494
     * equal the return value of a call to `getHeader('Host')` on the returned
495
     * request.
496
     *
497
     * This method MUST be implemented in such a way as to retain the
498
     * immutability of the message, and MUST return an instance that has the
499
     * new UriInterface instance.
500
     *
501
     * @link http://tools.ietf.org/html/rfc3986#section-4.3
502
     * @param UriInterface $uri New request URI to use.
503
     * @param bool $preserveHost Preserve the original state of the Host header.
504
     * @return self
505
     */
506
    public function withUri(UriInterface $uri, $preserveHost = false)
507
    {
508
        // Preserve previous host information if omitted from the new uri or if $preserveHost is true
509
        if (!strlen($uri->getHost()) || $preserveHost) {
510
            $uri = new Uri(
511
                $uri->getScheme(),
512
                $uri->getHost(),
513
                $uri->getPort(),
514
                $uri->getPath(),
515
                $uri->getQuery(),
516
                $uri->getFragment(),
517
                $uri->getUserInfo()
518
            );
519
        }
520
521
        $clone = clone $this;
522
        $clone->uri = $uri;
523
524
        return $clone;
525
    }
526
527
    /**
528
     * Get the Query String parameters.
529
     *
530
     * @return Bag
531
     */
532
    public function getQueryParams()
533
    {
534
        return $this->queryParams;
535
    }
536
537
    /**
538
     * Retrieve all parameters for this request.
539
     *
540
     * @return array
541
     */
542
    public function getParameters()
543
    {
544
        return $this->parameters->all();
545
    }
546
547
    /**
548
     * Get a parameter of this request.
549
     *
550
     * @param $key
551
     * @param null $default
552
     * @return mixed|null
553
     */
554
    public function getParameter($key, $default = null)
555
    {
556
        return $this->parameters->get($key, $default);
557
    }
558
559
    /**
560
     * Check if the request has a parameter with the specified key.
561
     *
562
     * @param $key
563
     * @return bool
564
     */
565
    public function hasParameter($key)
566
    {
567
        return $this->parameters->has($key);
568
    }
569
570
    /**
571
     * Return a new Request instance with an additional specified parameter.
572
     *
573
     * @param $key
574
     * @param $value
575
     * @return Request
576
     */
577
    public function withParameter($key, $value)
578
    {
579
        $clone = clone $this;
580
        $clone->parameters->add($key, $value);
581
582
        return $clone;
583
    }
584
585
    /**
586
     * Return a new Request instance with a replaced, new set of parameters.
587
     *
588
     * @param $parameters
589
     * @return Request
590
     */
591
    public function withParameters($parameters)
592
    {
593
        $clone = clone $this;
594
        $clone->parameters = new Bag($parameters);
595
596
        return $clone;
597
    }
598
599
    /**
600
     * Return a new Request instance without the specified parameter.
601
     *
602
     * @param $key
603
     * @return Request
604
     */
605
    public function withoutParameter($key)
606
    {
607
        $clone = clone $this;
608
        $clone->parameters->remove($key);
609
610
        return $clone;
611
    }
612
}
613