Skip to content

Commit 76bbdaa

Browse files
committed
[provider] MaxMind binary provider.
1 parent bfec617 commit 76bbdaa

File tree

7 files changed

+243
-5
lines changed

7 files changed

+243
-5
lines changed

.travis.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,6 @@ php:
77

88
before_script:
99
- curl -s http://getcomposer.org/installer | php
10-
- php composer.phar install --dev --prefer-dist
10+
- php composer.phar install --dev --prefer-dist --no-interaction
1111

1212
script: phpunit --coverage-text

CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ CHANGELOG
33

44
### 1.5.1 (????-??-??) ###
55

6-
n/a
6+
* Added: MaxMind's binary provider
77

88
### 1.5.0 (2013-05-03) ###
99

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,8 @@ Currently, there are many providers for the following APIs:
4747
* [Yandex](http://api.yandex.com.tr/maps/doc/geocoder/desc/concepts/About.xml) as Address-Based geocoding and reverse geocoding provider;
4848
* [GeoPlugin](http://www.geoplugin.com/webservices) as IP-Based geocoding provider;
4949
* [GeoIPs](http://www.geoips.com/developer/geoips-api) as IP-Based geocoding provider;
50-
* [MaxMind web service](http://dev.maxmind.com/geoip/web-services) as IP-Based geocoding provider (City/ISP/Org and Omni services);
50+
* [MaxMind web service](http://dev.maxmind.com/geoip/legacy/web-services) as IP-Based geocoding provider (City/ISP/Org and Omni services);
51+
* [MaxMind binary file](http://dev.maxmind.com/geoip/legacy/downloadable) as IP-Based geocoding provider;
5152
* [Geonames](http://www.geonames.org/) as Place-Based geocoding and reverse geocoding provider;
5253
* [IpGeoBase](http://ipgeobase.ru/) as IP-Based geocoding provider (very accurate in Russia);
5354
* [Baidu](http://developer.baidu.com/map/geocoding-api.htm) as Address-Based geocoding and reverse geocoding provider (exclusively in China);

composer.json

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,15 @@
1717
"require-dev": {
1818
"kriswallsmith/buzz": "@stable",
1919
"guzzle/guzzle": "@stable",
20-
"zendframework/zendframework": "~2.1"
20+
"zendframework/zendframework": "~2.1",
21+
"maxromanovsky/php-maxmind-geoip": "~1.12.1"
2122
},
2223
"suggest": {
2324
"kriswallsmith/buzz": "Enabling Buzz allows you to use the BuzzHttpAdapter.",
2425
"ext-curl": "Enabling the curl extension allows you to use CurlHttpAdapter.",
2526
"guzzle/guzzle": "Enabling Guzzle allows you to use the GuzzleHttpAdapter.",
26-
"zendframework/zend-http": "Enabling Zend Http allows you to use the ZendHttpAdapter."
27+
"zendframework/zend-http": "Enabling Zend Http allows you to use the ZendHttpAdapter.",
28+
"maxromanovsky/php-maxmind-geoip": "If you are going to use MaxMindBinaryProvider."
2729
},
2830
"autoload": {
2931
"psr-0": { "Geocoder": "src/" }
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
<?php
2+
3+
/**
4+
* This file is part of the Geocoder package.
5+
* For the full copyright and license information, please view the LICENSE
6+
* file that was distributed with this source code.
7+
*
8+
* @license MIT License
9+
*/
10+
11+
namespace Geocoder\Provider;
12+
13+
use Geocoder\Provider\ProviderInterface;
14+
use Geocoder\Exception\NoResultException;
15+
use Geocoder\Exception\InvalidArgumentException;
16+
use Geocoder\Exception\RuntimeException;
17+
use Geocoder\Exception\UnsupportedException;
18+
19+
class MaxMindBinaryProvider extends AbstractProvider implements ProviderInterface
20+
{
21+
/**
22+
* @var string
23+
*/
24+
protected $datFile;
25+
26+
/**
27+
* @var int|null
28+
*/
29+
protected $openFlag;
30+
31+
/**
32+
* @param string $datFile
33+
* @param int|null $openFlag
34+
*
35+
* @throws RuntimeException if maxmind's lib not installed.
36+
* @throws InvalidArgumentException if dat file is not correct.
37+
*/
38+
public function __construct($datFile, $openFlag = null)
39+
{
40+
if (false === function_exists('geoip_open')) {
41+
throw new RuntimeException('The MaxMindBinaryProvider requires maxmind\'s lib to be installed and loaded. Have you included geoip.inc file?');
42+
}
43+
if (false === function_exists('GeoIP_record_by_addr')) {
44+
throw new RuntimeException('The MaxMindBinaryProvider requires maxmind\'s lib to be installed and loaded. Have you included geoipcity.inc file?');
45+
}
46+
47+
if (false === is_file($datFile)) {
48+
throw new InvalidArgumentException(sprintf('Given MaxMind dat file %s is not exist.', $this->datFile));
49+
}
50+
if (false === is_readable($datFile)) {
51+
throw new InvalidArgumentException(sprintf('Given MaxMind dat file %s is not readable.', $this->datFile));
52+
}
53+
$this->datFile = $datFile;
54+
55+
$this->openFlag = null === $openFlag ? GEOIP_STANDARD : $openFlag;
56+
}
57+
58+
/**
59+
* {@inheritDoc}
60+
*/
61+
public function getGeocodedData($address)
62+
{
63+
if (false === filter_var($address, FILTER_VALIDATE_IP)) {
64+
throw new UnsupportedException('The MaxMindBinaryProvider does not support street addresses.');
65+
}
66+
67+
$geoIp = geoip_open($this->datFile, $this->openFlag);
68+
69+
$geoIpRecord = GeoIP_record_by_addr($geoIp, $address);
70+
71+
geoip_close($geoIp);
72+
73+
if (false === $geoIpRecord instanceof \geoiprecord) {
74+
throw new NoResultException(sprintf('No results found for IP address %s', $address));
75+
}
76+
77+
return array_merge($this->getDefaults(), array(
78+
'countryCode' => $geoIpRecord->country_code,
79+
'country' => $geoIpRecord->country_name,
80+
'region' => $geoIpRecord->region,
81+
'city' => $geoIpRecord->city,
82+
'latitude' => $geoIpRecord->latitude,
83+
'longitude' => $geoIpRecord->longitude,
84+
));
85+
}
86+
87+
/**
88+
* {@inheritDoc}
89+
*/
90+
public function getReversedData(array $coordinates)
91+
{
92+
throw new UnsupportedException('The MaxMindBinaryProvider is not able to do reverse geocoding.');
93+
}
94+
95+
/**
96+
* {@inheritDoc}
97+
*/
98+
public function getName()
99+
{
100+
return 'maxmind_binary';
101+
}
102+
}
Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
<?php
2+
namespace Geocoder\Tests\Provider;
3+
4+
use Geocoder\Provider\MaxMindBinaryProvider;
5+
6+
class MaxMindBinaryProviderTest extends \PHPUnit_Framework_TestCase
7+
{
8+
public static function setUpBeforeClass()
9+
{
10+
if (false == function_exists('geoip_open')) {
11+
throw new \PHPUnit_Framework_SkippedTestError('The maxmind\'s official lib required to run these tests.');
12+
}
13+
if (false == function_exists('GeoIP_record_by_addr')) {
14+
throw new \PHPUnit_Framework_SkippedTestError('The maxmind\'s official lib required to run these tests.');
15+
}
16+
}
17+
18+
public static function provideIps()
19+
{
20+
return array(
21+
'24.24.24.24' => array('24.24.24.24', 'East Syracuse', 'United States'),
22+
'80.24.24.24' => array('80.24.24.24', 'Sabadell', 'Spain'),
23+
);
24+
}
25+
26+
/**
27+
* @expectedException \Geocoder\Exception\InvalidArgumentException
28+
* @expectedExceptionMessage Given MaxMind dat file is not exist.
29+
*/
30+
public function testThrowIfNotExistBinaryFileGiven()
31+
{
32+
new MaxMindBinaryProvider('not_exist.dat');
33+
}
34+
35+
/**
36+
* @dataProvider provideIps
37+
*/
38+
public function testLocationResultContainsExpectedFields($ip)
39+
{
40+
$binaryFile = __DIR__.'/fixtures/GeoLiteCity.dat';
41+
42+
$provider = new MaxMindBinaryProvider($binaryFile);
43+
44+
$result = $provider->getGeocodedData($ip);
45+
46+
$this->assertInternalType('array', $result);
47+
48+
$this->assertArrayHasKey('country', $result);
49+
$this->assertArrayHasKey('countryCode', $result);
50+
$this->assertArrayHasKey('regionCode', $result);
51+
$this->assertArrayHasKey('city', $result);
52+
$this->assertArrayHasKey('latitude', $result);
53+
$this->assertArrayHasKey('longitude', $result);
54+
$this->assertArrayHasKey('zipcode', $result);
55+
$this->assertArrayHasKey('bounds', $result);
56+
$this->assertArrayHasKey('streetNumber', $result);
57+
$this->assertArrayHasKey('streetName', $result);
58+
$this->assertArrayHasKey('cityDistrict', $result);
59+
$this->assertArrayHasKey('county', $result);
60+
$this->assertArrayHasKey('countyCode', $result);
61+
$this->assertArrayHasKey('region', $result);
62+
$this->assertArrayHasKey('timezone', $result);
63+
}
64+
65+
/**
66+
* @dataProvider provideIps
67+
*/
68+
public function testFindLocationByIp($ip, $expectedCity, $expectedCountry)
69+
{
70+
$binaryFile = __DIR__.'/fixtures/GeoLiteCity.dat';
71+
72+
$provider = new MaxMindBinaryProvider($binaryFile);
73+
74+
$result = $provider->getGeocodedData($ip);
75+
76+
$this->assertInternalType('array', $result);
77+
78+
$this->assertArrayHasKey('city', $result);
79+
$this->assertEquals($expectedCity, $result['city']);
80+
81+
$this->assertArrayHasKey('country', $result);
82+
$this->assertEquals($expectedCountry, $result['country']);
83+
}
84+
85+
public function testGetName()
86+
{
87+
$binaryFile = __DIR__.'/fixtures/GeoLiteCity.dat';
88+
89+
$provider = new MaxMindBinaryProvider($binaryFile);
90+
91+
$this->assertEquals('maxmind_binary', $provider->getName());
92+
}
93+
94+
/**
95+
* @expectedException \Geocoder\Exception\NoResultException
96+
* @expectedExceptionMessage No results found for IP address 127.0.0.1
97+
*/
98+
public function testThrowIfIpAddressCouldNotBeLocated()
99+
{
100+
$binaryFile = __DIR__.'/fixtures/GeoLiteCity.dat';
101+
102+
$provider = new MaxMindBinaryProvider($binaryFile);
103+
104+
$provider->getGeocodedData('127.0.0.1');
105+
}
106+
107+
/**
108+
* @expectedException \Geocoder\Exception\UnsupportedException
109+
* @expectedExceptionMessage The MaxMindBinaryProvider does not support street addresses.
110+
*/
111+
public function testThrowIfInvalidIpAddressGiven()
112+
{
113+
$binaryFile = __DIR__.'/fixtures/GeoLiteCity.dat';
114+
115+
$provider = new MaxMindBinaryProvider($binaryFile);
116+
117+
$provider->getGeocodedData('invalidIp');
118+
}
119+
120+
/**
121+
* @expectedException \Geocoder\Exception\UnsupportedException
122+
* @expectedExceptionMessage The MaxMindBinaryProvider is not able to do reverse geocoding.
123+
*/
124+
public function testThrowOnReversedDataMethodUsage()
125+
{
126+
$binaryFile = __DIR__.'/fixtures/GeoLiteCity.dat';
127+
128+
$provider = new MaxMindBinaryProvider($binaryFile);
129+
130+
$provider->getReversedData(array());
131+
}
132+
133+
}
17.5 MB
Binary file not shown.

0 commit comments

Comments
 (0)