Skip to content

Commit

Permalink
feat: Add ipinfo driver (#67)
Browse files Browse the repository at this point in the history
* feat: Add ipinfo driver

* Fix styling

* throwable

* update readme and config
  • Loading branch information
pulkitjalan authored Oct 13, 2024
1 parent e7f6262 commit 1dc7860
Show file tree
Hide file tree
Showing 7 changed files with 218 additions and 7 deletions.
25 changes: 22 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ IP Geolocation
[![License](https://poser.pugx.org/pulkitjalan/ip-geolocation/license)](https://packagist.org/packages/pulkitjalan/ip-geolocation)


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.
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.

## Requirements

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

Next run `php artisan vendor:publish --provider="PulkitJalan\IPGeolocation\IPGeolocationServiceProvider" --tag="config"` to publish the config file.
Next publish the config file:

```bash
php artisan vendor:publish --provider="PulkitJalan\IPGeolocation\IPGeolocationServiceProvider" --tag="config"
```

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

Expand Down Expand Up @@ -133,8 +137,19 @@ $config = [
];
```

#### IPinfo

Note: Make sure to download the appropriate IP2Location database file and provide the correct path in the configuration.
To use IPinfo as the driver, set the config as follows:

Example:
```php
$config = [
'driver' => 'ipinfo',
'ipinfo' => [
'token' => 'YOUR IPINFO API TOKEN',
],
];
```

### Laravel

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

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/).

### IPinfo

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/).

## License

The MIT License (MIT). Please see the [License File](LICENSE) for more information.
10 changes: 10 additions & 0 deletions config/ip-geolocation.php
Original file line number Diff line number Diff line change
Expand Up @@ -75,4 +75,14 @@
// Get your API key here: https://www.ip2location.io/pricing
'api_key' => env('IPGEOLOCATION_IP2LOCATION_API_KEY'),
],

/*
|--------------------------------------------------------------------------
| IPInfo Driver
|--------------------------------------------------------------------------
*/
'ipinfo' => [
// Get your token here: https://ipinfo.io/
'token' => env('IPGEOLOCATION_IPINFO_TOKEN'),
],
];
71 changes: 71 additions & 0 deletions src/Drivers/IPInfoDriver.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
<?php

namespace PulkitJalan\IPGeolocation\Drivers;

use Throwable;
use Illuminate\Support\Arr;
use GuzzleHttp\Client as GuzzleClient;
use PulkitJalan\IPGeolocation\Exceptions\InvalidCredentialsException;

class IPInfoDriver extends AbstractIPGeolocationDriver implements IPGeolocationInterface
{
/**
* @param array $config
* @param GuzzleClient|null $guzzle
* @throws InvalidCredentialsException
*/
public function __construct(array $config, GuzzleClient $guzzle = null)
{
parent::__construct($config, $guzzle);

if (! Arr::get($this->config, 'token')) {
throw new InvalidCredentialsException('The IPInfo access token is required.');
}
}

/**
* Get array of data using IPInfo.
*
* @param string $ip
* @return array
*/
public function get($ip)
{
$data = $this->getRaw($ip);

if (empty($data)) {
return $this->getDefault();
}

return [
'city' => Arr::get($data, 'city'),
'country' => Arr::get($data, 'country'),
'countryCode' => Arr::get($data, 'country'),
'latitude' => (float) explode(',', Arr::get($data, 'loc', '0,0'))[0],
'longitude' => (float) explode(',', Arr::get($data, 'loc', '0,0'))[1],
'region' => Arr::get($data, 'region'),
'regionCode' => Arr::get($data, 'region'),
'timezone' => Arr::get($data, 'timezone'),
'postalCode' => Arr::get($data, 'postal'),
];
}

/**
* Get the raw IPGeolocation info using IPInfo.
*
* @param string $ip
* @return array
*/
public function getRaw($ip)
{
$url = "https://ipinfo.io/{$ip}?token=" . Arr::get($this->config, 'token');

try {
$response = $this->guzzle->get($url);

return json_decode($response->getBody(), true);
} catch (Throwable $e) {
return [];
}
}
}
5 changes: 3 additions & 2 deletions src/IPGeolocation.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace PulkitJalan\IPGeolocation;

use Throwable;
use Illuminate\Support\Arr;
use Illuminate\Support\Str;
use GuzzleHttp\Client as GuzzleClient;
Expand Down Expand Up @@ -126,7 +127,7 @@ public function getRaw()
if (! $data) {
try {
$data = $this->getDriver()->getRaw($ip);
} catch (\Exception $e) {
} catch (Throwable $e) {
throw new IPGeolocationException('Failed to get raw ip geolocation data', 0, $e);
}

Expand Down Expand Up @@ -155,7 +156,7 @@ protected function getData()
if (! $data) {
try {
$data = $this->getDriver()->get($ip);
} catch (\Exception $e) {
} catch (Throwable $e) {
throw new IPGeolocationException('Failed to get ip geolocation data', 0, $e);
}

Expand Down
11 changes: 11 additions & 0 deletions src/IPGeolocationManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
use Illuminate\Support\Str;
use GuzzleHttp\Client as GuzzleClient;
use PulkitJalan\IPGeolocation\Drivers\IPApiDriver;
use PulkitJalan\IPGeolocation\Drivers\IPInfoDriver;
use PulkitJalan\IPGeolocation\Drivers\IPStackDriver;
use PulkitJalan\IPGeolocation\Drivers\MaxmindApiDriver;
use PulkitJalan\IPGeolocation\Drivers\IP2LocationDriver;
Expand Down Expand Up @@ -101,4 +102,14 @@ protected function createIp2locationDriver(array $data): IP2LocationDriver
{
return new IP2LocationDriver($data, $this->guzzle);
}

/**
* Get the IPInfo driver.
*
* @return IPInfoDriver
*/
protected function createIpInfoDriver(array $data): IPInfoDriver
{
return new IPInfoDriver($data, $this->guzzle);
}
}
4 changes: 2 additions & 2 deletions src/IPGeolocationUpdater.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
namespace PulkitJalan\IPGeolocation;

use PharData;
use Exception;
use Throwable;
use Illuminate\Support\Arr;
use GuzzleHttp\Client as GuzzleClient;
use PulkitJalan\IPGeolocation\Exceptions\InvalidDatabaseException;
Expand Down Expand Up @@ -93,7 +93,7 @@ protected function updateMaxmindDatabase()

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

Expand Down
99 changes: 99 additions & 0 deletions tests/Drivers/IPInfoDriverTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
<?php

use GuzzleHttp\Client;
use GuzzleHttp\HandlerStack;
use GuzzleHttp\Psr7\Response;
use GuzzleHttp\Handler\MockHandler;
use PulkitJalan\IPGeolocation\Drivers\IPInfoDriver;
use PulkitJalan\IPGeolocation\Exceptions\InvalidCredentialsException;

beforeEach(function () {
$this->validConfig = ['token' => 'test_token'];
$this->invalidConfig = [];
});

it('throws exception with invalid config', function () {
expect(fn () => new IPInfoDriver($this->invalidConfig))
->toThrow(InvalidCredentialsException::class);
});

it('returns correct data for valid IP', function () {
$mockResponse = [
'ip' => '8.8.8.8',
'city' => 'Mountain View',
'region' => 'California',
'country' => 'US',
'loc' => '37.4056,-122.0775',
'postal' => '94043',
'timezone' => 'America/Los_Angeles',
];

$mock = new MockHandler([
new Response(200, [], json_encode($mockResponse)),
]);

$handlerStack = HandlerStack::create($mock);
$client = new Client(['handler' => $handlerStack]);

$driver = new IPInfoDriver($this->validConfig, $client);
$result = $driver->get('8.8.8.8');

expect($result)->toMatchArray([
'city' => 'Mountain View',
'country' => 'US',
'countryCode' => 'US',
'latitude' => 37.4056,
'longitude' => -122.0775,
'region' => 'California',
'regionCode' => 'California',
'timezone' => 'America/Los_Angeles',
'postalCode' => '94043',
]);
});

it('returns default data for invalid response', function () {
$mock = new MockHandler([
new Response(400, []),
]);

$handlerStack = HandlerStack::create($mock);
$client = new Client(['handler' => $handlerStack]);

$driver = new IPInfoDriver($this->validConfig, $client);

expect($driver->get('invalid_ip'))->toEqual([
'city' => null,
'country' => null,
'countryCode' => null,
'latitude' => null,
'longitude' => null,
'region' => null,
'regionCode' => null,
'timezone' => null,
'postalCode' => null,
]);
});

it('returns raw data for valid IP', function () {
$mockResponse = [
'ip' => '8.8.8.8',
'city' => 'Mountain View',
'region' => 'California',
'country' => 'US',
'loc' => '37.4056,-122.0775',
'postal' => '94043',
'timezone' => 'America/Los_Angeles',
];

$mock = new MockHandler([
new Response(200, [], json_encode($mockResponse)),
]);

$handlerStack = HandlerStack::create($mock);
$client = new Client(['handler' => $handlerStack]);

$driver = new IPInfoDriver($this->validConfig, $client);
$result = $driver->getRaw('8.8.8.8');

expect($result)->toBe($mockResponse);
});

0 comments on commit 1dc7860

Please sign in to comment.