Skip to content

Commit 1dc7860

Browse files
authored
feat: Add ipinfo driver (#67)
* feat: Add ipinfo driver * Fix styling * throwable * update readme and config
1 parent e7f6262 commit 1dc7860

File tree

7 files changed

+218
-7
lines changed

7 files changed

+218
-7
lines changed

README.md

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ IP Geolocation
88
[![License](https://poser.pugx.org/pulkitjalan/ip-geolocation/license)](https://packagist.org/packages/pulkitjalan/ip-geolocation)
99

1010

11-
This package provides an easy way to get geolocation information from IP addresses. It supports multiple drivers including IP-API, MaxMind Database, MaxMind API, IPStack, and IP2Location.
11+
This package provides an easy way to get geolocation information from IP addresses. It supports multiple drivers including IP-API, MaxMind Database, MaxMind API, IPStack, IP2Location, and IPinfo.
1212

1313
## Requirements
1414

@@ -38,7 +38,11 @@ Next add the following to the `aliases` array in your `config/app.php`
3838
'IPGeolocation' => PulkitJalan\IPGeolocation\Facades\IPGeolocation::class
3939
```
4040

41-
Next run `php artisan vendor:publish --provider="PulkitJalan\IPGeolocation\IPGeolocationServiceProvider" --tag="config"` to publish the config file.
41+
Next publish the config file:
42+
43+
```bash
44+
php artisan vendor:publish --provider="PulkitJalan\IPGeolocation\IPGeolocationServiceProvider" --tag="config"
45+
```
4246

4347
#### Using an older version of PHP / Laravel?
4448

@@ -133,8 +137,19 @@ $config = [
133137
];
134138
```
135139

140+
#### IPinfo
136141

137-
Note: Make sure to download the appropriate IP2Location database file and provide the correct path in the configuration.
142+
To use IPinfo as the driver, set the config as follows:
143+
144+
Example:
145+
```php
146+
$config = [
147+
'driver' => 'ipinfo',
148+
'ipinfo' => [
149+
'token' => 'YOUR IPINFO API TOKEN',
150+
],
151+
];
152+
```
138153

139154
### Laravel
140155

@@ -303,6 +318,10 @@ IPStack is a real-time IP to geolocation API service. They offer both free and p
303318

304319
IP2Location provides IP geolocation databases and web services. They offer various products and services, including both free and paid options. You can learn more and sign up on their [website](https://www.ip2location.io/).
305320

321+
### IPinfo
322+
323+
IPinfo is a comprehensive IP address data provider offering accurate geolocation, ASN, company, and other IP-related information. They provide both API and database download options. You can sign up for a free API key or explore their paid plans on their [website](https://ipinfo.io/).
324+
306325
## License
307326

308327
The MIT License (MIT). Please see the [License File](LICENSE) for more information.

config/ip-geolocation.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,4 +75,14 @@
7575
// Get your API key here: https://www.ip2location.io/pricing
7676
'api_key' => env('IPGEOLOCATION_IP2LOCATION_API_KEY'),
7777
],
78+
79+
/*
80+
|--------------------------------------------------------------------------
81+
| IPInfo Driver
82+
|--------------------------------------------------------------------------
83+
*/
84+
'ipinfo' => [
85+
// Get your token here: https://ipinfo.io/
86+
'token' => env('IPGEOLOCATION_IPINFO_TOKEN'),
87+
],
7888
];

src/Drivers/IPInfoDriver.php

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
<?php
2+
3+
namespace PulkitJalan\IPGeolocation\Drivers;
4+
5+
use Throwable;
6+
use Illuminate\Support\Arr;
7+
use GuzzleHttp\Client as GuzzleClient;
8+
use PulkitJalan\IPGeolocation\Exceptions\InvalidCredentialsException;
9+
10+
class IPInfoDriver extends AbstractIPGeolocationDriver implements IPGeolocationInterface
11+
{
12+
/**
13+
* @param array $config
14+
* @param GuzzleClient|null $guzzle
15+
* @throws InvalidCredentialsException
16+
*/
17+
public function __construct(array $config, GuzzleClient $guzzle = null)
18+
{
19+
parent::__construct($config, $guzzle);
20+
21+
if (! Arr::get($this->config, 'token')) {
22+
throw new InvalidCredentialsException('The IPInfo access token is required.');
23+
}
24+
}
25+
26+
/**
27+
* Get array of data using IPInfo.
28+
*
29+
* @param string $ip
30+
* @return array
31+
*/
32+
public function get($ip)
33+
{
34+
$data = $this->getRaw($ip);
35+
36+
if (empty($data)) {
37+
return $this->getDefault();
38+
}
39+
40+
return [
41+
'city' => Arr::get($data, 'city'),
42+
'country' => Arr::get($data, 'country'),
43+
'countryCode' => Arr::get($data, 'country'),
44+
'latitude' => (float) explode(',', Arr::get($data, 'loc', '0,0'))[0],
45+
'longitude' => (float) explode(',', Arr::get($data, 'loc', '0,0'))[1],
46+
'region' => Arr::get($data, 'region'),
47+
'regionCode' => Arr::get($data, 'region'),
48+
'timezone' => Arr::get($data, 'timezone'),
49+
'postalCode' => Arr::get($data, 'postal'),
50+
];
51+
}
52+
53+
/**
54+
* Get the raw IPGeolocation info using IPInfo.
55+
*
56+
* @param string $ip
57+
* @return array
58+
*/
59+
public function getRaw($ip)
60+
{
61+
$url = "https://ipinfo.io/{$ip}?token=" . Arr::get($this->config, 'token');
62+
63+
try {
64+
$response = $this->guzzle->get($url);
65+
66+
return json_decode($response->getBody(), true);
67+
} catch (Throwable $e) {
68+
return [];
69+
}
70+
}
71+
}

src/IPGeolocation.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace PulkitJalan\IPGeolocation;
44

5+
use Throwable;
56
use Illuminate\Support\Arr;
67
use Illuminate\Support\Str;
78
use GuzzleHttp\Client as GuzzleClient;
@@ -126,7 +127,7 @@ public function getRaw()
126127
if (! $data) {
127128
try {
128129
$data = $this->getDriver()->getRaw($ip);
129-
} catch (\Exception $e) {
130+
} catch (Throwable $e) {
130131
throw new IPGeolocationException('Failed to get raw ip geolocation data', 0, $e);
131132
}
132133

@@ -155,7 +156,7 @@ protected function getData()
155156
if (! $data) {
156157
try {
157158
$data = $this->getDriver()->get($ip);
158-
} catch (\Exception $e) {
159+
} catch (Throwable $e) {
159160
throw new IPGeolocationException('Failed to get ip geolocation data', 0, $e);
160161
}
161162

src/IPGeolocationManager.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
use Illuminate\Support\Str;
77
use GuzzleHttp\Client as GuzzleClient;
88
use PulkitJalan\IPGeolocation\Drivers\IPApiDriver;
9+
use PulkitJalan\IPGeolocation\Drivers\IPInfoDriver;
910
use PulkitJalan\IPGeolocation\Drivers\IPStackDriver;
1011
use PulkitJalan\IPGeolocation\Drivers\MaxmindApiDriver;
1112
use PulkitJalan\IPGeolocation\Drivers\IP2LocationDriver;
@@ -101,4 +102,14 @@ protected function createIp2locationDriver(array $data): IP2LocationDriver
101102
{
102103
return new IP2LocationDriver($data, $this->guzzle);
103104
}
105+
106+
/**
107+
* Get the IPInfo driver.
108+
*
109+
* @return IPInfoDriver
110+
*/
111+
protected function createIpInfoDriver(array $data): IPInfoDriver
112+
{
113+
return new IPInfoDriver($data, $this->guzzle);
114+
}
104115
}

src/IPGeolocationUpdater.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
namespace PulkitJalan\IPGeolocation;
44

55
use PharData;
6-
use Exception;
6+
use Throwable;
77
use Illuminate\Support\Arr;
88
use GuzzleHttp\Client as GuzzleClient;
99
use PulkitJalan\IPGeolocation\Exceptions\InvalidDatabaseException;
@@ -93,7 +93,7 @@ protected function updateMaxmindDatabase()
9393

9494
array_map(fn ($file) => $this->removeIfExists($file), glob("$dir/*.*"));
9595
@rmdir($dir);
96-
} catch (Exception $e) {
96+
} catch (Throwable $e) {
9797
return false;
9898
}
9999

tests/Drivers/IPInfoDriverTest.php

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
<?php
2+
3+
use GuzzleHttp\Client;
4+
use GuzzleHttp\HandlerStack;
5+
use GuzzleHttp\Psr7\Response;
6+
use GuzzleHttp\Handler\MockHandler;
7+
use PulkitJalan\IPGeolocation\Drivers\IPInfoDriver;
8+
use PulkitJalan\IPGeolocation\Exceptions\InvalidCredentialsException;
9+
10+
beforeEach(function () {
11+
$this->validConfig = ['token' => 'test_token'];
12+
$this->invalidConfig = [];
13+
});
14+
15+
it('throws exception with invalid config', function () {
16+
expect(fn () => new IPInfoDriver($this->invalidConfig))
17+
->toThrow(InvalidCredentialsException::class);
18+
});
19+
20+
it('returns correct data for valid IP', function () {
21+
$mockResponse = [
22+
'ip' => '8.8.8.8',
23+
'city' => 'Mountain View',
24+
'region' => 'California',
25+
'country' => 'US',
26+
'loc' => '37.4056,-122.0775',
27+
'postal' => '94043',
28+
'timezone' => 'America/Los_Angeles',
29+
];
30+
31+
$mock = new MockHandler([
32+
new Response(200, [], json_encode($mockResponse)),
33+
]);
34+
35+
$handlerStack = HandlerStack::create($mock);
36+
$client = new Client(['handler' => $handlerStack]);
37+
38+
$driver = new IPInfoDriver($this->validConfig, $client);
39+
$result = $driver->get('8.8.8.8');
40+
41+
expect($result)->toMatchArray([
42+
'city' => 'Mountain View',
43+
'country' => 'US',
44+
'countryCode' => 'US',
45+
'latitude' => 37.4056,
46+
'longitude' => -122.0775,
47+
'region' => 'California',
48+
'regionCode' => 'California',
49+
'timezone' => 'America/Los_Angeles',
50+
'postalCode' => '94043',
51+
]);
52+
});
53+
54+
it('returns default data for invalid response', function () {
55+
$mock = new MockHandler([
56+
new Response(400, []),
57+
]);
58+
59+
$handlerStack = HandlerStack::create($mock);
60+
$client = new Client(['handler' => $handlerStack]);
61+
62+
$driver = new IPInfoDriver($this->validConfig, $client);
63+
64+
expect($driver->get('invalid_ip'))->toEqual([
65+
'city' => null,
66+
'country' => null,
67+
'countryCode' => null,
68+
'latitude' => null,
69+
'longitude' => null,
70+
'region' => null,
71+
'regionCode' => null,
72+
'timezone' => null,
73+
'postalCode' => null,
74+
]);
75+
});
76+
77+
it('returns raw data for valid IP', function () {
78+
$mockResponse = [
79+
'ip' => '8.8.8.8',
80+
'city' => 'Mountain View',
81+
'region' => 'California',
82+
'country' => 'US',
83+
'loc' => '37.4056,-122.0775',
84+
'postal' => '94043',
85+
'timezone' => 'America/Los_Angeles',
86+
];
87+
88+
$mock = new MockHandler([
89+
new Response(200, [], json_encode($mockResponse)),
90+
]);
91+
92+
$handlerStack = HandlerStack::create($mock);
93+
$client = new Client(['handler' => $handlerStack]);
94+
95+
$driver = new IPInfoDriver($this->validConfig, $client);
96+
$result = $driver->getRaw('8.8.8.8');
97+
98+
expect($result)->toBe($mockResponse);
99+
});

0 commit comments

Comments
 (0)