Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 13 additions & 28 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
FIG Cookies
===========
# FIG Cookies

Managing Cookies for PSR-7 Requests and Responses.

Expand All @@ -15,20 +14,16 @@ Managing Cookies for PSR-7 Requests and Responses.
<br>
[![Join the chat at https://gitter.im/dflydev/dflydev-fig-cookies](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/dflydev/dflydev-fig-cookies?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)


Installation
------------
## Installation

```bash
$> composer require dflydev/fig-cookies
```

## Concepts

Concepts
--------

FIG Cookies tackles two problems, managing **Cookie** *Request* headers and
managing **Set-Cookie** *Response* headers. It does this by way of introducing
FIG Cookies tackles two problems, managing **Cookie** _Request_ headers and
managing **Set-Cookie** _Response_ headers. It does this by way of introducing
a `Cookies` class to manage collections of `Cookie` instances and a
`SetCookies` class to manage collections of `SetCookie` instances.

Expand Down Expand Up @@ -66,9 +61,7 @@ verbose very quickly. In order to get around that, FIG Cookies provides
two facades in an attempt to help simplify things and make the whole process
less verbose.


Basic Usage
-----------
## Basic Usage

The easiest way to start working with FIG Cookies is by using the
`FigRequestCookies` and `FigResponseCookies` classes. They are facades to the
Expand All @@ -81,7 +74,6 @@ process so be wary of using too many of these calls in the same section of
code. In some cases it may be better to work with the primitive FIG Cookies
classes directly rather than using the facades.


### Request Cookies

Requests include cookie information in the **Cookie** request header. The
Expand Down Expand Up @@ -180,6 +172,7 @@ $setCookie = SetCookie::create('lu')
->withSecure(true)
->withHttpOnly(true)
->withSameSite(SameSite::lax())
->withPartitioned()
;
```

Expand Down Expand Up @@ -279,9 +272,7 @@ $setCookie = SetCookie::create('ba')
FigResponseCookies::set($response, $setCookie->expire());
```


FAQ
---
## FAQ

### Do you call `setcookies`?

Expand All @@ -290,15 +281,13 @@ No.
Delivery of the rendered `SetCookie` instances is the responsibility of the
PSR-7 client implementation.


### Do you do anything with sessions?

No.

It would be possible to build session handling using cookies on top of FIG
Cookies but it is out of scope for this package.


### Do you read from `$_COOKIES`?

No.
Expand All @@ -310,18 +299,14 @@ implementations should be including `$_COOKIES` values in the headers
so in that case FIG Cookies may be interacting with `$_COOKIES`
indirectly.


License
-------
## License

MIT, see LICENSE.


Community
---------
## Community

Want to get involved? Here are a few ways:

* Find us in the #dflydev IRC channel on irc.freenode.org.
* Mention [@dflydev](https://twitter.com/dflydev) on Twitter.
* [![Join the chat at https://gitter.im/dflydev/dflydev-fig-cookies](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/dflydev/dflydev-fig-cookies?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
- Find us in the #dflydev IRC channel on irc.freenode.org.
- Mention [@dflydev](https://twitter.com/dflydev) on Twitter.
- [![Join the chat at https://gitter.im/dflydev/dflydev-fig-cookies](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/dflydev/dflydev-fig-cookies?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
37 changes: 37 additions & 0 deletions src/Dflydev/FigCookies/SetCookie.php
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ class SetCookie
private $httpOnly = false;
/** @var SameSite|null */
private $sameSite;
/** @var bool */
private $partitioned = false;

private function __construct(string $name, ?string $value = null)
{
Expand Down Expand Up @@ -94,6 +96,11 @@ public function getSameSite(): ?SameSite
return $this->sameSite;
}

public function getPartitioned(): bool
{
return $this->partitioned;
}

public function withValue(?string $value = null): self
{
$clone = clone $this;
Expand Down Expand Up @@ -212,6 +219,18 @@ public function withoutSameSite(): self
return $clone;
}

public function withPartitioned(bool $partitioned = true): self
{
$clone = clone $this;

$clone->partitioned = $partitioned;
if ($partitioned) {
$clone->secure = true;
}

return $clone;
}

public function __toString(): string
{
$cookieStringParts = [
Expand All @@ -225,6 +244,7 @@ public function __toString(): string
$cookieStringParts = $this->appendFormattedSecurePartIfSet($cookieStringParts);
$cookieStringParts = $this->appendFormattedHttpOnlyPartIfSet($cookieStringParts);
$cookieStringParts = $this->appendFormattedSameSitePartIfSet($cookieStringParts);
$cookieStringParts = $this->appendFormattedPartitionedPartIfSet($cookieStringParts);

return implode('; ', $cookieStringParts);
}
Expand Down Expand Up @@ -301,6 +321,9 @@ public static function fromSetCookieString(string $string): self
case 'samesite':
$setCookie = $setCookie->withSameSite(SameSite::fromString((string) $attributeValue));
break;
case 'partitioned':
$setCookie = $setCookie->withPartitioned();
break;
}
}

Expand Down Expand Up @@ -406,4 +429,18 @@ private function appendFormattedSameSitePartIfSet(array $cookieStringParts): arr

return $cookieStringParts;
}

/**
* @param string[] $cookieStringParts
*
* @return string[]
*/
private function appendFormattedPartitionedPartIfSet(array $cookieStringParts): array
{
if ($this->partitioned) {
$cookieStringParts[] = 'Partitioned';
}

return $cookieStringParts;
}
}
83 changes: 60 additions & 23 deletions tests/Dflydev/FigCookies/SetCookieTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -110,37 +110,50 @@ public function provideParsesFromSetCookieStringData(): array
[
'lu=Rg3vHJZnehYLjVg7qi3bZjzg; Domain=.example.com; Path=/; Expires=Tue, 15 Jan 2013 21:47:38 GMT; Max-Age=500; Secure; HttpOnly',
SetCookie::create('lu')
->withValue('Rg3vHJZnehYLjVg7qi3bZjzg')
->withExpires(new DateTime('Tue, 15-Jan-2013 21:47:38 GMT'))
->withMaxAge(500)
->withPath('/')
->withDomain('.example.com')
->withSecure(true)
->withHttpOnly(true),
->withValue('Rg3vHJZnehYLjVg7qi3bZjzg')
->withExpires(new DateTime('Tue, 15-Jan-2013 21:47:38 GMT'))
->withMaxAge(500)
->withPath('/')
->withDomain('.example.com')
->withSecure(true)
->withHttpOnly(true),
],
[
'lu=Rg3vHJZnehYLjVg7qi3bZjzg; Domain=.example.com; Path=/; Expires=Tue, 15 Jan 2013 21:47:38 GMT; Max-Age=500; Secure; HttpOnly; SameSite=Strict',
SetCookie::create('lu')
->withValue('Rg3vHJZnehYLjVg7qi3bZjzg')
->withExpires(new DateTime('Tue, 15-Jan-2013 21:47:38 GMT'))
->withMaxAge(500)
->withPath('/')
->withDomain('.example.com')
->withSecure(true)
->withHttpOnly(true)
->withSameSite(SameSite::strict()),
->withValue('Rg3vHJZnehYLjVg7qi3bZjzg')
->withExpires(new DateTime('Tue, 15-Jan-2013 21:47:38 GMT'))
->withMaxAge(500)
->withPath('/')
->withDomain('.example.com')
->withSecure(true)
->withHttpOnly(true)
->withSameSite(SameSite::strict()),
],
[
'lu=Rg3vHJZnehYLjVg7qi3bZjzg; Domain=.example.com; Path=/; Expires=Tue, 15 Jan 2013 21:47:38 GMT; Max-Age=500; Secure; HttpOnly; SameSite=Lax',
SetCookie::create('lu')
->withValue('Rg3vHJZnehYLjVg7qi3bZjzg')
->withExpires(new DateTime('Tue, 15-Jan-2013 21:47:38 GMT'))
->withMaxAge(500)
->withPath('/')
->withDomain('.example.com')
->withSecure(true)
->withHttpOnly(true)
->withSameSite(SameSite::lax()),
->withValue('Rg3vHJZnehYLjVg7qi3bZjzg')
->withExpires(new DateTime('Tue, 15-Jan-2013 21:47:38 GMT'))
->withMaxAge(500)
->withPath('/')
->withDomain('.example.com')
->withSecure(true)
->withHttpOnly(true)
->withSameSite(SameSite::lax()),
],
[
'lu=d2ioU4.4KDUjjnCGNut4; Domain=.example.com; Path=/; Expires=Tue, 15 Jan 2013 21:47:38 GMT; Max-Age=500; Secure; HttpOnly; SameSite=Lax; Partitioned',
SetCookie::create('lu')
->withValue('d2ioU4.4KDUjjnCGNut4')
->withExpires(new DateTime('Tue, 15-Jan-2013 21:47:38 GMT'))
->withMaxAge(500)
->withPath('/')
->withDomain('.example.com')
->withSecure(true)
->withHttpOnly(true)
->withSameSite(SameSite::lax())
->withPartitioned(),
],
];
}
Expand Down Expand Up @@ -171,6 +184,30 @@ public function it_creates_long_living_cookies(): void
self::assertGreaterThan($fourYearsFromNow, $setCookie->getExpires());
}

/**
* @test
*/
public function it_creates_partitioned_cookies(): void
{
$setCookie = SetCookie::create('chips_cookie')->withPartitioned();
self::assertEquals(true, $setCookie->getPartitioned());
}

/**
* @test
*/
public function it_does_not_set_partitioned_cookies_by_default(): void
{
$setCookie = SetCookie::create('non_chips_cookie');
self::assertEquals(false, $setCookie->getPartitioned());
}

public function partitioned_cookies_are_secure(): void
{
$setCookie = SetCookie::create('maybe_secure_partitioned_cookie')->withPartitioned();
self::assertEquals(true, $setCookie->getSecure());
}

/** @test */
public function SameSite_modifier_can_be_added_and_removed(): void
{
Expand Down
14 changes: 14 additions & 0 deletions tests/Dflydev/FigCookies/SetCookiesTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,20 @@ public function provideSetCookieStringsAndExpectedSetCookiesData(): array
SetCookie::create('c', 'CCC'),
],
],
[
[
'd=DDD',
'e=EEE; Partitioned',
'f=FFF',
'g=GGG; Partitioned',
],
[
SetCookie::create('d', 'DDD'),
SetCookie::create('e', 'EEE')->withPartitioned(),
SetCookie::create('f', 'FFF'),
SetCookie::create('g', 'GGG')->withPartitioned(),
],
],
];
}

Expand Down