From d399343035ee16a9ae756dbb6e4b859fc944d39e Mon Sep 17 00:00:00 2001 From: mateen993 Date: Mon, 5 Oct 2026 16:23:38 +0500 Subject: [PATCH] Add IPGeolocation.io driver --- config/location.php | 4 ++ readme.md | 1 + src/Drivers/IpGeolocation.php | 41 +++++++++++++++ tests/Drivers/IpGeolocationTest.php | 81 +++++++++++++++++++++++++++++ 4 files changed, 127 insertions(+) create mode 100644 src/Drivers/IpGeolocation.php create mode 100644 tests/Drivers/IpGeolocationTest.php diff --git a/config/location.php b/config/location.php index 50b0a01..b203333 100644 --- a/config/location.php +++ b/config/location.php @@ -132,6 +132,10 @@ 'token' => env('IP2LOCATIONIO_TOKEN'), ], + 'ipgeolocation' => [ + 'token' => env('IPGEOLOCATION_TOKEN'), + ], + /* |-------------------------------------------------------------------------- | Kloudend ~ ipapi.co Configuration diff --git a/readme.md b/readme.md index 8b597aa..86264d1 100644 --- a/readme.md +++ b/readme.md @@ -157,6 +157,7 @@ Available drivers: - [MaxMind](https://www.maxmind.com/en/home) - [Cloudflare](https://support.cloudflare.com/hc/en-us/articles/200168236-Configuring-IP-geolocation) - [IP2Location.io](https://www.ip2location.io/) +- [IPGeolocation.io](https://ipgeolocation.io) #### Setting up MaxMind with a self-hosted database (optional) diff --git a/src/Drivers/IpGeolocation.php b/src/Drivers/IpGeolocation.php new file mode 100644 index 0000000..0e79814 --- /dev/null +++ b/src/Drivers/IpGeolocation.php @@ -0,0 +1,41 @@ + config('location.ipgeolocation.token'), + 'ip' => $ip, + 'fields' => 'location,currency.code,time_zone.name', + ]); + } + + /** + * {@inheritdoc} + */ + protected function hydrate(Position $position, Fluent $location): Position + { + $position->countryName = $location['location']['country_name'] ?? null; + $position->countryCode = $location['location']['country_code2'] ?? null; + $position->regionCode = $location['location']['state_code'] ?? null; + $position->regionName = $location['location']['state_prov'] ?? null; + $position->cityName = $location['location']['city'] ?? null; + $position->zipCode = $location['location']['zipcode'] ?? null; + $position->postalCode = $location['location']['zipcode'] ?? null; + $position->latitude = $location['location']['latitude'] ?? null; + $position->longitude = $location['location']['longitude'] ?? null; + $position->timezone = $location['time_zone']['name'] ?? null; + $position->currencyCode = $location['currency']['code'] ?? null; + + return $position; + } +} diff --git a/tests/Drivers/IpGeolocationTest.php b/tests/Drivers/IpGeolocationTest.php new file mode 100644 index 0000000..0ef4eff --- /dev/null +++ b/tests/Drivers/IpGeolocationTest.php @@ -0,0 +1,81 @@ +makePartial(); + + $response = new Fluent([ + 'ip' => '66.102.0.0', + 'location' => [ + 'continent_code' => 'NA', + 'continent_name' => 'North America', + 'country_code2' => 'US', + 'country_code3' => 'USA', + 'country_name' => 'United States', + 'state_prov' => 'California', + 'state_code' => 'US-CA', + 'district' => 'Santa Clara County', + 'city' => 'Mountain View', + 'zipcode' => '94043', + 'latitude' => '37.42240', + 'longitude' => '-122.08421', + ], + 'currency' => ['code' => 'USD'], + 'time_zone' => ['name' => 'America/Los_Angeles'], + ]); + + $driver + ->shouldAllowMockingProtectedMethods() + ->shouldReceive('process')->once()->andReturn($response); + + Location::setDriver($driver); + + $position = Location::get(); + + expect($position)->toBeInstanceOf(Position::class); + + expect($position->toArray())->toEqual([ + 'countryName' => 'United States', + 'currencyCode' => 'USD', + 'countryCode' => 'US', + 'regionCode' => 'US-CA', + 'regionName' => 'California', + 'cityName' => 'Mountain View', + 'zipCode' => '94043', + 'isoCode' => null, + 'postalCode' => '94043', + 'latitude' => '37.42240', + 'longitude' => '-122.08421', + 'metroCode' => null, + 'areaCode' => null, + 'ip' => '66.102.0.0', + 'timezone' => 'America/Los_Angeles', + 'driver' => get_class($driver), + ]); +}); + +it('requests the v3 endpoint with the api key and a field filter', function () { + config(['location.ipgeolocation.token' => 'secret']); + + expect((new IpGeolocation)->url('2001:4860:4860::8888'))->toBe( + 'https://api.ipgeolocation.io/v3/ipgeo?apiKey=secret&ip=2001%3A4860%3A4860%3A%3A8888&fields=location%2Ccurrency.code%2Ctime_zone.name' + ); +}); + +it('returns false when the api responds with an error', function () { + Http::fake([ + 'api.ipgeolocation.io/*' => Http::response(['message' => "'10.0.0.1' is a bogon IP address."], 423), + ]); + + Location::setDriver(new IpGeolocation); + + expect(Location::get('10.0.0.1'))->toBeFalse(); +});