Skip to content

Commit ce5d102

Browse files
committed
Add IpInfo provider
0 parents  commit ce5d102

File tree

12 files changed

+419
-0
lines changed

12 files changed

+419
-0
lines changed

.gitattributes

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
.gitattributes export-ignore
2+
.travis.yml export-ignore
3+
phpunit.xml.dist export-ignore
4+
Tests/ export-ignore

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
vendor/
2+
composer.lock
3+
phpunit.xml

.travis.yml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
language: php
2+
sudo: false
3+
4+
php: 7.0
5+
6+
7+
install:
8+
- composer update --prefer-stable --prefer-dist
9+
10+
script:
11+
- composer test-ci
12+
13+
after_success:
14+
- wget https://scrutinizer-ci.com/ocular.phar
15+
- php ocular.phar code-coverage:upload --format=php-clover build/coverage.xml
16+

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# Change Log
2+
3+
The change log describes what is "Added", "Removed", "Changed" or "Fixed" between each release.
4+
5+
## 4.0.0
6+
7+
First release of this library.

IpInfo.php

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/*
6+
* This file is part of the Geocoder package.
7+
* For the full copyright and license information, please view the LICENSE
8+
* file that was distributed with this source code.
9+
*
10+
* @license MIT License
11+
*/
12+
13+
namespace Geocoder\Provider\IpInfo;
14+
15+
use Geocoder\Exception\UnsupportedOperation;
16+
use Geocoder\Collection;
17+
use Geocoder\Model\Address;
18+
use Geocoder\Model\AddressCollection;
19+
use Geocoder\Query\GeocodeQuery;
20+
use Geocoder\Query\ReverseQuery;
21+
use Geocoder\Http\Provider\AbstractHttpProvider;
22+
use Geocoder\Provider\Provider;
23+
24+
/**
25+
* @author Roro Neutron <[email protected]>
26+
*/
27+
final class IpInfo extends AbstractHttpProvider implements Provider
28+
{
29+
/**
30+
* @var string
31+
*/
32+
const ENDPOINT_URL = 'https://ipinfo.io/%s/json';
33+
34+
/**
35+
* {@inheritdoc}
36+
*/
37+
public function geocodeQuery(GeocodeQuery $query): Collection
38+
{
39+
$address = $query->getText();
40+
41+
if (!filter_var($address, FILTER_VALIDATE_IP)) {
42+
throw new UnsupportedOperation('The IpInfo provider does not support street addresses, only IP addresses.');
43+
}
44+
45+
if (in_array($address, ['127.0.0.1', '::1'], true)) {
46+
return new AddressCollection([$this->getLocationForLocalhost()]);
47+
}
48+
49+
return $this->executeQuery(sprintf(self::ENDPOINT_URL, $address));
50+
}
51+
52+
/**
53+
* {@inheritdoc}
54+
*/
55+
public function reverseQuery(ReverseQuery $query): Collection
56+
{
57+
throw new UnsupportedOperation('The IpInfo provider is not able to do reverse geocoding.');
58+
}
59+
60+
/**
61+
* {@inheritdoc}
62+
*/
63+
public function getName(): string
64+
{
65+
return 'ip_info';
66+
}
67+
68+
/**
69+
* @param string $url
70+
*
71+
* @return Collection
72+
*/
73+
private function executeQuery(string $url): AddressCollection
74+
{
75+
$content = $this->getUrlContents($url);
76+
$data = json_decode($content, true);
77+
78+
if (empty($data) || !isset($data['loc']) || '' === $data['loc']) {
79+
return new AddressCollection([]);
80+
}
81+
82+
$location = explode(',', $data['loc']);
83+
84+
return new AddressCollection([
85+
Address::createFromArray([
86+
'providedBy' => $this->getName(),
87+
'latitude' => $location[0],
88+
'longitude' => $location[1],
89+
'locality' => $data['city'] ?? null,
90+
'postalCode' => $data['postal'] ?? null,
91+
'adminLevels' => isset($data['region']) ? [['name' => $data['region'], 'level' => 1]] : [],
92+
'countryCode' => $data['country'] ?? null,
93+
]),
94+
]);
95+
}
96+
}

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
The MIT License (MIT)
2+
3+
Copyright (c) 2011 — William Durand <[email protected]>
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

