Skip to content

Commit

Permalink
feat: Add iplocation driver
Browse files Browse the repository at this point in the history
  • Loading branch information
pulkitjalan committed Oct 10, 2024
1 parent 095121c commit 9f735e9
Show file tree
Hide file tree
Showing 4 changed files with 196 additions and 1 deletion.
11 changes: 10 additions & 1 deletion config/ip-geolocation.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
| Supported: "ip-api", "maxmind_database", "maxmind_api", "ipstack"
|
*/
'driver' => env('IPGEOLOCATION_DRIVER', 'ip-api'),
'driver' => env('IP_GEOLOCATION_DRIVER', 'ip-api'),

/*
|--------------------------------------------------------------------------
Expand Down Expand Up @@ -65,4 +65,13 @@
// Get your access key here: https://ipstack.com/product
'key' => env('IPGEOLOCATION_IPSTACK_KEY'),
],

/*
|--------------------------------------------------------------------------
| IP2Location Driver
|--------------------------------------------------------------------------
*/
'ip2location' => [
'api_key' => env('IP2LOCATION_API_KEY'),
],
];
76 changes: 76 additions & 0 deletions src/Drivers/IP2LocationDriver.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
<?php

namespace PulkitJalan\IPGeolocation\Drivers;

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

class IP2LocationDriver 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, 'api_key')) {
throw new InvalidCredentialsException('IP2Location API key is required');
}
}

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

if (empty($data) || Arr::get($data, 'response') !== 'OK') {
return $this->getDefault();
}

return [
'city' => Arr::get($data, 'city_name'),
'country' => Arr::get($data, 'country_name'),
'countryCode' => Arr::get($data, 'country_code'),
'latitude' => (float) number_format(Arr::get($data, 'latitude', 0), 5),
'longitude' => (float) number_format(Arr::get($data, 'longitude', 0), 5),
'region' => Arr::get($data, 'region_name'),
'regionCode' => Arr::get($data, 'region_code'),
'timezone' => Arr::get($data, 'time_zone'),
'postalCode' => Arr::get($data, 'zip_code'),
];
}

/**
* Get the raw IP2Location info.
*
* @param string $ip
* @return array
*/
public function getRaw($ip)
{
$url = $this->getUrl($ip);
$response = $this->guzzle->get($url);
return json_decode($response->getBody(), true);
}

/**
* Get the IP2Location API URL.
*
* @param string $ip
* @return string
*/
protected function getUrl($ip)
{
$apiKey = Arr::get($this->config, 'api_key');
return "https://api.ip2location.io/?key={$apiKey}&ip={$ip}&format=json";
}
}
11 changes: 11 additions & 0 deletions src/IPGeolocationManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
use PulkitJalan\IPGeolocation\Drivers\MaxmindDatabaseDriver;
use PulkitJalan\IPGeolocation\Exceptions\InvalidDriverException;
use PulkitJalan\IPGeolocation\Drivers\AbstractIPGeolocationDriver;
use PulkitJalan\IPGeolocation\Drivers\IP2LocationDriver;

class IPGeolocationManager
{
Expand Down Expand Up @@ -90,4 +91,14 @@ protected function createIpStackDriver(array $data): IPStackDriver
{
return new IPStackDriver($data, $this->guzzle);
}

/**
* Get the IP2Location driver.
*
* @return IP2LocationDriver
*/
protected function createIp2locationDriver(array $data): IP2LocationDriver
{
return new IP2LocationDriver($data, $this->guzzle);
}
}
99 changes: 99 additions & 0 deletions tests/Drivers/IP2LocationDriverTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
<?php

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

test('it throws exception with invalid credentials', function () {
expect(fn () => new IP2LocationDriver([]))
->toThrow(InvalidCredentialsException::class);
});

test('it returns default for invalid response', function () {
$mock = new MockHandler([
new Response(200, [], json_encode(['response' => 'FAILED'])),
]);

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

$driver = new IP2LocationDriver(['api_key' => 'test_key'], $client);

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

test('it returns correct data', function () {
$mockResponse = [
'response' => 'OK',
'country_code' => 'US',
'country_name' => 'United States of America',
'region_name' => 'California',
'region_code' => 'CA',
'city_name' => 'Los Angeles',
'latitude' => 34.05223,
'longitude' => -118.24368,
'zip_code' => '90001',
'time_zone' => '-07:00',
];

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

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

$driver = new IP2LocationDriver(['api_key' => 'test_key'], $client);

$result = $driver->get('127.0.0.1');

$expected = [
'city' => 'Los Angeles',
'country' => 'United States of America',
'countryCode' => 'US',
'latitude' => 34.05223,
'longitude' => -118.24368,
'region' => 'California',
'regionCode' => 'CA',
'timezone' => '-07:00',
'postalCode' => '90001',
];

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

test('it handles raw data', function () {
$mockResponse = [
'response' => 'OK',
'country_code' => 'US',
'country_name' => 'United States of America',
'region_name' => 'California',
'city_name' => 'Los Angeles',
];

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

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

$driver = new IP2LocationDriver(['api_key' => 'test_key'], $client);

$result = $driver->getRaw('127.0.0.1');

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

0 comments on commit 9f735e9

Please sign in to comment.