Skip to content
This repository was archived by the owner on Dec 31, 2022. It is now read-only.

Commit 953b4e1

Browse files
authored
Merge pull request #29 from sunrise-php/release/v2.2.0
v3.0.0
2 parents 171d170 + 6e18f58 commit 953b4e1

83 files changed

Lines changed: 2724 additions & 5142 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.circleci/config.yml

Lines changed: 0 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -4,30 +4,6 @@
44
#
55
version: 2
66
jobs:
7-
php71:
8-
docker:
9-
- image: cimg/php:7.1
10-
steps:
11-
- checkout
12-
- run: php -v
13-
- run: composer install --no-interaction
14-
- run: XDEBUG_MODE=coverage php vendor/bin/phpunit --coverage-text
15-
php72:
16-
docker:
17-
- image: cimg/php:7.2
18-
steps:
19-
- checkout
20-
- run: php -v
21-
- run: composer install --no-interaction
22-
- run: XDEBUG_MODE=coverage php vendor/bin/phpunit --coverage-text
23-
php73:
24-
docker:
25-
- image: cimg/php:7.3
26-
steps:
27-
- checkout
28-
- run: php -v
29-
- run: composer install --no-interaction
30-
- run: XDEBUG_MODE=coverage php vendor/bin/phpunit --coverage-text
317
php74:
328
docker:
339
- image: cimg/php:7.4
@@ -56,9 +32,6 @@ workflows:
5632
version: 2
5733
build:
5834
jobs:
59-
- php71
60-
- php72
61-
- php73
6235
- php74
6336
- php80
6437
- php81

.scrutinizer.yml

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,30 @@
11
build:
2-
environment:
3-
php:
4-
version: '8.0'
2+
image: default-bionic
53
nodes:
64
analysis:
5+
environment:
6+
php: 8.1
77
tests:
88
override:
99
- php-scrutinizer-run
1010
coverage:
11+
environment:
12+
php: 8.1
1113
tests:
1214
override:
1315
- command: XDEBUG_MODE=coverage php vendor/bin/phpunit --coverage-clover coverage.xml
1416
coverage:
1517
file: coverage.xml
1618
format: clover
19+
php80:
20+
environment:
21+
php: 8.0
22+
tests:
23+
override:
24+
- command: php vendor/bin/phpunit
25+
php74:
26+
environment:
27+
php: 7.4
28+
tests:
29+
override:
30+
- command: php vendor/bin/phpunit

composer.json

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,8 @@
77
"fenric",
88
"sunrise",
99
"http",
10-
"header",
11-
"kit",
12-
"psr-7",
13-
"php7",
14-
"php8"
10+
"message",
11+
"header"
1512
],
1613
"authors": [
1714
{
@@ -21,12 +18,11 @@
2118
}
2219
],
2320
"require": {
24-
"php": "^7.1|^8.0",
25-
"sunrise/http-header": "^2.0",
26-
"sunrise/http-header-collection": "^2.0"
21+
"php": ">=7.4",
22+
"sunrise/http-header": "^2.1"
2723
},
2824
"require-dev": {
29-
"phpunit/phpunit": "7.5.20|9.5.0",
25+
"phpunit/phpunit": "~9.5.0",
3026
"sunrise/coding-standard": "1.0.0",
3127
"sunrise/uri": "~1.2.0"
3228
},

src/AbstractHeader.php

Lines changed: 226 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -15,42 +15,253 @@
1515
* Import classes
1616
*/
1717
use ArrayIterator;
18-
use IteratorAggregate;
18+
use DateTime;
19+
use DateTimeImmutable;
20+
use DateTimeInterface;
21+
use DateTimeZone;
22+
use InvalidArgumentException;
1923
use Traversable;
2024

2125
/**
2226
* Import functions
2327
*/
28+
use function gettype;
29+
use function is_int;
30+
use function is_string;
31+
use function preg_match;
2432
use function sprintf;
2533

