-
Notifications
You must be signed in to change notification settings - Fork 517
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #303 from jenswiese/geoip2
Implement MaxData GeoIP2 provider and database adapter
- Loading branch information
Showing
6 changed files
with
624 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,137 @@ | ||
<?php | ||
|
||
/** | ||
* 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\HttpAdapter; | ||
|
||
use Geocoder\Exception\InvalidArgumentException; | ||
use Geocoder\Exception\UnsupportedException; | ||
use GeoIp2\ProviderInterface; | ||
|
||
/** | ||
* @author Jens Wiese <jens@howtrueisfalse.de> | ||
*/ | ||
class GeoIP2Adapter implements HttpAdapterInterface | ||
{ | ||
/** | ||
* GeoIP2 models (e.g. city or country) | ||
*/ | ||
const GEOIP2_MODEL_CITY = 'city'; | ||
const GEOIP2_MODEL_COUNTRY = 'country'; | ||
const GEOIP2_MODEL_OMNI = 'omni'; | ||
|
||
/** | ||
* @var ProviderInterface | ||
*/ | ||
protected $geoIp2Provider; | ||
|
||
/** | ||
* @var string | ||
*/ | ||
protected $geoIP2Model; | ||
|
||
/** | ||
* @var string | ||
*/ | ||
protected $locale; | ||
|
||
/** | ||
* @param \GeoIp2\ProviderInterface $geoIpProvider | ||
* @param string $geoIP2Model (e.g. self::GEOIP2_MODEL_CITY) | ||
* @throws \Geocoder\Exception\UnsupportedException | ||
* @internal param string $dbFile | ||
*/ | ||
public function __construct(ProviderInterface $geoIpProvider, $geoIP2Model = self::GEOIP2_MODEL_CITY) | ||
{ | ||
$this->geoIp2Provider = $geoIpProvider; | ||
|
||
if (false === $this->isSupportedGeoIP2Model($geoIP2Model)) { | ||
throw new UnsupportedException( | ||
sprintf('Model "%s" is not available.', $geoIP2Model) | ||
); | ||
} | ||
|
||
$this->geoIP2Model = $geoIP2Model; | ||
} | ||
|
||
/** | ||
* @param string $locale | ||
* @return $this | ||
*/ | ||
public function setLocale($locale) | ||
{ | ||
$this->locale = $locale; | ||
|
||
return $this; | ||
} | ||
|
||
/** | ||
* @return string | ||
*/ | ||
public function getLocale() | ||
{ | ||
return $this->locale; | ||
} | ||
|
||
/** | ||
* Returns the content fetched from a given resource. | ||
* | ||
* @param string $url (e.g. file://database?127.0.0.1) | ||
* @throws \Geocoder\Exception\UnsupportedException | ||
* @throws \Geocoder\Exception\InvalidArgumentException | ||
* @return string | ||
*/ | ||
public function getContent($url) | ||
{ | ||
if (false === filter_var($url, FILTER_VALIDATE_URL)) { | ||
throw new InvalidArgumentException( | ||
sprintf('"%s" must be called with a valid url. Got "%s" instead.', __METHOD__, $url) | ||
); | ||
} | ||
|
||
$ipAddress = parse_url($url, PHP_URL_QUERY); | ||
|
||
if (false === filter_var($ipAddress, FILTER_VALIDATE_IP)) { | ||
throw new InvalidArgumentException('URL must contain a valid query-string (an IP address, 127.0.0.1 for instance)'); | ||
} | ||
|
||
$result = $this->geoIp2Provider | ||
->{$this->geoIP2Model}($ipAddress) | ||
->jsonSerialize(); | ||
|
||
return json_encode($result); | ||
} | ||
|
||
/** | ||
* Returns the name of the Adapter. | ||
* | ||
* @return string | ||
*/ | ||
public function getName() | ||
{ | ||
return 'maxmind_geoip2'; | ||
} | ||
|
||
/** | ||
* Returns whether method is supported by GeoIP2 | ||
* | ||
* @param string $method | ||
* @return bool | ||
*/ | ||
protected function isSupportedGeoIP2Model($method) | ||
{ | ||
$availableMethods = array( | ||
self::GEOIP2_MODEL_CITY, | ||
self::GEOIP2_MODEL_COUNTRY, | ||
self::GEOIP2_MODEL_OMNI | ||
); | ||
|
||
return in_array($method, $availableMethods); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
<?php | ||
|
||
/** | ||
* 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; | ||
|
||
use Geocoder\Exception\NoResultException; | ||
use Geocoder\Exception\InvalidArgumentException; | ||
use Geocoder\Exception\UnsupportedException; | ||
use Geocoder\HttpAdapter\GeoIP2Adapter; | ||
use Geocoder\HttpAdapter\HttpAdapterInterface; | ||
use GeoIp2\Exception\AddressNotFoundException; | ||
use GeoIp2\Model\City; | ||
|
||
/** | ||
* @author Jens Wiese <jens@howtrueisfalse.de> | ||
*/ | ||
class GeoIP2Provider extends AbstractProvider implements ProviderInterface | ||
{ | ||
/** | ||
* {@inheritdoc} | ||
*/ | ||
public function __construct(HttpAdapterInterface $adapter, $locale = 'en') | ||
{ | ||
if (false === $adapter instanceof GeoIP2Adapter) { | ||
throw new InvalidArgumentException( | ||
'GeoIP2Adapter is needed in order to access the GeoIP2 service.' | ||
); | ||
} | ||
|
||
parent::__construct($adapter, $locale); | ||
} | ||
|
||
/** | ||
* {@inheritDoc} | ||
*/ | ||
public function getGeocodedData($address) | ||
{ | ||
if (false === filter_var($address, FILTER_VALIDATE_IP)) { | ||
throw new UnsupportedException(sprintf('The %s does not support street addresses.', __CLASS__)); | ||
} | ||
|
||
if ('127.0.0.1' === $address) { | ||
return $this->getLocalhostDefaults(); | ||
} | ||
|
||
$result = json_decode($this->executeQuery($address)); | ||
|
||
return array($this->fixEncoding(array_merge($this->getDefaults(), array( | ||
'countryCode' => (isset($result->country->iso_code) ? $result->country->iso_code : null), | ||
'country' => (isset($result->country->names->{$this->locale}) ? $result->country->names->{$this->locale} : null), | ||
'city' => (isset($result->city->names->{$this->locale}) ? $result->city->names->{$this->locale} : null), | ||
'latitude' => (isset($result->location->latitude) ? $result->location->latitude : null), | ||
'longitude' => (isset($result->location->longitude) ? $result->location->longitude : null), | ||
'timezone' => (isset($result->location->timezone) ? $result->location->timezone : null), | ||
'zipcode' => (isset($result->location->postalcode) ? $result->location->postalcode : null), | ||
)))); | ||
} | ||
|
||
/** | ||
* {@inheritDoc} | ||
*/ | ||
public function getReversedData(array $coordinates) | ||
{ | ||
throw new UnsupportedException(sprintf('The %s is not able to do reverse geocoding.', __CLASS__)); | ||
} | ||
|
||
/** | ||
* {@inheritDoc} | ||
*/ | ||
public function getName() | ||
{ | ||
return 'maxmind_geoip2'; | ||
} | ||
|
||
/** | ||
* @param string $address | ||
* @throws \Geocoder\Exception\NoResultException | ||
* @return City | ||
*/ | ||
protected function executeQuery($address) | ||
{ | ||
$uri = sprintf('file://geoip?%s', $address); | ||
|
||
try { | ||
$result = $this->getAdapter()->setLocale($this->locale)->getContent($uri); | ||
} catch (AddressNotFoundException $e) { | ||
throw new NoResultException(sprintf('No results found for IP address %s', $address)); | ||
} | ||
|
||
return $result; | ||
} | ||
|
||
} |
Oops, something went wrong.