diff --git a/CHANGELOG.md b/CHANGELOG.md index 537221c6..27ef1260 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,11 @@ CHANGELOG if an invalid IP address is passed to them. Previously, they would make a request to the web service and throw a `GeoIp2\Exception\InvalidRequestException`. +* The `isAnycast` property was added to `GeoIp2\Record\Traits`. This returns + `true` if the IP address belongs to an + [anycast network](https://en.wikipedia.org/wiki/Anycast anycast network). + This is available for the GeoIP2 Country, City Plus, and Insights web + services and the GeoIP2 Country, City, and Enterprise databases. 2.13.0 (2022-08-05) ------------------- diff --git a/src/Record/Traits.php b/src/Record/Traits.php index 5ffcb45d..40094d5c 100644 --- a/src/Record/Traits.php +++ b/src/Record/Traits.php @@ -75,6 +75,14 @@ class Traits implements \JsonSerializable */ public readonly bool $isAnonymousVpn; + /** + * @var bool This is true if the IP address belongs to an [anycast + * network](https://en.wikipedia.org/wiki/Anycast anycast network). + * This property is not available from GeoLite databases or web + * services. + */ + public readonly bool $isAnycast; + /** * @var bool This is true if the IP address belongs * to a hosting or VPN provider (see description of isAnonymousVpn property). @@ -198,6 +206,7 @@ public function __construct(array $record) $this->ipAddress = $record['ip_address'] ?? null; $this->isAnonymous = $record['is_anonymous'] ?? false; $this->isAnonymousVpn = $record['is_anonymous_vpn'] ?? false; + $this->isAnycast = $record['is_anycast'] ?? false; $this->isHostingProvider = $record['is_hosting_provider'] ?? false; $this->isLegitimateProxy = $record['is_legitimate_proxy'] ?? false; $this->isp = $record['isp'] ?? null; @@ -242,6 +251,9 @@ public function jsonSerialize(): array if ($this->isAnonymousVpn !== false) { $js['is_anonymous_vpn'] = $this->isAnonymousVpn; } + if ($this->isAnycast !== false) { + $js['is_anycast'] = $this->isAnycast; + } if ($this->isHostingProvider !== false) { $js['is_hosting_provider'] = $this->isHostingProvider; } diff --git a/tests/GeoIp2/Test/Database/ReaderTest.php b/tests/GeoIp2/Test/Database/ReaderTest.php index 4996c6e9..9ab8b880 100644 --- a/tests/GeoIp2/Test/Database/ReaderTest.php +++ b/tests/GeoIp2/Test/Database/ReaderTest.php @@ -177,6 +177,28 @@ public function testConnectionType(): void $reader->close(); } + public function testCity(): void + { + $reader = new Reader('maxmind-db/test-data/GeoIP2-City-Test.mmdb'); + + // This IP has is_anycast + $record = $reader->city('214.1.1.0'); + $this->assertTrue($record->traits->isAnycast); + + $reader->close(); + } + + public function testCountry(): void + { + $reader = new Reader('maxmind-db/test-data/GeoIP2-Country-Test.mmdb'); + + // This IP has is_anycast + $record = $reader->country('214.1.1.0'); + $this->assertTrue($record->traits->isAnycast); + + $reader->close(); + } + public function testDomain(): void { $reader = new Reader('maxmind-db/test-data/GeoIP2-Domain-Test.mmdb'); @@ -214,6 +236,10 @@ public function testEnterprise(): void $this->assertSame('310', $record->traits->mobileCountryCode); $this->assertSame('004', $record->traits->mobileNetworkCode); + // This IP has is_anycast + $record = $reader->enterprise('214.1.1.0'); + $this->assertTrue($record->traits->isAnycast); + $reader->close(); } diff --git a/tests/GeoIp2/Test/Model/CountryTest.php b/tests/GeoIp2/Test/Model/CountryTest.php index 9f1bc77e..9c7c67d5 100644 --- a/tests/GeoIp2/Test/Model/CountryTest.php +++ b/tests/GeoIp2/Test/Model/CountryTest.php @@ -36,6 +36,7 @@ class CountryTest extends TestCase ], 'traits' => [ 'ip_address' => '1.2.3.4', + 'is_anycast' => true, 'prefix_len' => 24, ], ]; @@ -188,6 +189,7 @@ public function testJsonSerialize(): void ], 'traits' => [ 'ip_address' => '1.2.3.4', + 'is_anycast' => true, 'network' => '1.2.3.0/24', ], ]; diff --git a/tests/GeoIp2/Test/Model/InsightsTest.php b/tests/GeoIp2/Test/Model/InsightsTest.php index 15ced55c..872c47ac 100644 --- a/tests/GeoIp2/Test/Model/InsightsTest.php +++ b/tests/GeoIp2/Test/Model/InsightsTest.php @@ -76,6 +76,7 @@ public function testFull(): void 'ip_address' => '1.2.3.4', 'is_anonymous' => true, 'is_anonymous_vpn' => true, + 'is_anycast' => true, 'is_hosting_provider' => true, 'is_legitimate_proxy' => true, 'is_public_proxy' => true, @@ -170,6 +171,11 @@ public function testFull(): void '$model->traits->isAnonymous is true' ); + $this->assertTrue( + $model->traits->isAnycast, + '$model->traits->isAnycast is true' + ); + $this->assertTrue( $model->traits->isHostingProvider, '$model->traits->isHostingProvider is true' @@ -255,6 +261,7 @@ public function testFull(): void 'ip_address' => '1.2.3.4', 'is_anonymous' => true, 'is_anonymous_vpn' => true, + 'is_anycast' => true, 'is_hosting_provider' => true, 'is_legitimate_proxy' => true, 'is_public_proxy' => true, diff --git a/tests/GeoIp2/Test/WebService/ClientTest.php b/tests/GeoIp2/Test/WebService/ClientTest.php index 3dbc9c24..30225dec 100644 --- a/tests/GeoIp2/Test/WebService/ClientTest.php +++ b/tests/GeoIp2/Test/WebService/ClientTest.php @@ -32,6 +32,7 @@ class ClientTest extends TestCase 'maxmind' => ['queries_remaining' => 11], 'traits' => [ 'ip_address' => '1.2.3.4', + 'is_anycast' => true, 'network' => '1.2.3.0/24', ], ]; @@ -236,6 +237,11 @@ public function testCountry(): void 'registered_country is_in_european_union is false' ); + $this->assertTrue( + $country->traits->isAnycast, + 'is_anycast' + ); + $this->assertSame( '1.2.3.0/24', $country->traits->network, @@ -255,6 +261,11 @@ public function testInsights(): void 'continent geoname_id is 42' ); + $this->assertTrue( + $record->traits->isAnycast, + 'is_anycast' + ); + $this->assertSame( '1.2.3.0/24', $record->traits->network,