Issues (2)

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/Dflydev/FigCookies/SetCookie.php (2 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
declare(strict_types=1);
4
5
namespace Dflydev\FigCookies;
6
7
use DateTime;
8
use DateTimeInterface;
9
use Dflydev\FigCookies\Modifier\SameSite;
10
use function array_shift;
11
use function count;
12
use function explode;
13
use function gmdate;
14
use function implode;
15
use function is_int;
16
use function is_numeric;
17
use function is_string;
18
use function sprintf;
19 31
use function strtolower;
20
use function strtotime;
21 31
use function urlencode;
22 31
23 31
class SetCookie
24
{
25 19
    /** @var string */
26
    private $name;
27 19
    /** @var string|null */
28
    private $value;
29
    /** @var int */
30 3
    private $expires = 0;
31
    /** @var int */
32 3
    private $maxAge = 0;
33
    /** @var string|null */
34
    private $path;
35 2
    /** @var string|null */
36
    private $domain;
37 2
    /** @var bool */
38
    private $secure = false;
39
    /** @var bool */
40
    private $httpOnly = false;
41
    /** @var SameSite|null */
42
    private $sameSite;
43
44
    private function __construct(string $name, ?string $value = null)
45
    {
46
        $this->name  = $name;
47
        $this->value = $value;
48
    }
49
50
    public function getName() : string
51
    {
52
        return $this->name;
53
    }
54
55
    public function getValue() : ?string
56
    {
57
        return $this->value;
58
    }
59
60
    public function getExpires() : int
61
    {
62
        return $this->expires;
63
    }
64
65 29
    public function getMaxAge() : int
66
    {
67 29
        return $this->maxAge;
68
    }
69 29
70
    public function getPath() : ?string
71 29
    {
72
        return $this->path;
73
    }
74 13
75
    public function getDomain() : ?string
76 13
    {
77
        return $this->domain;
78
    }
79
80 13
    public function getSecure() : bool
81 2
    {
82
        return $this->secure;
83
    }
84 11
85
    public function getHttpOnly() : bool
86
    {
87
        return $this->httpOnly;
88 11
    }
89
90
    public function getSameSite() : ?SameSite
91 13
    {
92
        return $this->sameSite;
93 13
    }
94
95 13
    public function withValue(?string $value = null) : self
96
    {
97 13
        $clone = clone($this);
98
99 13
        $clone->value = $value;
100
101
        return $clone;
102 1
    }
103
104 1
    /** @param int|\DateTimeInterface|string|null $expires */
105
    private function resolveExpires($expires = null) : int
106
    {
107 1
        if ($expires === null) {
108
            return 0;
109 1
        }
110
111
        if ($expires instanceof DateTimeInterface) {
112 4
            return $expires->getTimestamp();
113
        }
114 4
115
        if (is_numeric($expires)) {
116 4
            return (int) $expires;
117
        }
118 4
119
        $time = strtotime($expires);
120
121 12
        if (! is_int($time)) {
122
            throw new \InvalidArgumentException(sprintf('Invalid expires "%s" provided', $expires));
123 12
        }
124
125 12
        return $time;
126
    }
127 12
128
    /** @param int|string|\DateTimeInterface|null $expires */
129
    public function withExpires($expires = null) : self
130 7
    {
131
        $expires = $this->resolveExpires($expires);
132 7
133
        $clone = clone($this);
134 7
135
        $clone->expires = $expires;
136 7
137
        return $clone;
138
    }
139 10
140
    public function rememberForever() : self
141 10
    {
142
        return $this->withExpires(new DateTime('+5 years'));
143 10
    }
144
145 10
    public function expire() : self
146
    {
147
        return $this->withExpires(new DateTime('-5 years'));
148 12
    }
149
150 12
    public function withMaxAge(?int $maxAge = null) : self
151
    {
152 12
        $clone = clone($this);
153
154 12
        $clone->maxAge = (int) $maxAge;
155
156
        return $clone;
157 17
    }
158
159
    public function withPath(?string $path = null) : self
160 17
    {
161 17
        $clone = clone($this);
162
163 17
        $clone->path = $path;
164 17
165 17
        return $clone;
166 17
    }
167 17
168 17
    public function withDomain(?string $domain = null) : self
169
    {
170 17
        $clone = clone($this);
171
172
        $clone->domain = $domain;
173 8
174
        return $clone;
175 8
    }
176
177
    public function withSecure(bool $secure = true) : self
178 1
    {
179
        $clone = clone($this);
180 1
181
        $clone->secure = $secure;
182
183 1
        return $clone;
184
    }
185 1
186
    public function withHttpOnly(bool $httpOnly = true) : self
187
    {
188 29
        $clone = clone($this);
189
190 29
        $clone->httpOnly = $httpOnly;
191
192 29
        return $clone;
193
    }
194
195 29
    public function withSameSite(SameSite $sameSite) : self
196
    {
197 29
        $clone = clone($this);
198 29
199 29
        $clone->sameSite = $sameSite;
200
201 29
        return $clone;
202 12
    }
203
204 12
    public function withoutSameSite() : self
205 12
    {
206
        $clone = clone($this);
207 12
208
        $clone->sameSite = null;
209
210 12
        return $clone;
211 11
    }
212 11
213 12
    public function __toString() : string
214 4
    {
215 4
        $cookieStringParts = [
216 12
            urlencode($this->name) . '=' . urlencode((string) $this->value),
217 7
        ];
218 7
219 12
        $cookieStringParts = $this->appendFormattedDomainPartIfSet($cookieStringParts);
220 12
        $cookieStringParts = $this->appendFormattedPathPartIfSet($cookieStringParts);
221 12
        $cookieStringParts = $this->appendFormattedExpiresPartIfSet($cookieStringParts);
222 12
        $cookieStringParts = $this->appendFormattedMaxAgePartIfSet($cookieStringParts);
223 10
        $cookieStringParts = $this->appendFormattedSecurePartIfSet($cookieStringParts);
224 10
        $cookieStringParts = $this->appendFormattedHttpOnlyPartIfSet($cookieStringParts);
225 12
        $cookieStringParts = $this->appendFormattedSameSitePartIfSet($cookieStringParts);
226 12
227 12
        return implode('; ', $cookieStringParts);
228
    }
229
230 12
    public static function create(string $name, ?string $value = null) : self
231
    {
232 29
        return new static($name, $value);
233
    }
234 17
235
    public static function createRememberedForever(string $name, ?string $value = null) : self
236 17
    {
237 7
        return static::create($name, $value)->rememberForever();
238 7
    }
239
240 17
    public static function createExpired(string $name) : self
241
    {
242
        return static::create($name)->expire();
243 17
    }
244
245 17
    public static function fromSetCookieString(string $string) : self
246 8
    {
247 8
        $rawAttributes = StringUtil::splitOnAttributeDelimiter($string);
248
249 17
        $rawAttribute = array_shift($rawAttributes);
250
251
        if (! is_string($rawAttribute)) {
252 17
            throw new \InvalidArgumentException(sprintf(
253
                'The provided cookie string "%s" must have at least one attribute',
254 17
                $string
255 7
            ));
256 7
        }
257
258 17
        list ($cookieName, $cookieValue) = StringUtil::splitCookiePair($rawAttribute);
259
260
        /** @var SetCookie $setCookie */
261 17
        $setCookie = new static($cookieName);
262
263 17
        if ($cookieValue !== null) {
264 4
            $setCookie = $setCookie->withValue($cookieValue);
265 4
        }
266
267 17
        while ($rawAttribute = array_shift($rawAttributes)) {
268
            $rawAttributePair = explode('=', $rawAttribute, 2);
269
270 17
            $attributeKey   = $rawAttributePair[0];
271
            $attributeValue = count($rawAttributePair) > 1 ? $rawAttributePair[1] : null;
272 17
273 6
            $attributeKey = strtolower($attributeKey);
274 6
275
            switch ($attributeKey) {
276 17
                case 'expires':
277
                    $setCookie = $setCookie->withExpires($attributeValue);
278
                    break;
279 17
                case 'max-age':
280
                    $setCookie = $setCookie->withMaxAge((int) $attributeValue);
281 17
                    break;
282 8
                case 'domain':
283 8
                    $setCookie = $setCookie->withDomain($attributeValue);
284
                    break;
285 17
                case 'path':
286
                    $setCookie = $setCookie->withPath($attributeValue);
287
                    break;
288
                case 'secure':
289
                    $setCookie = $setCookie->withSecure(true);
290
                    break;
291
                case 'httponly':
292
                    $setCookie = $setCookie->withHttpOnly(true);
293
                    break;
294
                case 'samesite':
295
                    $setCookie = $setCookie->withSameSite(SameSite::fromString((string) $attributeValue));
296
                    break;
297
            }
298
        }
299
300
        return $setCookie;
301
    }
302
303
    /**
304
     * @param string[] $cookieStringParts
305
     *
306
     * @return string[]
307
     */
308
    private function appendFormattedDomainPartIfSet(array $cookieStringParts) : array
309
    {
310
        if ($this->domain) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->domain of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
311
            $cookieStringParts[] = sprintf('Domain=%s', $this->domain);
312
        }
313
314
        return $cookieStringParts;
315
    }
316
317
    /**
318
     * @param string[] $cookieStringParts
319
     *
320
     * @return string[]
321
     */
322
    private function appendFormattedPathPartIfSet(array $cookieStringParts) : array
323
    {
324
        if ($this->path) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->path of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
325
            $cookieStringParts[] = sprintf('Path=%s', $this->path);
326
        }
327
328
        return $cookieStringParts;
329
    }
