Skip to content

Commit

Permalink
Added IP2Location and IP2LocationBinary provider. (#1031)
Browse files Browse the repository at this point in the history
* Added IP2Location and IP2LocationBinary provider.

* Fixed spacing issues.

* Replaced tabs into spaces.

* Update src/Provider/IP2Location/IP2Location.php

Co-Authored-By: atymic <atymicq@gmail.com>

* Updated codes and format to match Geocoder standards and requirements.

* Added IP2Location API configuration.

* Updated indent and formatting issues.

* Updated Readme.md.

* Updated Readme.md to explain IP2Location Web service credit usage.

* Update Readme.md
  • Loading branch information
ip2location authored and jbelien committed Nov 12, 2019
0 parents commit e71fd5b
Show file tree
Hide file tree
Showing 14 changed files with 478 additions and 0 deletions.
4 changes: 4 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
.gitattributes export-ignore
.travis.yml export-ignore
phpunit.xml.dist export-ignore
Tests/ export-ignore
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
vendor/
composer.lock
phpunit.xml
16 changes: 16 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
language: php
sudo: false

php: 7.2


install:
- composer update --prefer-stable --prefer-dist

script:
- composer test-ci

after_success:
- wget https://scrutinizer-ci.com/ocular.phar
- php ocular.phar code-coverage:upload --format=php-clover build/coverage.xml

7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Change Log

The change log describes what is "Added", "Removed", "Changed" or "Fixed" between each release.

## 1.0.0

First release of this library.
146 changes: 146 additions & 0 deletions IP2Location.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
<?php

declare(strict_types=1);

/*
* This file is part of the Geocoder package.
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @license MIT License
*/

namespace Geocoder\Provider\IP2Location;

use Geocoder\Exception\InvalidCredentials;
use Geocoder\Exception\UnsupportedOperation;
use Geocoder\Collection;
use Geocoder\Model\Address;
use Geocoder\Model\AddressCollection;
use Geocoder\Query\GeocodeQuery;
use Geocoder\Query\ReverseQuery;
use Geocoder\Http\Provider\AbstractHttpProvider;
use Geocoder\Provider\Provider;
use Http\Client\HttpClient;

/**
* @author William Durand <william.durand1@gmail.com>
*/
final class IP2Location extends AbstractHttpProvider implements Provider
{
/**
* @var string
*/
const ENDPOINT_URL = 'https://api.ip2location.com/v2/?key=%s&ip=%s&format=json&package=WS9';

/**
* @var string
*/
private $apiKey;

/**
* @var string
*/
private $endpointUrl;

/**
* @param HttpClient $client a HTTP adapter
* @param string $apiKey an API key
*/
public function __construct(HttpClient $client, string $apiKey)
{
parent::__construct($client);

$this->apiKey = $apiKey;
$this->endpointUrl = self::ENDPOINT_URL;
}

/**
* {@inheritdoc}
*/
public function geocodeQuery(GeocodeQuery $query): Collection
{
$address = $query->getText();

if (empty($this->apiKey)) {
throw new InvalidCredentials('No API key provided.');
}

if (!filter_var($address, FILTER_VALIDATE_IP)) {
throw new UnsupportedOperation('The IP2Location provider does not support street addresses, only IP addresses.');
}

if (in_array($address, ['127.0.0.1', '::1'])) {
return new AddressCollection([$this->getLocationForLocalhost()]);
}

$url = sprintf($this->endpointUrl, $this->apiKey, $address);

return $this->executeQuery($url);
}

/**
* {@inheritdoc}
*/
public function reverseQuery(ReverseQuery $query): Collection
{
throw new UnsupportedOperation('The IP2Location provider is not able to do reverse geocoding.');
}

/**
* {@inheritdoc}
*/
public function getName(): string
{
return 'ip2location';
}

/**
* @param string $url
*
* @return Collection
*/
private function executeQuery(string $url): AddressCollection
{
$content = $this->getUrlContents($url);
$data = json_decode($content, true);

if (empty($data)) {
return new AddressCollection([]);
}

if (isset($data['response'])) {
if (preg_match('/suspended|denied|invalid account/i', $data['response'])) {
throw new InvalidCredentials('API Key provided is not valid.');
} elseif (preg_match('/insufficient/i', $data['response'])) {
throw new InvalidCredentials('Insufficient credits to use IP2Location service.');
} elseif (preg_match('/invalid ip address/i', $data['response'])) {
throw new UnsupportedOperation('Invalid IP address.');
} else {
throw new UnsupportedOperation('Unexpected error.');
}
}

if (isset($data['region_name'])) {
$adminLevels = [[
'name' => $data['region_name'],
'level' => 1,
]];
} else {
$adminLevels = [];
}

return new AddressCollection([
Address::createFromArray([
'providedBy' => $this->getName(),
'latitude' => $data['latitude'] ?? null,
'longitude' => $data['longitude'] ?? null,
'locality' => $data['city_name'] ?? null,
'postalCode' => $data['zip_code'] ?? null,
'adminLevels' => $adminLevels,
'country' => $data['country_name'] ?? null,
'countryCode' => $data['country_code'] ?? null,
]),
]);
}
}
21 changes: 21 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
The MIT License (MIT)

Copyright (c) 2011 — William Durand <william.durand1@gmail.com>

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
28 changes: 28 additions & 0 deletions Readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# IP2Location Geocoder provider
[![Build Status](https://travis-ci.org/geocoder-php/ip2location-provider.svg?branch=master)](http://travis-ci.org/geocoder-php/ip2location-provider)
[![Latest Stable Version](https://poser.pugx.org/geocoder-php/ip2location-provider/v/stable)](https://packagist.org/packages/geocoder-php/ip2location-provider)
[![Total Downloads](https://poser.pugx.org/geocoder-php/ip2location-provider/downloads)](https://packagist.org/packages/geocoder-php/ip2location-provider)
[![Monthly Downloads](https://poser.pugx.org/geocoder-php/ip2location-provider/d/monthly.png)](https://packagist.org/packages/geocoder-php/ip2location-provider)
[![Code Coverage](https://img.shields.io/scrutinizer/coverage/g/geocoder-php/ip2location-provider.svg?style=flat-square)](https://scrutinizer-ci.com/g/geocoder-php/ip2location-provider)
[![Quality Score](https://img.shields.io/scrutinizer/g/geocoder-php/ip2location-provider.svg?style=flat-square)](https://scrutinizer-ci.com/g/geocoder-php/ip2location-provider)
[![Software License](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square)](LICENSE)

This is the IP2Location provider from the PHP Geocoder. This is a **READ ONLY** repository. See the
[main repo](https://github.com/geocoder-php/Geocoder) for information and documentation.

### Install

```bash
composer require geocoder-php/ip2location-provider
```

### Note

This provider requires IP2Location™ [IP Geolocation Web Service](https://www.ip2location.com/web-service/ip2location) subscription. It is a paid solution with high accuracy. For free solution, please use our free [IpInfoDB](https://github.com/geocoder-php/Geocoder#ip) project. Ipinfodb is using [IP2Location LITE](https://lite.ip2location.com/) database which has less accuracy at city level.

Please note that this provider is querying IP2Location Web Service **WS9** package and each query will cost **4 credits**.

### Contribute

Contributions are very welcome! Send a pull request to the [main repository](https://github.com/geocoder-php/Geocoder) or
report any issues you find on the [issue tracker](https://github.com/geocoder-php/Geocoder/issues).
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
s:183:"{"country_code":"US","country_name":"United States","region_name":"Oklahoma","city_name":"Tulsa","latitude":"36.15398","longitude":"-95.99278","zip_code":"74101","credits_consumed":4}";
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
s:183:"{"country_code":"US","country_name":"United States","region_name":"Oklahoma","city_name":"Tulsa","latitude":"36.15398","longitude":"-95.99278","zip_code":"74101","credits_consumed":4}";
133 changes: 133 additions & 0 deletions Tests/IP2LocationTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
<?php

declare(strict_types=1);

/*
* This file is part of the Geocoder package.
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @license MIT License
*/

namespace Geocoder\Provider\IP2Location\Tests;

use Geocoder\IntegrationTest\BaseTestCase;
use Geocoder\Location;
use Geocoder\Query\GeocodeQuery;
use Geocoder\Query\ReverseQuery;
use Geocoder\Provider\IP2Location\IP2Location;

class IP2LocationTest extends BaseTestCase
{
protected function getCacheDir()
{
return __DIR__.'/.cached_responses';
}

public function testGetName()
{
$provider = new IP2Location($this->getMockedHttpClient(), 'api_key');
$this->assertEquals('ip2location', $provider->getName());
}

/**
* @expectedException \Geocoder\Exception\UnsupportedOperation
* @expectedExceptionMessage The IP2Location provider does not support street addresses, only IP addresses.
*/
public function testGeocodeWithRandomString()
{
$provider = new IP2Location($this->getMockedHttpClient(), 'api_key');
$provider->geocodeQuery(GeocodeQuery::create('foobar'));
}

/**
* @expectedException \Geocoder\Exception\UnsupportedOperation
* @expectedExceptionMessage The IP2Location provider does not support street addresses, only IP addresses.
*/
public function testGeocodeWithAddress()
{
$provider = new IP2Location($this->getMockedHttpClient(), 'api_key');
$provider->geocodeQuery(GeocodeQuery::create('10 avenue Gambetta, Paris, France'));
}

/**
* @expectedException \Geocoder\Exception\InvalidCredentials
* @expectedExceptionMessage API Key provided is not valid.
*/
public function testGeocodeWithInvalidKey()
{
$provider = new IP2Location($this->getHttpClient('invalid_key'), 'api_key');
$results = $provider->geocodeQuery(GeocodeQuery::create('74.125.45.100'));
}

/**
* @expectedException \Geocoder\Exception\UnsupportedOperation
* @expectedExceptionMessage The IP2Location provider does not support street addresses, only IP addresses.
*/
public function testGeocodeWithInvalidIPAddress()
{
$provider = new IP2Location($this->getMockedHttpClient(), 'api_key');
$provider->geocodeQuery(GeocodeQuery::create('300.23.255.5'));
}

public function testGeocodeWithRealIPv4()
{
if (!isset($_SERVER['IP2LOCATION_API_KEY'])) {
$this->markTestSkipped('You need to configure the IP2LOCATION_API_KEY value in phpunit.xml');
}

$provider = new IP2Location($this->getHttpClient($_SERVER['IP2LOCATION_API_KEY']), $_SERVER['IP2LOCATION_API_KEY']);
$results = $provider->geocodeQuery(GeocodeQuery::create('74.125.45.100'));

$this->assertInstanceOf('Geocoder\Model\AddressCollection', $results);
$this->assertCount(1, $results);

/** @var Location $result */
$result = $results->first();
$this->assertInstanceOf('\Geocoder\Model\Address', $result);
$this->assertEquals(36.154, $result->getCoordinates()->getLatitude(), '', 0.001);
$this->assertEquals(-95.9928, $result->getCoordinates()->getLongitude(), '', 0.001);
$this->assertEquals(74101, $result->getPostalCode());
$this->assertEquals('Tulsa', $result->getLocality());
$this->assertCount(1, $result->getAdminLevels());
$this->assertEquals('Oklahoma', $result->getAdminLevels()->get(1)->getName());
$this->assertEquals('United States', $result->getCountry()->getName());
$this->assertEquals('US', $result->getCountry()->getCode());
}

public function testGeocodeWithRealIPv6()
{
if (!isset($_SERVER['IP2LOCATION_API_KEY'])) {
$this->markTestSkipped('You need to configure the IP2LOCATION_API_KEY value in phpunit.xml');
}

$provider = new IP2Location($this->getHttpClient($_SERVER['IP2LOCATION_API_KEY']), $_SERVER['IP2LOCATION_API_KEY']);
$results = $provider->geocodeQuery(GeocodeQuery::create('::ffff:74.125.45.100'));

$this->assertInstanceOf('Geocoder\Model\AddressCollection', $results);
$this->assertCount(1, $results);

/** @var Location $result */
$result = $results->first();
$this->assertInstanceOf('\Geocoder\Model\Address', $result);
$this->assertEquals(36.154, $result->getCoordinates()->getLatitude(), '', 0.001);
$this->assertEquals(-95.9928, $result->getCoordinates()->getLongitude(), '', 0.001);
$this->assertEquals(74101, $result->getPostalCode());
$this->assertEquals('Tulsa', $result->getLocality());
$this->assertCount(1, $result->getAdminLevels());
$this->assertEquals('Oklahoma', $result->getAdminLevels()->get(1)->getName());
$this->assertEquals('United States', $result->getCountry()->getName());
$this->assertEquals('US', $result->getCountry()->getCode());
}

/**
* @expectedException \Geocoder\Exception\UnsupportedOperation
* @expectedExceptionMessage The IP2Location provider is not able to do reverse geocoding.
*/
public function testReverse()
{
$provider = new IP2Location($this->getMockedHttpClient(), 'api_key');
$provider->reverseQuery(ReverseQuery::fromCoordinates(0, 0));
}
}

0 comments on commit e71fd5b

Please sign in to comment.