Readme.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# IpInfo Geocoder provider
2+
3+
This is the IpInfo provider from the PHP Geocoder. This is a **READ ONLY** repository. See the
4+
[main repo](https://github.com/geocoder-php/Geocoder) for information and documentation.
5+
6+
### Install
7+
8+
```bash
9+
composer require geocoder-php/ip-info-provider
10+
```
11+
12+
### Contribute
13+
14+
Contributions are very welcome! Send a pull request to the [main repository](https://github.com/geocoder-php/Geocoder) or
15+
report any issues you find on the [issue tracker](https://github.com/geocoder-php/Geocoder/issues).

Tests/.cached_responses/.gitkeep

Whitespace-only changes.

Tests/IntegrationTest.php

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/*
6+
* This file is part of the Geocoder package.
7+
* For the full copyright and license information, please view the LICENSE
8+
* file that was distributed with this source code.
9+
*
10+
* @license MIT License
11+
*/
12+
13+
namespace Geocoder\Provider\IpInfo\Tests;
14+
15+
use Geocoder\IntegrationTest\ProviderIntegrationTest;
16+
use Geocoder\Provider\IpInfo\IpInfo;
17+
use Http\Client\HttpClient;
18+
19+
/**
20+
* @author Tobias Nyholm <[email protected]>
21+
*/
22+
class IntegrationTest extends ProviderIntegrationTest
23+
{
24+
protected $testAddress = false;
25+
protected $testReverse = false;
26+
protected $testIpv6 = true;
27+
28+
protected function createProvider(HttpClient $httpClient)
29+
{
30+
return new IpInfo($httpClient);
31+
}
32+
33+
protected function getCacheDir()
34+
{
35+
return __DIR__.'/.cached_responses';
36+
}
37+
38+
protected function getApiKey()
39+
{
40+
}
41+
}

Tests/IpInfoTest.php

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/*
6+
* This file is part of the Geocoder package.
7+
* For the full copyright and license information, please view the LICENSE
8+
* file that was distributed with this source code.
9+
*
10+
* @license MIT License
11+
*/
12+
13+
namespace Geocoder\Provider\IpInfo\Tests;
14+
15+
use Geocoder\IntegrationTest\BaseTestCase;
16+
use Geocoder\Location;
17+
use Geocoder\Query\GeocodeQuery;
18+
use Geocoder\Query\ReverseQuery;
19+
use Geocoder\Provider\IpInfo\IpInfo;
20+
21+
class IpInfoTest extends BaseTestCase
22+
{
23+
protected function getCacheDir()
24+
{
25+
return __DIR__.'/.cached_responses';
26+
}
27+
28+
public function testGetName()
29+
{
30+
$provider = new IpInfo($this->getMockedHttpClient());
31+
$this->assertEquals('ip_info', $provider->getName());
32+
}
33+
34+
/**
35+
* @expectedException \Geocoder\Exception\UnsupportedOperation
36+
* @expectedExceptionMessage The IpInfo provider does not support street addresses, only IP addresses.
37+
*/
38+
public function testGeocodeWithRandomString()
39+
{
40+
$provider = new IpInfo($this->getMockedHttpClient());
41+
$provider->geocodeQuery(GeocodeQuery::create('foobar'));
42+
}
43+
44+
/**
45+
* @expectedException \Geocoder\Exception\UnsupportedOperation
46+
* @expectedExceptionMessage The IpInfo provider does not support street addresses, only IP addresses.
47+
*/
48+
public function testGeocodeWithAddress()
49+
{
50+
$provider = new IpInfo($this->getMockedHttpClient());
51+
$provider->geocodeQuery(GeocodeQuery::create('10 avenue Gambetta, Paris, France'));
52+
}
53+
54+
/** @dataProvider provideLocalhostIps */
55+
public function testGeocodeWithLocalhost($localhostIp)
56+
{
57+
$provider = new IpInfo($this->getMockedHttpClient());
58+
$results = $provider->geocodeQuery(GeocodeQuery::create('127.0.0.1'));
59+
60+
$this->assertInstanceOf('Geocoder\Model\AddressCollection', $results);
61+
$this->assertCount(1, $results);
62+
63+
/** @var Location $result */
64+
$result = $results->first();
65+
$this->assertInstanceOf('\Geocoder\Model\Address', $result);
66+
$this->assertNull($result->getCoordinates());
67+
68+
$this->assertNull($result->getPostalCode());
69+
$this->assertNull($result->getTimezone());
70+
$this->assertEmpty($result->getAdminLevels());
71+
72+
$this->assertEquals('localhost', $result->getLocality());
73+
$this->assertEquals('localhost', $result->getCountry()->getName());
74+
}
75+
76+
public function provideLocalhostIps()
77+
{
78+
yield ['127.0.0.1'];
79+
yield ['::1'];
80+
}
81+
82+
/**
83+
* @expectedException \Geocoder\Exception\InvalidServerResponse
84+
*/
85+
public function testGeocodeWithRealIPv4GetsNullContent()
86+
{
87+
$provider = new IpInfo($this->getMockedHttpClient());
88+
$provider->geocodeQuery(GeocodeQuery::create('74.125.45.100'));
89+
}
90+
91+
public function testGeocodeWithRealIPv4()
92+
{
93+
$provider = new IpInfo($this->getHttpClient());
94+
$results = $provider->geocodeQuery(GeocodeQuery::create('74.125.45.100'));
95+
96+
$this->assertInstanceOf('Geocoder\Model\AddressCollection', $results);
97+
$this->assertCount(1, $results);
98+
99+
/** @var Location $result */
100+
$result = $results->first();
101+
$this->assertInstanceOf('\Geocoder\Model\Address', $result);
102+
$this->assertEquals(36.154, $result->getCoordinates()->getLatitude(), '', 0.001);
103+
$this->assertEquals(-95.9928, $result->getCoordinates()->getLongitude(), '', 0.001);
104+
$this->assertEquals(74102, $result->getPostalCode());
105+
$this->assertEquals('Tulsa', $result->getLocality());
106+
$this->assertCount(1, $result->getAdminLevels());
107+
$this->assertEquals('Oklahoma', $result->getAdminLevels()->get(1)->getName());
108+
$this->assertNull($result->getCountry()->getName());
109+
$this->assertEquals('US', $result->getCountry()->getCode());
110+
$this->assertNull($result->getTimezone());
111+
}
112+
113+
public function testGeocodeWithRealIPv6()
114+
{
115+
$provider = new IpInfo($this->getHttpClient());
116+
$results = $provider->geocodeQuery(GeocodeQuery::create('2601:9:7680:363:75df:f491:6f85:352f'));
117+
118+
$this->assertInstanceOf('Geocoder\Model\AddressCollection', $results);
119+
$this->assertCount(1, $results);
120+
121+
/** @var Location $result */
122+
$result = $results->first();
123+
$this->assertInstanceOf('\Geocoder\Model\Address', $result);
124+
$this->assertEquals(37.751, $result->getCoordinates()->getLatitude(), '', 0.001);
125+
$this->assertEquals(-97.822, $result->getCoordinates()->getLongitude(), '', 0.001);
126+
$this->assertNull($result->getPostalCode());
127+
$this->assertEmpty($result->getLocality());
128+
$this->assertNull($result->getCountry()->getName());
129+
$this->assertEquals('US', $result->getCountry()->getCode());
130+
$this->assertNull($result->getTimezone());
131+
}
132+
133+
/**
134+
* @expectedException \Geocoder\Exception\UnsupportedOperation
135+
* @expectedExceptionMessage The IpInfo provider is not able to do reverse geocoding.
136+
*/
137+
public function testReverse()
138+
{
139+
$provider = new IpInfo($this->getMockedHttpClient());
140+
$provider->reverseQuery(ReverseQuery::fromCoordinates(0, 0));
141+
}
142+
}

0 commit comments

Comments
 (0)