Skip to content

Commit 0214011

Browse files
committed
Enhance getServerName to prioritize and correctly parse forwarded headers for accurate server name resolution; add corresponding tests.
1 parent 1cd514e commit 0214011

2 files changed

Lines changed: 90 additions & 7 deletions

File tree

src/base/types/traits/Helper/ServerTrait.php

Lines changed: 66 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -54,19 +54,78 @@ public function getTs($formatted = false)
5454
*/
5555
public function getServerName()
5656
{
57-
$serverName = $this->getServer('SERVER_NAME');
57+
$serverName = $this->extractForwardedHost();
5858
if (empty($serverName)) {
59-
$serverName = $this->getServer('HTTP_HOST');
59+
$serverName = $this->extractHostFromValue((string)$this->getServer('HTTP_HOST', ''));
6060
}
61-
$serverName = is_string($serverName) ? $serverName : '';
62-
if (str_contains($serverName, ':')) {
63-
$pieces = explode(':', $serverName);
64-
$serverName = $pieces[0];
61+
if (empty($serverName)) {
62+
$serverName = $this->extractHostFromValue((string)$this->getServer('SERVER_NAME', ''));
6563
}
66-
return true === in_array($serverName, ['0.0.0.0', '127.0.0.1', 'docker.host.internal']
64+
65+
return true === in_array(
66+
strtolower($serverName),
67+
['0.0.0.0', '127.0.0.1', '::1', 'docker.host.internal'],
68+
true
6769
) ? 'localhost' : $serverName;
6870
}
6971

72+
/**
73+
* @return string
74+
*/
75+
private function extractForwardedHost(): string
76+
{
77+
$forwarded = trim((string)$this->getServer('HTTP_FORWARDED', ''));
78+
if ($forwarded !== '') {
79+
$entry = trim((string)explode(',', $forwarded)[0]);
80+
if (preg_match('/(?:^|;)\\s*host\\s*=\\s*\"?([^\";]+)\"?/i', $entry, $matches) === 1) {
81+
return $this->extractHostFromValue($matches[1]);
82+
}
83+
}
84+
85+
foreach (['HTTP_X_FORWARDED_HOST', 'HTTP_X_ORIGINAL_HOST', 'HTTP_X_HOST', 'HTTP_X_FORWARDED_SERVER'] as $header) {
86+
$candidate = trim((string)$this->getServer($header, ''));
87+
if ($candidate === '') {
88+
continue;
89+
}
90+
$candidate = trim((string)explode(',', $candidate)[0]);
91+
$host = $this->extractHostFromValue($candidate);
92+
if ($host !== '') {
93+
return $host;
94+
}
95+
}
96+
97+
return '';
98+
}
99+
100+
/**
101+
* @param string $value
102+
* @return string
103+
*/
104+
private function extractHostFromValue(string $value): string
105+
{
106+
$value = trim($value);
107+
if ($value === '') {
108+
return '';
109+
}
110+
111+
$host = (string)parse_url($value, PHP_URL_HOST);
112+
if ($host === '') {
113+
$host = (string)parse_url('http://' . $value, PHP_URL_HOST);
114+
}
115+
if ($host !== '') {
116+
return $host;
117+
}
118+
119+
if (preg_match('/^\\[([0-9a-f:.]+)](?::\\d+)?$/i', $value, $matches) === 1) {
120+
return $matches[1];
121+
}
122+
if (preg_match('/^([^:]+):\\d+$/', $value, $matches) === 1) {
123+
return $matches[1];
124+
}
125+
126+
return $value;
127+
}
128+
70129
/**
71130
* @return string
72131
*/

tests/base/RequestTest.php

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,30 @@ public function testRootUrlOmitsStandardPorts(): void
113113
$this->assertSame('https://secure.example.org', $request->getRootUrl());
114114
}
115115

116+
public function testGetServerNamePrioritizesForwardedHeaders(): void
117+
{
118+
$request = Request::getInstance();
119+
$request->setServer([
120+
'SERVER_NAME' => 'internal.local',
121+
'HTTP_HOST' => 'internal.local:8080',
122+
'HTTP_X_FORWARDED_HOST' => 'public.example.com:443, edge.local',
123+
]);
124+
125+
$this->assertSame('public.example.com', $request->getServerName());
126+
}
127+
128+
public function testGetServerNameParsesForwardedHeader(): void
129+
{
130+
$request = Request::getInstance();
131+
$request->setServer([
132+
'SERVER_NAME' => 'internal.local',
133+
'HTTP_HOST' => 'internal.local',
134+
'HTTP_FORWARDED' => 'for=203.0.113.60;proto=https;host="api.example.com:8443"',
135+
]);
136+
137+
$this->assertSame('api.example.com', $request->getServerName());
138+
}
139+
116140
public function testFileDetectionAndLanguageHeaderAndTimestamp(): void
117141
{
118142
$request = Request::getInstance();

0 commit comments

Comments
 (0)