2634
/**
2735
* AbstractHeader
28-
*
29-
* @template-implements IteratorAggregate<int, string>
3036
*/
31-
abstract class AbstractHeader implements HeaderInterface, IteratorAggregate
37+
abstract class AbstractHeader implements HeaderInterface
3238
{
3339

3440
/**
3541
* {@inheritdoc}
3642
*/
37-
public function __toString() : string
43+
final public function __toString() : string
3844
{
39-
return sprintf(
40-
'%s: %s',
41-
$this->getFieldName(),
42-
$this->getFieldValue()
43-
);
45+
return sprintf('%s: %s', $this->getFieldName(), $this->getFieldValue());
4446
}
4547

4648
/**
4749
* {@inheritdoc}
4850
*/
49-
public function getIterator() : Traversable
51+
final public function getIterator() : Traversable
52+
{
53+
return new ArrayIterator([$this->getFieldName(), $this->getFieldValue()]);
54+
}
55+
56+
/**
57+
* Gets Regular Expression for a token validation
58+
*
59+
* @return string
60+
*/
61+
protected function getTokenValidationRegularExpression() : string
62+
{
63+
return HeaderInterface::RFC7230_TOKEN;
64+
}
65+
66+
/**
67+
* Gets Regular Expression for a parameter name validation
68+
*
69+
* @return string
70+
*/
71+
protected function getParameterNameValidationRegularExpression() : string
72+
{
73+
return HeaderInterface::RFC7230_TOKEN;
74+
}
75+
76+
/**
77+
* Gets Regular Expression for a parameter value validation
78+
*
79+
* @return string
80+
*/
81+
protected function getParameterValueValidationRegularExpression() : string
82+
{
83+
return HeaderInterface::RFC7230_QUOTED_STRING;
84+
}
85+
86+
/**
87+
* Checks if the given string is token
88+
*
89+
* @param string $token
90+
*
91+
* @return bool
92+
*/
93+
final protected function isToken(string $token) : bool
94+
{
95+
return preg_match($this->getTokenValidationRegularExpression(), $token) === 1;
96+
}
97+
98+
/**
99+
* Validates the given token(s)
100+
*
101+
* @param string ...$tokens
102+
*
103+
* @return void
104+
*
105+
* @throws InvalidArgumentException
106+
* If one of the tokens isn't valid.
107+
*/
108+
final protected function validateToken(string ...$tokens) : void
109+
{
110+
foreach ($tokens as $token) {
111+
if (!$this->isToken($token)) {
112+
throw new InvalidArgumentException(sprintf(
113+
'The value "%2$s" for the header "%1$s" is not valid',
114+
$this->getFieldName(),
115+
$token
116+
));
117+
}
118+
}
119+
}
120+
121+
/**
122+
* Validates the given quoted string(s)
123+
*
124+
* @param string ...$quotedStrings
125+
*
126+
* @return void
127+
*
128+
* @throws InvalidArgumentException
129+
* If one of the quoted strings isn't valid.
130+
*/
131+
final protected function validateQuotedString(string ...$quotedStrings) : void
132+
{
133+
foreach ($quotedStrings as $quotedString) {
134+
if (!preg_match(HeaderInterface::RFC7230_QUOTED_STRING, $quotedString)) {
135+
throw new InvalidArgumentException(sprintf(
136+
'The value "%2$s" for the header "%1$s" is not valid',
137+
$this->getFieldName(),
138+
$quotedString
139+
));
140+
}
141+
}
142+
}
143+
144+
/**
145+
* Validates and normalizes the given parameters
146+
*
147+
* @param array<array-key, mixed> $parameters
148+
*
149+
* @return array
150+
*
151+
* @throws InvalidArgumentException
152+
* If one of the parameters isn't valid.
153+
*/
154+
final protected function validateParameters(array $parameters) : array
155+
{
156+
foreach ($parameters as $name => $value) {
157+
// e.g. Cache-Control: max-age=31536000
158+
if (is_int($value)) {
159+
$parameters[$name] = $value = (string) $value;
160+
}
161+
162+
if (!is_string($name) || !preg_match($this->getParameterNameValidationRegularExpression(), $name)) {
163+
throw new InvalidArgumentException(sprintf(
164+
'The parameter-name "%2$s" for the header "%1$s" is not valid',
165+
$this->getFieldName(),
166+
(is_string($name) ? $name : ('<' . gettype($name) . '>'))
167+
));
168+
}
169+
170+
/** @psalm-suppress MixedArgument */
171+
if (!is_string($value) || !preg_match($this->getParameterValueValidationRegularExpression(), $value)) {
172+
throw new InvalidArgumentException(sprintf(
173+
'The parameter-value "%2$s" for the header "%1$s" is not valid',
174+
$this->getFieldName(),
175+
(is_string($value) ? $value : ('<' . gettype($value) . '>'))
176+
));
177+
}
178+
}
179+
180+
return $parameters;
181+
}
182+
183+
/**
184+
* Validates the given header field-name
185+
*
186+
* @param mixed $fieldName
187+
*
188+
* @return void
189+
*
190+
* @throws InvalidArgumentException
191+
* If the header field-name isn't valid.
192+
*/
193+
final protected function validateFieldName($fieldName) : void
194+
{
195+
if (!is_string($fieldName)) {
196+
throw new InvalidArgumentException('Header field-name must be a string');
197+
}
198+
199+
if (!preg_match(HeaderInterface::RFC7230_TOKEN, $fieldName)) {
200+
throw new InvalidArgumentException('Header field-name is invalid');
201+
}
202+
}
203+
204+
/**
205+
* Validates the given header field-value
206+
*
207+
* @param mixed $fieldValue
208+
*
209+
* @return void
210+
*
211+
* @throws InvalidArgumentException
212+
* If the header field-value isn't valid.
213+
*/
214+
final protected function validateFieldValue($fieldValue) : void
215+
{
216+
if (!is_string($fieldValue)) {
217+
throw new InvalidArgumentException('Header field-value must be a string');
218+
}
219+
220+
// a header's field value can be empty...
221+
if ($fieldValue === '') {
222+
return;
223+
}
224+
225+
if (!preg_match(HeaderInterface::RFC7230_FIELD_VALUE, $fieldValue)) {
226+
throw new InvalidArgumentException('Header field-value is invalid');
227+
}
228+
}
229+
230+
/**
231+
* Normalizes the given date-time object
232+
*
233+
* @param T $dateTime
234+
*
235+
* @return T
236+
*
237+
* @template T as DateTimeInterface
238+
*/
239+
final protected function normalizeDateTime(DateTimeInterface $dateTime) : DateTimeInterface
240+
{
241+
if ($dateTime instanceof DateTime) {
242+
return (clone $dateTime)->setTimezone(new DateTimeZone('GMT'));
243+
}
244+
245+
if ($dateTime instanceof DateTimeImmutable) {
246+
return $dateTime->setTimezone(new DateTimeZone('GMT'));
247+
}
248+
249+
// @codeCoverageIgnoreStart
250+
return $dateTime;
251+
// @codeCoverageIgnoreEnd
252+
}
253+
254+
/**
255+
* Formats the given date-time object
256+
*
257+
* @param DateTimeInterface $dateTime
258+
*
259+
* @return string
260+
*
261+
* @link https://datatracker.ietf.org/doc/html/rfc822
262+
*/
263+
final protected function formatDateTime(DateTimeInterface $dateTime) : string
50264
{
51-
return new ArrayIterator([
52-
$this->getFieldName(),
53-
$this->getFieldValue(),
54-
]);
265+
return $this->normalizeDateTime($dateTime)->format(DateTime::RFC822);
55266
}
56267
}

src/HeaderAccessControlAllowCredentials.php

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,9 @@
1212
namespace Sunrise\Http\Header;
1313

1414
/**
15-
* HeaderAccessControlAllowCredentials
16-
*
1715
* @link https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Credentials
1816
*/
19-
class HeaderAccessControlAllowCredentials extends AbstractHeader implements HeaderInterface
17+
class HeaderAccessControlAllowCredentials extends AbstractHeader
2018
{
2119

2220
/**

0 commit comments

Comments
 (0)