Skip to content

Commit 80b5a6a

Browse files
committed
Add ServerNormalizer
1 parent a377fac commit 80b5a6a

File tree

2 files changed

+258
-0
lines changed

2 files changed

+258
-0
lines changed

src/ServerNormalizer.php

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace HttpSoft\Request;
6+
7+
use HttpSoft\Uri\Uri;
8+
use HttpSoft\Uri\UriData;
9+
use Psr\Http\Message\UriInterface;
10+
11+
use function array_key_exists;
12+
use function explode;
13+
use function in_array;
14+
use function is_string;
15+
use function preg_replace;
16+
use function strpos;
17+
use function str_replace;
18+
use function strtolower;
19+
use function substr;
20+
use function ucwords;
21+
22+
final class ServerNormalizer implements ServerNormalizerInterface
23+
{
24+
/**
25+
* {@inheritDoc}
26+
*/
27+
public function normalizeMethod(array $server): string
28+
{
29+
if (empty($server['REQUEST_METHOD'])) {
30+
return RequestMethodInterface::METHOD_GET;
31+
}
32+
33+
return (string) $server['REQUEST_METHOD'];
34+
}
35+
36+
/**
37+
* {@inheritDoc}
38+
*/
39+
public function normalizeProtocolVersion(array $server): string
40+
{
41+
if (empty($server['SERVER_PROTOCOL'])) {
42+
return '1.1';
43+
}
44+
45+
return str_replace('HTTP/', '', (string) $server['SERVER_PROTOCOL']);
46+
}
47+
48+
/**
49+
* {@inheritDoc}
50+
*/
51+
public function normalizeUri(array $server): UriInterface
52+
{
53+
$uriData = new UriData();
54+
55+
if (isset($server['HTTPS']) && in_array(strtolower((string) $server['HTTPS']), ['on', '1'])) {
56+
$uriData->setScheme(UriData::SCHEMES[UriData::SECURE_PORT]);
57+
} elseif ($scheme = $server['HTTP_X_FORWARDED_PROTO'] ?? $server['REQUEST_SCHEME'] ?? UriData::EMPTY_STRING) {
58+
$uriData->setScheme((string) $scheme);
59+
}
60+
61+
if ($host = $server['HTTP_X_FORWARDED_HOST'] ?? $server['HTTP_HOST'] ?? UriData::EMPTY_STRING) {
62+
$uriData->setHost((string) $host);
63+
} elseif ($host = $server['SERVER_NAME'] ?? $server['SERVER_ADDR'] ?? UriData::EMPTY_STRING) {
64+
$uriData->setHost((string) $host);
65+
}
66+
67+
if (($port = $server['SERVER_PORT'] ?? null) && (strpos($uriData->getHost(), ':') === false)) {
68+
$uriData->setPort((int) $port);
69+
}
70+
71+
if ($path = $server['REQUEST_URI'] ?? $server['ORIG_PATH_INFO'] ?? UriData::EMPTY_STRING) {
72+
$uriData->setPath(explode('?', preg_replace('/^[^\/:]+:\/\/[^\/]+/', '', (string) $path), 2)[0]);
73+
}
74+
75+
if ($query = $server['QUERY_STRING'] ?? UriData::EMPTY_STRING) {
76+
$uriData->setQuery((string) $query);
77+
}
78+
79+
return new Uri($uriData->__toString());
80+
}
81+
82+
/**
83+
* {@inheritDoc}
84+
*/
85+
public function normalizeHeaders(array $server): array
86+
{
87+
$headers = [];
88+
89+
foreach ($server as $name => $value) {
90+
if (!is_string($name) || $value === '') {
91+
continue;
92+
}
93+
94+
if (strpos($name, 'REDIRECT_') === 0) {
95+
if (array_key_exists($name = substr($name, 9), $server)) {
96+
continue;
97+
}
98+
}
99+
100+
if (strpos($name, 'HTTP_') === 0) {
101+
$headers[$this->normalizeHeaderName(substr($name, 5))] = $value;
102+
}
103+
104+
if (strpos($name, 'CONTENT_') === 0) {
105+
$headers[$this->normalizeHeaderName($name)] = $value;
106+
}
107+
}
108+
109+
return $headers;
110+
}
111+
112+
/**
113+
* @param string $name
114+
* @return string
115+
*/
116+
private function normalizeHeaderName(string $name): string
117+
{
118+
return str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', $name))));
119+
}
120+
}