330
331
    /**
332
     * @param string[] $cookieStringParts
333
     *
334
     * @return string[]
335
     */
336
    private function appendFormattedExpiresPartIfSet(array $cookieStringParts) : array
337
    {
338
        if ($this->expires) {
339
            $cookieStringParts[] = sprintf('Expires=%s', gmdate('D, d M Y H:i:s T', $this->expires));
340
        }
341
342
        return $cookieStringParts;
343
    }
344
345
    /**
346
     * @param string[] $cookieStringParts
347
     *
348
     * @return string[]
349
     */
350
    private function appendFormattedMaxAgePartIfSet(array $cookieStringParts) : array
351
    {
352
        if ($this->maxAge) {
353
            $cookieStringParts[] = sprintf('Max-Age=%s', $this->maxAge);
354
        }
355
356
        return $cookieStringParts;
357
    }
358
359
    /**
360
     * @param string[] $cookieStringParts
361
     *
362
     * @return string[]
363
     */
364
    private function appendFormattedSecurePartIfSet(array $cookieStringParts) : array
365
    {
366
        if ($this->secure) {
367
            $cookieStringParts[] = 'Secure';
368
        }
369
370
        return $cookieStringParts;
371
    }
372
373
    /**
374
     * @param string[] $cookieStringParts
375
     *
376
     * @return string[]
377
     */
378
    private function appendFormattedHttpOnlyPartIfSet(array $cookieStringParts) : array
379
    {
380
        if ($this->httpOnly) {
381
            $cookieStringParts[] = 'HttpOnly';
382
        }
383
384
        return $cookieStringParts;
385
    }
386
387
    /**
388
     * @param string[] $cookieStringParts
389
     *
390
     * @return string[]
391
     */
392
    private function appendFormattedSameSitePartIfSet(array $cookieStringParts) : array
393
    {
394
        if ($this->sameSite === null) {
395
            return $cookieStringParts;
396
        }
397
398
        $cookieStringParts[] = $this->sameSite->asString();
399
400
        return $cookieStringParts;
401
    }
402
}
403