Skip to content

Commit e7f6262

Browse files
authored
feat: Add iplocation driver (#68)
* feat: Add iplocation driver * Fix styling * update readme * add example and update config * fix * fix config
1 parent 095121c commit e7f6262

File tree

5 files changed

+237
-15
lines changed

5 files changed

+237
-15
lines changed

README.md

Lines changed: 39 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,22 @@
1-
IPGeolocation
1+
IP Geolocation
22
=============
33

44
> IP Geolocation Wrapper with Laravel Support
55
6-
[![Latest Stable Version](https://poser.pugx.org/pulkitjalan/ip-geolocation/v/stable?format=flat-square)](https://packagist.org/packages/pulkitjalan/ip-geolocation)
7-
[![MIT License](http://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square)](http://www.opensource.org/licenses/MIT)
8-
[![Run Tests](https://github.com/pulkitjalan/ip-geolocation/actions/workflows/run-tests.yml/badge.svg)](https://github.com/pulkitjalan/ip-geolocation/actions/workflows/run-tests.yml)
9-
[![Coverage](https://codecov.io/gh/pulkitjalan/ip-geolocation/branch/main/graph/badge.svg?token=JTB1ASXAB0)](https://codecov.io/gh/pulkitjalan/ip-geolocation)
10-
[![Total Downloads](https://img.shields.io/packagist/dt/pulkitjalan/ip-geolocation.svg?style=flat-square)](https://packagist.org/packages/pulkitjalan/ip-geolocation)
6+
[![Latest Stable Version](https://poser.pugx.org/pulkitjalan/ip-geolocation/v/stable)](https://packagist.org/packages/pulkitjalan/ip-geolocation)
7+
[![Total Downloads](https://poser.pugx.org/pulkitjalan/ip-geolocation/downloads)](https://packagist.org/packages/pulkitjalan/ip-geolocation)
8+
[![License](https://poser.pugx.org/pulkitjalan/ip-geolocation/license)](https://packagist.org/packages/pulkitjalan/ip-geolocation)
119

12-
## Supported Drivers ([Services](#services))
1310

14-
* [IP-API](http://ip-api.com/)
15-
* [Maxmind](https://www.maxmind.com/)
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.
1612

1713
## Requirements
1814

19-
* PHP >= 8.1
15+
- PHP >= 8.1
2016

2117
## Installation
2218

23-
Install via composer
19+
Install via composer:
2420

2521
```bash
2622
composer require pulkitjalan/ip-geolocation
@@ -123,6 +119,22 @@ $config = [
123119
];
124120
```
125121

122+
#### IP2Location
123+
124+
To use IP2Location as the driver, set the config as follows:
125+
126+
Example:
127+
```php
128+
$config = [
129+
'driver' => 'ip2location',
130+
'ip2location' => [
131+
'api_key' => 'YOUR IP2LOCATION API KEY',
132+
],
133+
];
134+
```
135+
136+
137+
Note: Make sure to download the appropriate IP2Location database file and provide the correct path in the configuration.
126138

127139
### Laravel
128140

@@ -275,10 +287,22 @@ Once you have registered the service provider (supports auto discovery), you can
275287

276288
## Services
277289

278-
#### IP-API
290+
### IP-API
291+
292+
IP-API is a free (or paid) service that can be used instead of the database file or the paid MaxMind service. They do have some limitations on the free service, so please review their [documentation](http://ip-api.com/docs/) first.
293+
294+
### MaxMind
295+
296+
You can use the free database from MaxMind (license key required) or their web API service. You can sign up and get a free license key [here](https://www.maxmind.com/en/geolite2/signup).
297+
298+
### IPStack
299+
300+
IPStack is a real-time IP to geolocation API service. They offer both free and paid plans. You can find more information and sign up on their [website](https://ipstack.com/).
301+
302+
### IP2Location
279303

280-
IP-API is a free (or paid) service that can also be used instead of the database file or the paid maxmind service. They do have some limitations on the free service so please have a look at the [docs](http://ip-api.com/docs/) first.
304+
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/).
281305

282-
#### Maxmind
306+
## License
283307

284-
You can use the free database from maxmind (license_key required) or their web api service. You can signup and get a free license code [here](https://www.maxmind.com/en/geolite2/signup).
308+
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
@@ -65,4 +65,14 @@
6565
// Get your access key here: https://ipstack.com/product
6666
'key' => env('IPGEOLOCATION_IPSTACK_KEY'),
6767
],
68+
69+
/*
70+
|--------------------------------------------------------------------------
71+
| IP2Location Driver
72+
|--------------------------------------------------------------------------
73+
*/
74+
'ip2location' => [
75+
// Get your API key here: https://www.ip2location.io/pricing
76+
'api_key' => env('IPGEOLOCATION_IP2LOCATION_API_KEY'),
77+
],
6878
];

src/Drivers/IP2LocationDriver.php

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

src/IPGeolocationManager.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
use PulkitJalan\IPGeolocation\Drivers\IPApiDriver;
99
use PulkitJalan\IPGeolocation\Drivers\IPStackDriver;
1010
use PulkitJalan\IPGeolocation\Drivers\MaxmindApiDriver;
11+
use PulkitJalan\IPGeolocation\Drivers\IP2LocationDriver;
1112
use PulkitJalan\IPGeolocation\Drivers\MaxmindDatabaseDriver;
1213
use PulkitJalan\IPGeolocation\Exceptions\InvalidDriverException;
1314
use PulkitJalan\IPGeolocation\Drivers\AbstractIPGeolocationDriver;
@@ -90,4 +91,14 @@ protected function createIpStackDriver(array $data): IPStackDriver
9091
{
9192
return new IPStackDriver($data, $this->guzzle);
9293
}
94+
95+
/**
96+
* Get the IP2Location driver.
97+
*
98+
* @return IP2LocationDriver
99+
*/
100+
protected function createIp2locationDriver(array $data): IP2LocationDriver
101+
{
102+
return new IP2LocationDriver($data, $this->guzzle);
103+
}
93104
}
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\IP2LocationDriver;
8+
use PulkitJalan\IPGeolocation\Exceptions\InvalidCredentialsException;
9+
10+
test('it throws exception with invalid credentials', function () {
11+
expect(fn () => new IP2LocationDriver([]))
12+
->toThrow(InvalidCredentialsException::class);
13+
});
14+
15+
test('it returns default for invalid response', function () {
16+
$mock = new MockHandler([
17+
new Response(200, [], json_encode(['response' => 'FAILED'])),
18+
]);
19+
20+
$handler = HandlerStack::create($mock);
21+
$client = new Client(['handler' => $handler]);
22+
23+
$driver = new IP2LocationDriver(['api_key' => 'test_key'], $client);
24+
25+
expect($driver->get('127.0.0.1'))->toEqual([
26+
'city' => null,
27+
'country' => null,
28+
'countryCode' => null,
29+
'latitude' => null,
30+
'longitude' => null,
31+
'region' => null,
32+
'regionCode' => null,
33+
'timezone' => null,
34+
'postalCode' => null,
35+
]);
36+
});
37+
38+
test('it returns correct data', function () {
39+
$mockResponse = [
40+
'response' => 'OK',
41+
'country_code' => 'US',
42+
'country_name' => 'United States of America',
43+
'region_name' => 'California',
44+
'region_code' => 'CA',
45+
'city_name' => 'Los Angeles',
46+
'latitude' => 34.05223,
47+
'longitude' => -118.24368,
48+
'zip_code' => '90001',
49+
'time_zone' => '-07:00',
50+
];
51+
52+
$mock = new MockHandler([
53+
new Response(200, [], json_encode($mockResponse)),
54+
]);
55+
56+
$handler = HandlerStack::create($mock);
57+
$client = new Client(['handler' => $handler]);
58+
59+
$driver = new IP2LocationDriver(['api_key' => 'test_key'], $client);
60+
61+
$result = $driver->get('127.0.0.1');
62+
63+
$expected = [
64+
'city' => 'Los Angeles',
65+
'country' => 'United States of America',
66+
'countryCode' => 'US',
67+
'latitude' => 34.05223,
68+
'longitude' => -118.24368,
69+
'region' => 'California',
70+
'regionCode' => 'CA',
71+
'timezone' => '-07:00',
72+
'postalCode' => '90001',
73+
];
74+
75+
expect($result)->toBe($expected);
76+
});
77+
78+
test('it handles raw data', function () {
79+
$mockResponse = [
80+
'response' => 'OK',
81+
'country_code' => 'US',
82+
'country_name' => 'United States of America',
83+
'region_name' => 'California',
84+
'city_name' => 'Los Angeles',
85+
];
86+
87+
$mock = new MockHandler([
88+
new Response(200, [], json_encode($mockResponse)),
89+
]);
90+
91+
$handler = HandlerStack::create($mock);
92+
$client = new Client(['handler' => $handler]);
93+
94+
$driver = new IP2LocationDriver(['api_key' => 'test_key'], $client);
95+
96+
$result = $driver->getRaw('127.0.0.1');
97+
98+
expect($result)->toBe($mockResponse);
99+
});

0 commit comments

Comments
 (0)