-
Notifications
You must be signed in to change notification settings - Fork 3.4k
Description
Description
In ServerRequest, the method withAddedHeader() always casts the header value to an array, even if you pass a single string:
public function withAddedHeader(string $name, $value): static
{
$new = clone $this;
$name = $this->normalizeHeaderName($name);
$existing = [];
if (isset($new->_environment[$name])) {
$existing = (array)$new->_environment[$name];
}
$existing = array_merge($existing, (array)$value);
$new->_environment[$name] = $existing;
return $new;
}This means even adding a single header value like '1.1.1.1' results in storing ['1.1.1.1'] in the internal $_environment.
Meanwhile, getEnv() unconditionally casts stored values to string:
return $this->_environment[$key] !== null
? (string)$this->_environment[$key]
: $default;Casting an array to string triggers PHP warning and returns the string "Array".
Example: effect on ServerRequest::clientIp()
The clientIp() method expects getEnv('HTTP_X_FORWARDED_FOR') to return a string it can explode and parse:
$addresses = array_map('trim', explode(',', (string)$this->getEnv('HTTP_X_FORWARDED_FOR')));But if you add the header with withAddedHeader() even for a single value:
$request = $request->withAddedHeader('X-Forwarded-For', '1.1.1.1');
echo $request->clientIp();getEnv('HTTP_X_FORWARDED_FOR') returns (string)['1.1.1.1'] which becomes "Array", not the expected IP address string.
This breaks the logic that parses client IPs from headers.
Expected behavior:
withAddedHeader()should not always cast header values to arrays internally, orgetEnv()should handle array values safely and not blindly cast them to strings.
Actual behavior:
- Even single header values are stored as arrays in
$_environment. getEnv()casts arrays to strings, causing PHP warning and breaking dependent methods likeclientIp().
Example test demonstrating expected behavior (which currently fails):
public function testClientIpWithSingleXForwardedForHeader()
{
$request = new ServerRequest();
$request->trustProxy = true;
$request = $request->withAddedHeader('X-Forwarded-For', '1.1.1.1');
$this->assertSame('1.1.1.1', $request->getEnv('HTTP_X_FORWARDED_FOR'));
$this->assertSame('1.1.1.1', $request->clientIp());
}CakePHP Version
5.x
PHP Version
8.3