From 987d2bb9e04f1a55f9f867f48ab0daed78691419 Mon Sep 17 00:00:00 2001 From: Michael Hoffmann Date: Fri, 13 Feb 2026 20:10:19 +0100 Subject: [PATCH] fix(UserDataBag): Handle bracketed IPv6 addresses in setIpAddress MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Strip brackets from IPv6 addresses (e.g. `[::1]` → `::1`) before validation. Replace the exception with a debug log message via the SDK logger when an invalid IP is provided, preventing crashes in environments like ReactPHP where bracketed IPv6 addresses may appear. Fixes #2003 Co-Authored-By: Claude --- src/UserDataBag.php | 19 +++++++++++++++++-- tests/UserDataBagTest.php | 39 ++++++++++++++++++++++++++++----------- 2 files changed, 45 insertions(+), 13 deletions(-) diff --git a/src/UserDataBag.php b/src/UserDataBag.php index dcc374f1f..8a46af60e 100644 --- a/src/UserDataBag.php +++ b/src/UserDataBag.php @@ -220,8 +220,23 @@ public function getIpAddress(): ?string */ public function setIpAddress(?string $ipAddress): self { - if ($ipAddress !== null && filter_var($ipAddress, \FILTER_VALIDATE_IP) === false) { - throw new \InvalidArgumentException(\sprintf('The "%s" value is not a valid IP address.', $ipAddress)); + if ($ipAddress !== null) { + // Strip brackets from IPv6 addresses (e.g. [::1] -> ::1) + if (strpos($ipAddress, '[') === 0 && substr($ipAddress, -1) === ']') { + $ipAddress = substr($ipAddress, 1, -1); + } + + if (filter_var($ipAddress, \FILTER_VALIDATE_IP) === false) { + $client = SentrySdk::getCurrentHub()->getClient(); + + if ($client !== null) { + $client->getOptions()->getLoggerOrNullLogger()->debug( + \sprintf('The "%s" value is not a valid IP address.', $ipAddress) + ); + } + + return $this; + } } $this->ipAddress = $ipAddress; diff --git a/tests/UserDataBagTest.php b/tests/UserDataBagTest.php index 8fd8fb0c0..7ef0ce891 100644 --- a/tests/UserDataBagTest.php +++ b/tests/UserDataBagTest.php @@ -162,29 +162,46 @@ public static function unexpectedValueForIdFieldDataProvider(): iterable ]; } - public function testConstructorThrowsIfIpAddressArgumentIsInvalid(): void + /** + * @dataProvider bracketedIpv6AddressDataProvider + */ + public function testSetIpAddressStripsBracketsFromIpv6(string $input, string $expected): void { - $this->expectException(\InvalidArgumentException::class); - $this->expectExceptionMessage('The "foo" value is not a valid IP address.'); + $userDataBag = new UserDataBag(); + $userDataBag->setIpAddress($input); - new UserDataBag(null, null, 'foo'); + $this->assertSame($expected, $userDataBag->getIpAddress()); + } + + public static function bracketedIpv6AddressDataProvider(): iterable + { + yield 'IPv6 loopback with brackets' => ['[::1]', '::1']; + yield 'IPv6 full address with brackets' => ['[2001:db8::1]', '2001:db8::1']; + yield 'IPv6 loopback without brackets' => ['::1', '::1']; + yield 'IPv4 address' => ['127.0.0.1', '127.0.0.1']; } - public function testSetIpAddressThrowsIfArgumentIsInvalid(): void + public function testConstructorDoesNotSetInvalidIpAddress(): void { - $this->expectException(\InvalidArgumentException::class); - $this->expectExceptionMessage('The "foo" value is not a valid IP address.'); + $userDataBag = new UserDataBag(null, null, 'foo'); + $this->assertNull($userDataBag->getIpAddress()); + } + + public function testSetIpAddressDoesNotSetInvalidIpAddress(): void + { $userDataBag = new UserDataBag(); + $userDataBag->setIpAddress('127.0.0.1'); $userDataBag->setIpAddress('foo'); + + $this->assertSame('127.0.0.1', $userDataBag->getIpAddress()); } - public function testCreateFromIpAddressThrowsIfArgumentIsInvalid(): void + public function testCreateFromIpAddressDoesNotSetInvalidIpAddress(): void { - $this->expectException(\InvalidArgumentException::class); - $this->expectExceptionMessage('The "foo" value is not a valid IP address.'); + $userDataBag = UserDataBag::createFromUserIpAddress('foo'); - UserDataBag::createFromUserIpAddress('foo'); + $this->assertNull($userDataBag->getIpAddress()); } public function testMerge(): void