tests/ServerNormalizerTest.php

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace HttpSoft\Tests\Request;
6+
7+
use HttpSoft\Request\ServerNormalizer;
8+
use PHPUnit\Framework\TestCase;
9+
use Psr\Http\Message\UriInterface;
10+
11+
class ServerNormalizerTest extends TestCase
12+
{
13+
/**
14+
* @var ServerNormalizer
15+
*/
16+
private ServerNormalizer $normalizer;
17+
18+
/**
19+
* @var array
20+
*/
21+
private array $server;
22+
23+
public function setUp(): void
24+
{
25+
$this->normalizer = new ServerNormalizer();
26+
$this->server = [
27+
'HTTPS' => 'on',
28+
'SERVER_PORT' => '443',
29+
'REQUEST_METHOD' => 'GET',
30+
'SERVER_PROTOCOL' => 'HTTP/1.1',
31+
'HTTP_HOST' => 'example.com',
32+
'HTTP_CACHE_CONTROL' => 'max-age=0',
33+
'HTTP_X_FORWARDED_PROTO' => 'https',
34+
'CONTENT_TYPE' => 'text/html; charset=UTF-8',
35+
'REQUEST_URI' => '/path?name=value',
36+
'QUERY_STRING' => 'name=value',
37+
];
38+
}
39+
40+
public function testNormalizeMethod(): void
41+
{
42+
$method = $this->normalizer->normalizeMethod($this->server);
43+
self::assertEquals($this->server['REQUEST_METHOD'], $method);
44+
}
45+
46+
public function testNormalizeMethodIfRequestMethodHeaderIsEmptyOrNotExist(): void
47+
{
48+
$defaultMethod = 'GET';
49+
$server = $this->server;
50+
51+
$server['REQUEST_METHOD'] = null;
52+
$method = $this->normalizer->normalizeMethod($server);
53+
self::assertEquals($defaultMethod, $method);
54+
55+
$server['REQUEST_METHOD'] = '';
56+
$method = $this->normalizer->normalizeMethod($server);
57+
self::assertEquals($defaultMethod, $method);
58+
59+
unset($server['REQUEST_METHOD']);
60+
$method = $this->normalizer->normalizeMethod($server);
61+
self::assertEquals($defaultMethod, $method);
62+
}
63+
64+
public function testNormalizeProtocolVersion(): void
65+
{
66+
$version = $this->normalizer->normalizeProtocolVersion($this->server);
67+
self::assertEquals($this->server['SERVER_PROTOCOL'], 'HTTP/' . $version);
68+
}
69+
70+
public function testNormalizeProtocolVersionIfServerProtocolHeaderIsEmptyOrNotExist(): void
71+
{
72+
$defaultVersion = '1.1';
73+
$server = $this->server;
74+
75+
$server['SERVER_PROTOCOL'] = null;
76+
$version = $this->normalizer->normalizeProtocolVersion($server);
77+
self::assertEquals($defaultVersion, $version);
78+
79+
$server['SERVER_PROTOCOL'] = '';
80+
$version = $this->normalizer->normalizeProtocolVersion($server);
81+
self::assertEquals($defaultVersion, $version);
82+
83+
unset($server['SERVER_PROTOCOL']);
84+
$version = $this->normalizer->normalizeProtocolVersion($server);
85+
self::assertEquals($defaultVersion, $version);
86+
}
87+
88+
public function testNormalizeUri(): void
89+
{
90+
$uri = $this->normalizer->normalizeUri($this->server);
91+
self::assertInstanceOf(UriInterface::class, $uri);
92+
self::assertEquals($this->server['HTTP_X_FORWARDED_PROTO'], $uri->getScheme());
93+
self::assertEquals($this->server['HTTP_HOST'], $uri->getAuthority());
94+
self::assertEquals('', $uri->getUserInfo());
95+
self::assertEquals($this->server['HTTP_HOST'], $uri->getHost());
96+
self::assertEquals(null, $uri->getPort());
97+
self::assertEquals('/path', $uri->getPath());
98+
self::assertEquals($this->server['QUERY_STRING'], $uri->getQuery());
99+
self::assertEquals('https://example.com/path?name=value', (string) $uri);
100+
}
101+
102+
public function testNormalizeUriIfServerIsEmpty(): void
103+
{
104+
$uri = $this->normalizer->normalizeUri([]);
105+
self::assertInstanceOf(UriInterface::class, $uri);
106+
self::assertEquals('', $uri->getScheme());
107+
self::assertEquals('', $uri->getAuthority());
108+
self::assertEquals('', $uri->getUserInfo());
109+
self::assertEquals('', $uri->getHost());
110+
self::assertEquals(null, $uri->getPort());
111+
self::assertEquals('', $uri->getPath());
112+
self::assertEquals('', $uri->getQuery());
113+
self::assertEquals('', (string) $uri);
114+
}
115+
116+
public function testNormalizeHeaders(): void
117+
{
118+
$headers = $this->normalizer->normalizeHeaders($this->server);
119+
120+
self::assertEquals($this->server['HTTP_HOST'], $headers['Host']);
121+
self::assertEquals($this->server['HTTP_CACHE_CONTROL'], $headers['Cache-Control']);
122+
self::assertEquals($this->server['HTTP_X_FORWARDED_PROTO'], $headers['X-Forwarded-Proto']);
123+
self::assertEquals($this->server['CONTENT_TYPE'], $headers['Content-Type']);
124+
125+
self::assertFalse(isset($headers['HTTPS']));
126+
self::assertFalse(isset($headers['SERVER_PORT']));
127+
self::assertFalse(isset($headers['REQUEST_METHOD']));
128+
self::assertFalse(isset($headers['SERVER_PROTOCOL']));
129+
self::assertFalse(isset($headers['REQUEST_URI']));
130+
self::assertFalse(isset($headers['QUERY_STRING']));
131+
}
132+
133+
public function testNormalizeHeadersIfServerIsEmpty(): void
134+
{
135+
$headers = $this->normalizer->normalizeHeaders([]);
136+
self::assertEquals([], $headers);
137+
}
138+
}

0 commit comments

Comments
 (0)