mirror of
https://github.com/moodle/moodle.git
synced 2025-04-13 04:22:07 +02:00
MDL-48766 lib: Import MaxMind GeoIP2 PHP API
No changes from the upstream version have been made, it is recommended by upstream to install these depdencies via composer - but the composer installation is bundled with a load of test files, shell scripts etc (and we don't use composer to manage 'production dependencies') so we have to do it manually.
This commit is contained in:
parent
054da30ba9
commit
eacc36a26b
@ -49,6 +49,8 @@ lib/amd/src/mustache.js
|
||||
lib/graphlib.php
|
||||
lib/spout/
|
||||
lib/amd/src/chartjs-lazy.js
|
||||
lib/maxmind/GeoIP2/
|
||||
lib/maxmind/MaxMind/
|
||||
mod/assign/feedback/editpdf/fpdi/
|
||||
repository/s3/S3.php
|
||||
theme/bootstrapbase/less/bootstrap/
|
||||
|
@ -48,6 +48,8 @@ lib/amd/src/mustache.js
|
||||
lib/graphlib.php
|
||||
lib/spout/
|
||||
lib/amd/src/chartjs-lazy.js
|
||||
lib/maxmind/GeoIP2/
|
||||
lib/maxmind/MaxMind/
|
||||
mod/assign/feedback/editpdf/fpdi/
|
||||
repository/s3/S3.php
|
||||
theme/bootstrapbase/less/bootstrap/
|
||||
|
@ -73,6 +73,8 @@ class core_component {
|
||||
);
|
||||
/** @var array associative array of PRS-4 namespaces and corresponding paths. */
|
||||
protected static $psr4namespaces = array(
|
||||
'MaxMind' => 'lib/maxmind/MaxMind',
|
||||
'GeoIp2' => 'lib/maxmind/GeoIP2',
|
||||
);
|
||||
|
||||
/**
|
||||
|
27
lib/maxmind/GeoIp2/Compat/JsonSerializable.php
Normal file
27
lib/maxmind/GeoIp2/Compat/JsonSerializable.php
Normal file
@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
namespace GeoIp2\Compat;
|
||||
|
||||
// @codingStandardsIgnoreFile
|
||||
|
||||
/**
|
||||
* This interface exists to provide backwards compatibility with PHP 5.3
|
||||
*
|
||||
* This should _not_ be used by any third-party code.
|
||||
*
|
||||
* @ignore
|
||||
*/
|
||||
if (interface_exists('JsonSerializable')) {
|
||||
interface JsonSerializable extends \JsonSerializable
|
||||
{
|
||||
}
|
||||
} else {
|
||||
interface JsonSerializable
|
||||
{
|
||||
/**
|
||||
* Returns data that can be serialized by json_encode
|
||||
* @ignore
|
||||
*/
|
||||
public function jsonSerialize();
|
||||
}
|
||||
}
|
246
lib/maxmind/GeoIp2/Database/Reader.php
Normal file
246
lib/maxmind/GeoIp2/Database/Reader.php
Normal file
@ -0,0 +1,246 @@
|
||||
<?php
|
||||
|
||||
namespace GeoIp2\Database;
|
||||
|
||||
use GeoIp2\Exception\AddressNotFoundException;
|
||||
use GeoIp2\ProviderInterface;
|
||||
use MaxMind\Db\Reader as DbReader;
|
||||
|
||||
/**
|
||||
* Instances of this class provide a reader for the GeoIP2 database format.
|
||||
* IP addresses can be looked up using the database specific methods.
|
||||
*
|
||||
* ## Usage ##
|
||||
*
|
||||
* The basic API for this class is the same for every database. First, you
|
||||
* create a reader object, specifying a file name. You then call the method
|
||||
* corresponding to the specific database, passing it the IP address you want
|
||||
* to look up.
|
||||
*
|
||||
* If the request succeeds, the method call will return a model class for
|
||||
* the method you called. This model in turn contains multiple record classes,
|
||||
* each of which represents part of the data returned by the database. If
|
||||
* the database does not contain the requested information, the attributes
|
||||
* on the record class will have a `null` value.
|
||||
*
|
||||
* If the address is not in the database, an
|
||||
* {@link \GeoIp2\Exception\AddressNotFoundException} exception will be
|
||||
* thrown. If an invalid IP address is passed to one of the methods, a
|
||||
* SPL {@link \InvalidArgumentException} will be thrown. If the database is
|
||||
* corrupt or invalid, a {@link \MaxMind\Db\Reader\InvalidDatabaseException}
|
||||
* will be thrown.
|
||||
*
|
||||
*/
|
||||
class Reader implements ProviderInterface
|
||||
{
|
||||
private $dbReader;
|
||||
private $locales;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param string $filename The path to the GeoIP2 database file.
|
||||
* @param array $locales List of locale codes to use in name property
|
||||
* from most preferred to least preferred.
|
||||
* @throws \MaxMind\Db\Reader\InvalidDatabaseException if the database
|
||||
* is corrupt or invalid
|
||||
*/
|
||||
public function __construct(
|
||||
$filename,
|
||||
$locales = array('en')
|
||||
) {
|
||||
$this->dbReader = new DbReader($filename);
|
||||
$this->locales = $locales;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method returns a GeoIP2 City model.
|
||||
*
|
||||
* @param string $ipAddress IPv4 or IPv6 address as a string.
|
||||
*
|
||||
* @return \GeoIp2\Model\City
|
||||
*
|
||||
* @throws \GeoIp2\Exception\AddressNotFoundException if the address is
|
||||
* not in the database.
|
||||
* @throws \MaxMind\Db\Reader\InvalidDatabaseException if the database
|
||||
* is corrupt or invalid
|
||||
*/
|
||||
public function city($ipAddress)
|
||||
{
|
||||
return $this->modelFor('City', 'City', $ipAddress);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method returns a GeoIP2 Country model.
|
||||
*
|
||||
* @param string $ipAddress IPv4 or IPv6 address as a string.
|
||||
*
|
||||
* @return \GeoIp2\Model\Country
|
||||
*
|
||||
* @throws \GeoIp2\Exception\AddressNotFoundException if the address is
|
||||
* not in the database.
|
||||
* @throws \MaxMind\Db\Reader\InvalidDatabaseException if the database
|
||||
* is corrupt or invalid
|
||||
*/
|
||||
public function country($ipAddress)
|
||||
{
|
||||
return $this->modelFor('Country', 'Country', $ipAddress);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method returns a GeoIP2 Anonymous IP model.
|
||||
*
|
||||
* @param string $ipAddress IPv4 or IPv6 address as a string.
|
||||
*
|
||||
* @return \GeoIp2\Model\AnonymousIp
|
||||
*
|
||||
* @throws \GeoIp2\Exception\AddressNotFoundException if the address is
|
||||
* not in the database.
|
||||
* @throws \MaxMind\Db\Reader\InvalidDatabaseException if the database
|
||||
* is corrupt or invalid
|
||||
*/
|
||||
public function anonymousIp($ipAddress)
|
||||
{
|
||||
return $this->flatModelFor(
|
||||
'AnonymousIp',
|
||||
'GeoIP2-Anonymous-IP',
|
||||
$ipAddress
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method returns a GeoIP2 Connection Type model.
|
||||
*
|
||||
* @param string $ipAddress IPv4 or IPv6 address as a string.
|
||||
*
|
||||
* @return \GeoIp2\Model\ConnectionType
|
||||
*
|
||||
* @throws \GeoIp2\Exception\AddressNotFoundException if the address is
|
||||
* not in the database.
|
||||
* @throws \MaxMind\Db\Reader\InvalidDatabaseException if the database
|
||||
* is corrupt or invalid
|
||||
*/
|
||||
public function connectionType($ipAddress)
|
||||
{
|
||||
return $this->flatModelFor(
|
||||
'ConnectionType',
|
||||
'GeoIP2-Connection-Type',
|
||||
$ipAddress
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method returns a GeoIP2 Domain model.
|
||||
*
|
||||
* @param string $ipAddress IPv4 or IPv6 address as a string.
|
||||
*
|
||||
* @return \GeoIp2\Model\Domain
|
||||
*
|
||||
* @throws \GeoIp2\Exception\AddressNotFoundException if the address is
|
||||
* not in the database.
|
||||
* @throws \MaxMind\Db\Reader\InvalidDatabaseException if the database
|
||||
* is corrupt or invalid
|
||||
*/
|
||||
public function domain($ipAddress)
|
||||
{
|
||||
return $this->flatModelFor(
|
||||
'Domain',
|
||||
'GeoIP2-Domain',
|
||||
$ipAddress
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method returns a GeoIP2 Enterprise model.
|
||||
*
|
||||
* @param string $ipAddress IPv4 or IPv6 address as a string.
|
||||
*
|
||||
* @return \GeoIp2\Model\Enterprise
|
||||
*
|
||||
* @throws \GeoIp2\Exception\AddressNotFoundException if the address is
|
||||
* not in the database.
|
||||
* @throws \MaxMind\Db\Reader\InvalidDatabaseException if the database
|
||||
* is corrupt or invalid
|
||||
*/
|
||||
public function enterprise($ipAddress)
|
||||
{
|
||||
return $this->modelFor('Enterprise', 'Enterprise', $ipAddress);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method returns a GeoIP2 ISP model.
|
||||
*
|
||||
* @param string $ipAddress IPv4 or IPv6 address as a string.
|
||||
*
|
||||
* @return \GeoIp2\Model\Isp
|
||||
*
|
||||
* @throws \GeoIp2\Exception\AddressNotFoundException if the address is
|
||||
* not in the database.
|
||||
* @throws \MaxMind\Db\Reader\InvalidDatabaseException if the database
|
||||
* is corrupt or invalid
|
||||
*/
|
||||
public function isp($ipAddress)
|
||||
{
|
||||
return $this->flatModelFor(
|
||||
'Isp',
|
||||
'GeoIP2-ISP',
|
||||
$ipAddress
|
||||
);
|
||||
}
|
||||
|
||||
private function modelFor($class, $type, $ipAddress)
|
||||
{
|
||||
$record = $this->getRecord($class, $type, $ipAddress);
|
||||
|
||||
$record['traits']['ip_address'] = $ipAddress;
|
||||
$class = "GeoIp2\\Model\\" . $class;
|
||||
|
||||
return new $class($record, $this->locales);
|
||||
}
|
||||
|
||||
private function flatModelFor($class, $type, $ipAddress)
|
||||
{
|
||||
$record = $this->getRecord($class, $type, $ipAddress);
|
||||
|
||||
$record['ip_address'] = $ipAddress;
|
||||
$class = "GeoIp2\\Model\\" . $class;
|
||||
|
||||
return new $class($record);
|
||||
}
|
||||
|
||||
private function getRecord($class, $type, $ipAddress)
|
||||
{
|
||||
if (strpos($this->metadata()->databaseType, $type) === false) {
|
||||
$method = lcfirst($class);
|
||||
throw new \BadMethodCallException(
|
||||
"The $method method cannot be used to open a "
|
||||
. $this->metadata()->databaseType . " database"
|
||||
);
|
||||
}
|
||||
$record = $this->dbReader->get($ipAddress);
|
||||
if ($record === null) {
|
||||
throw new AddressNotFoundException(
|
||||
"The address $ipAddress is not in the database."
|
||||
);
|
||||
}
|
||||
return $record;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \InvalidArgumentException if arguments are passed to the method.
|
||||
* @throws \BadMethodCallException if the database has been closed.
|
||||
* @return \MaxMind\Db\Reader\Metadata object for the database.
|
||||
*/
|
||||
public function metadata()
|
||||
{
|
||||
return $this->dbReader->metadata();
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the GeoIP2 database and returns the resources to the system.
|
||||
*/
|
||||
public function close()
|
||||
{
|
||||
$this->dbReader->close();
|
||||
}
|
||||
}
|
10
lib/maxmind/GeoIp2/Exception/AddressNotFoundException.php
Normal file
10
lib/maxmind/GeoIp2/Exception/AddressNotFoundException.php
Normal file
@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace GeoIp2\Exception;
|
||||
|
||||
/**
|
||||
* This class represents a generic error.
|
||||
*/
|
||||
class AddressNotFoundException extends GeoIp2Exception
|
||||
{
|
||||
}
|
10
lib/maxmind/GeoIp2/Exception/AuthenticationException.php
Normal file
10
lib/maxmind/GeoIp2/Exception/AuthenticationException.php
Normal file
@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace GeoIp2\Exception;
|
||||
|
||||
/**
|
||||
* This class represents a generic error.
|
||||
*/
|
||||
class AuthenticationException extends GeoIp2Exception
|
||||
{
|
||||
}
|
10
lib/maxmind/GeoIp2/Exception/GeoIp2Exception.php
Normal file
10
lib/maxmind/GeoIp2/Exception/GeoIp2Exception.php
Normal file
@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace GeoIp2\Exception;
|
||||
|
||||
/**
|
||||
* This class represents a generic error.
|
||||
*/
|
||||
class GeoIp2Exception extends \Exception
|
||||
{
|
||||
}
|
25
lib/maxmind/GeoIp2/Exception/HttpException.php
Normal file
25
lib/maxmind/GeoIp2/Exception/HttpException.php
Normal file
@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace GeoIp2\Exception;
|
||||
|
||||
/**
|
||||
* This class represents an HTTP transport error.
|
||||
*/
|
||||
|
||||
class HttpException extends GeoIp2Exception
|
||||
{
|
||||
/**
|
||||
* The URI queried
|
||||
*/
|
||||
public $uri;
|
||||
|
||||
public function __construct(
|
||||
$message,
|
||||
$httpStatus,
|
||||
$uri,
|
||||
\Exception $previous = null
|
||||
) {
|
||||
$this->uri = $uri;
|
||||
parent::__construct($message, $httpStatus, $previous);
|
||||
}
|
||||
}
|
26
lib/maxmind/GeoIp2/Exception/InvalidRequestException.php
Normal file
26
lib/maxmind/GeoIp2/Exception/InvalidRequestException.php
Normal file
@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
namespace GeoIp2\Exception;
|
||||
|
||||
/**
|
||||
* This class represents an error returned by MaxMind's GeoIP2
|
||||
* web service.
|
||||
*/
|
||||
class InvalidRequestException extends HttpException
|
||||
{
|
||||
/**
|
||||
* The code returned by the MaxMind web service
|
||||
*/
|
||||
public $error;
|
||||
|
||||
public function __construct(
|
||||
$message,
|
||||
$error,
|
||||
$httpStatus,
|
||||
$uri,
|
||||
\Exception $previous = null
|
||||
) {
|
||||
$this->error = $error;
|
||||
parent::__construct($message, $httpStatus, $uri, $previous);
|
||||
}
|
||||
}
|
10
lib/maxmind/GeoIp2/Exception/OutOfQueriesException.php
Normal file
10
lib/maxmind/GeoIp2/Exception/OutOfQueriesException.php
Normal file
@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace GeoIp2\Exception;
|
||||
|
||||
/**
|
||||
* This class represents a generic error.
|
||||
*/
|
||||
class OutOfQueriesException extends GeoIp2Exception
|
||||
{
|
||||
}
|
62
lib/maxmind/GeoIp2/Model/AbstractModel.php
Normal file
62
lib/maxmind/GeoIp2/Model/AbstractModel.php
Normal file
@ -0,0 +1,62 @@
|
||||
<?php
|
||||
|
||||
namespace GeoIp2\Model;
|
||||
|
||||
use GeoIp2\Compat\JsonSerializable;
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
abstract class AbstractModel implements JsonSerializable
|
||||
{
|
||||
protected $raw;
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
public function __construct($raw)
|
||||
{
|
||||
$this->raw = $raw;
|
||||
}
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
protected function get($field)
|
||||
{
|
||||
if (isset($this->raw[$field])) {
|
||||
return $this->raw[$field];
|
||||
} else {
|
||||
if (preg_match('/^is_/', $field)) {
|
||||
return false;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
public function __get($attr)
|
||||
{
|
||||
if ($attr != "instance" && property_exists($this, $attr)) {
|
||||
return $this->$attr;
|
||||
}
|
||||
|
||||
throw new \RuntimeException("Unknown attribute: $attr");
|
||||
}
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
public function __isset($attr)
|
||||
{
|
||||
return $attr != "instance" && isset($this->$attr);
|
||||
}
|
||||
|
||||
public function jsonSerialize()
|
||||
{
|
||||
return $this->raw;
|
||||
}
|
||||
}
|
50
lib/maxmind/GeoIp2/Model/AnonymousIp.php
Normal file
50
lib/maxmind/GeoIp2/Model/AnonymousIp.php
Normal file
@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
namespace GeoIp2\Model;
|
||||
|
||||
/**
|
||||
* This class provides the GeoIP2 Anonymous IP model.
|
||||
*
|
||||
* @property-read boolean $isAnonymous This is true if the IP address belongs to
|
||||
* any sort of anonymous network.
|
||||
*
|
||||
* @property-read boolean $isAnonymousVpn This is true if the IP address belongs to
|
||||
* an anonymous VPN system.
|
||||
*
|
||||
* @property-read boolean $isHostingProvider This is true if the IP address belongs
|
||||
* to a hosting provider.
|
||||
*
|
||||
* @property-read boolean $isPublicProxy This is true if the IP address belongs to
|
||||
* a public proxy.
|
||||
*
|
||||
* @property-read boolean $isTorExitNode This is true if the IP address is a Tor
|
||||
* exit node.
|
||||
*
|
||||
* @property-read string $ipAddress The IP address that the data in the model is
|
||||
* for.
|
||||
*
|
||||
*/
|
||||
class AnonymousIp extends AbstractModel
|
||||
{
|
||||
protected $isAnonymous;
|
||||
protected $isAnonymousVpn;
|
||||
protected $isHostingProvider;
|
||||
protected $isPublicProxy;
|
||||
protected $isTorExitNode;
|
||||
protected $ipAddress;
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
public function __construct($raw)
|
||||
{
|
||||
parent::__construct($raw);
|
||||
|
||||
$this->isAnonymous = $this->get('is_anonymous');
|
||||
$this->isAnonymousVpn = $this->get('is_anonymous_vpn');
|
||||
$this->isHostingProvider = $this->get('is_hosting_provider');
|
||||
$this->isPublicProxy = $this->get('is_public_proxy');
|
||||
$this->isTorExitNode = $this->get('is_tor_exit_node');
|
||||
$this->ipAddress = $this->get('ip_address');
|
||||
}
|
||||
}
|
122
lib/maxmind/GeoIp2/Model/City.php
Normal file
122
lib/maxmind/GeoIp2/Model/City.php
Normal file
@ -0,0 +1,122 @@
|
||||
<?php
|
||||
|
||||
namespace GeoIp2\Model;
|
||||
|
||||
/**
|
||||
* Model class for the data returned by GeoIP2 City web service and database.
|
||||
*
|
||||
* The only difference between the City and Insights model classes is which
|
||||
* fields in each record may be populated. See
|
||||
* http://dev.maxmind.com/geoip/geoip2/web-services more details.
|
||||
*
|
||||
* @property-read \GeoIp2\Record\City $city City data for the requested IP
|
||||
* address.
|
||||
*
|
||||
* @property-read \GeoIp2\Record\Continent $continent Continent data for the
|
||||
* requested IP address.
|
||||
*
|
||||
* @property-read \GeoIp2\Record\Country $country Country data for the requested
|
||||
* IP address. This object represents the country where MaxMind believes the
|
||||
* end user is located.
|
||||
*
|
||||
* @property-read \GeoIp2\Record\Location $location Location data for the
|
||||
* requested IP address.
|
||||
*
|
||||
* @property-read \GeoIp2\Record\Postal $postal Postal data for the
|
||||
* requested IP address.
|
||||
*
|
||||
* @property-read \GeoIp2\Record\MaxMind $maxmind Data related to your MaxMind
|
||||
* account.
|
||||
*
|
||||
* @property-read \GeoIp2\Record\Country $registeredCountry Registered country
|
||||
* data for the requested IP address. This record represents the country
|
||||
* where the ISP has registered a given IP block and may differ from the
|
||||
* user's country.
|
||||
*
|
||||
* @property-read \GeoIp2\Record\RepresentedCountry $representedCountry
|
||||
* Represented country data for the requested IP address. The represented
|
||||
* country is used for things like military bases. It is only present when
|
||||
* the represented country differs from the country.
|
||||
*
|
||||
* @property-read array $subdivisions An array of {@link \GeoIp2\Record\Subdivision}
|
||||
* objects representing the country subdivisions for the requested IP
|
||||
* address. The number and type of subdivisions varies by country, but a
|
||||
* subdivision is typically a state, province, county, etc. Subdivisions
|
||||
* are ordered from most general (largest) to most specific (smallest).
|
||||
* If the response did not contain any subdivisions, this method returns
|
||||
* an empty array.
|
||||
*
|
||||
* @property-read \GeoIp2\Record\Subdivision $mostSpecificSubdivision An object
|
||||
* representing the most specific subdivision returned. If the response
|
||||
* did not contain any subdivisions, this method returns an empty
|
||||
* {@link \GeoIp2\Record\Subdivision} object.
|
||||
*
|
||||
* @property-read \GeoIp2\Record\Traits $traits Data for the traits of the
|
||||
* requested IP address.
|
||||
*/
|
||||
class City extends Country
|
||||
{
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
protected $city;
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
protected $location;
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
protected $postal;
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
protected $subdivisions = array();
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
public function __construct($raw, $locales = array('en'))
|
||||
{
|
||||
parent::__construct($raw, $locales);
|
||||
|
||||
$this->city = new \GeoIp2\Record\City($this->get('city'), $locales);
|
||||
$this->location = new \GeoIp2\Record\Location($this->get('location'));
|
||||
$this->postal = new \GeoIp2\Record\Postal($this->get('postal'));
|
||||
|
||||
$this->createSubdivisions($raw, $locales);
|
||||
}
|
||||
|
||||
private function createSubdivisions($raw, $locales)
|
||||
{
|
||||
if (!isset($raw['subdivisions'])) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($raw['subdivisions'] as $sub) {
|
||||
array_push(
|
||||
$this->subdivisions,
|
||||
new \GeoIp2\Record\Subdivision($sub, $locales)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
public function __get($attr)
|
||||
{
|
||||
if ($attr == 'mostSpecificSubdivision') {
|
||||
return $this->$attr();
|
||||
} else {
|
||||
return parent::__get($attr);
|
||||
}
|
||||
}
|
||||
|
||||
private function mostSpecificSubdivision()
|
||||
{
|
||||
return empty($this->subdivisions) ?
|
||||
new \GeoIp2\Record\Subdivision(array(), $this->locales) :
|
||||
end($this->subdivisions);
|
||||
}
|
||||
}
|
31
lib/maxmind/GeoIp2/Model/ConnectionType.php
Normal file
31
lib/maxmind/GeoIp2/Model/ConnectionType.php
Normal file
@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace GeoIp2\Model;
|
||||
|
||||
/**
|
||||
* This class provides the GeoIP2 Connection-Type model.
|
||||
*
|
||||
* @property-read string|null $connectionType The connection type may take the
|
||||
* following values: "Dialup", "Cable/DSL", "Corporate", "Cellular".
|
||||
* Additional values may be added in the future.
|
||||
*
|
||||
* @property-read string $ipAddress The IP address that the data in the model is
|
||||
* for.
|
||||
*
|
||||
*/
|
||||
class ConnectionType extends AbstractModel
|
||||
{
|
||||
protected $connectionType;
|
||||
protected $ipAddress;
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
public function __construct($raw)
|
||||
{
|
||||
parent::__construct($raw);
|
||||
|
||||
$this->connectionType = $this->get('connection_type');
|
||||
$this->ipAddress = $this->get('ip_address');
|
||||
}
|
||||
}
|
73
lib/maxmind/GeoIp2/Model/Country.php
Normal file
73
lib/maxmind/GeoIp2/Model/Country.php
Normal file
@ -0,0 +1,73 @@
|
||||
<?php
|
||||
|
||||
namespace GeoIp2\Model;
|
||||
|
||||
/**
|
||||
* Model class for the data returned by GeoIP2 Country web service and database.
|
||||
*
|
||||
* The only difference between the City and Insights model classes is which
|
||||
* fields in each record may be populated. See
|
||||
* http://dev.maxmind.com/geoip/geoip2/web-services more details.
|
||||
*
|
||||
* @property-read \GeoIp2\Record\Continent $continent Continent data for the
|
||||
* requested IP address.
|
||||
*
|
||||
* @property-read \GeoIp2\Record\Country $country Country data for the requested
|
||||
* IP address. This object represents the country where MaxMind believes the
|
||||
* end user is located.
|
||||
*
|
||||
* @property-read \GeoIp2\Record\MaxMind $maxmind Data related to your MaxMind
|
||||
* account.
|
||||
*
|
||||
* @property-read \GeoIp2\Record\Country $registeredCountry Registered country
|
||||
* data for the requested IP address. This record represents the country
|
||||
* where the ISP has registered a given IP block and may differ from the
|
||||
* user's country.
|
||||
*
|
||||
* @property-read \GeoIp2\Record\RepresentedCountry $representedCountry
|
||||
* Represented country data for the requested IP address. The represented
|
||||
* country is used for things like military bases. It is only present when
|
||||
* the represented country differs from the country.
|
||||
*
|
||||
* @property-read \GeoIp2\Record\Traits $traits Data for the traits of the
|
||||
* requested IP address.
|
||||
*/
|
||||
class Country extends AbstractModel
|
||||
{
|
||||
protected $continent;
|
||||
protected $country;
|
||||
protected $locales;
|
||||
protected $maxmind;
|
||||
protected $registeredCountry;
|
||||
protected $representedCountry;
|
||||
protected $traits;
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
public function __construct($raw, $locales = array('en'))
|
||||
{
|
||||
parent::__construct($raw);
|
||||
|
||||
$this->continent = new \GeoIp2\Record\Continent(
|
||||
$this->get('continent'),
|
||||
$locales
|
||||
);
|
||||
$this->country = new \GeoIp2\Record\Country(
|
||||
$this->get('country'),
|
||||
$locales
|
||||
);
|
||||
$this->maxmind = new \GeoIp2\Record\MaxMind($this->get('maxmind'));
|
||||
$this->registeredCountry = new \GeoIp2\Record\Country(
|
||||
$this->get('registered_country'),
|
||||
$locales
|
||||
);
|
||||
$this->representedCountry = new \GeoIp2\Record\RepresentedCountry(
|
||||
$this->get('represented_country'),
|
||||
$locales
|
||||
);
|
||||
$this->traits = new \GeoIp2\Record\Traits($this->get('traits'));
|
||||
|
||||
$this->locales = $locales;
|
||||
}
|
||||
}
|
31
lib/maxmind/GeoIp2/Model/Domain.php
Normal file
31
lib/maxmind/GeoIp2/Model/Domain.php
Normal file
@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace GeoIp2\Model;
|
||||
|
||||
/**
|
||||
* This class provides the GeoIP2 Domain model.
|
||||
*
|
||||
* @property-read string|null $domain The second level domain associated with the
|
||||
* IP address. This will be something like "example.com" or
|
||||
* "example.co.uk", not "foo.example.com".
|
||||
*
|
||||
* @property-read string $ipAddress The IP address that the data in the model is
|
||||
* for.
|
||||
*
|
||||
*/
|
||||
class Domain extends AbstractModel
|
||||
{
|
||||
protected $domain;
|
||||
protected $ipAddress;
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
public function __construct($raw)
|
||||
{
|
||||
parent::__construct($raw);
|
||||
|
||||
$this->domain = $this->get('domain');
|
||||
$this->ipAddress = $this->get('ip_address');
|
||||
}
|
||||
}
|
56
lib/maxmind/GeoIp2/Model/Enterprise.php
Normal file
56
lib/maxmind/GeoIp2/Model/Enterprise.php
Normal file
@ -0,0 +1,56 @@
|
||||
<?php
|
||||
|
||||
namespace GeoIp2\Model;
|
||||
|
||||
/**
|
||||
* Model class for the data returned by GeoIP2 Enterprise database lookups.
|
||||
*
|
||||
* The only difference between the City and Enterprise model classes is which
|
||||
* fields in each record may be populated. See
|
||||
* http://dev.maxmind.com/geoip/geoip2/web-services more details.
|
||||
*
|
||||
* @property-read \GeoIp2\Record\City $city City data for the requested IP
|
||||
* address.
|
||||
*
|
||||
* @property-read \GeoIp2\Record\Continent $continent Continent data for the
|
||||
* requested IP address.
|
||||
*
|
||||
* @property-read \GeoIp2\Record\Country $country Country data for the requested
|
||||
* IP address. This object represents the country where MaxMind believes the
|
||||
* end user is located.
|
||||
*
|
||||
* @property-read \GeoIp2\Record\Location $location Location data for the
|
||||
* requested IP address.
|
||||
*
|
||||
* @property-read \GeoIp2\Record\MaxMind $maxmind Data related to your MaxMind
|
||||
* account.
|
||||
*
|
||||
* @property-read \GeoIp2\Record\Country $registeredCountry Registered country
|
||||
* data for the requested IP address. This record represents the country
|
||||
* where the ISP has registered a given IP block and may differ from the
|
||||
* user's country.
|
||||
*
|
||||
* @property-read \GeoIp2\Record\RepresentedCountry $representedCountry
|
||||
* Represented country data for the requested IP address. The represented
|
||||
* country is used for things like military bases. It is only present when
|
||||
* the represented country differs from the country.
|
||||
*
|
||||
* @property-read array $subdivisions An array of {@link \GeoIp2\Record\Subdivision}
|
||||
* objects representing the country subdivisions for the requested IP
|
||||
* address. The number and type of subdivisions varies by country, but a
|
||||
* subdivision is typically a state, province, county, etc. Subdivisions
|
||||
* are ordered from most general (largest) to most specific (smallest).
|
||||
* If the response did not contain any subdivisions, this method returns
|
||||
* an empty array.
|
||||
*
|
||||
* @property-read \GeoIp2\Record\Subdivision $mostSpecificSubdivision An object
|
||||
* representing the most specific subdivision returned. If the response
|
||||
* did not contain any subdivisions, this method returns an empty
|
||||
* {@link \GeoIp2\Record\Subdivision} object.
|
||||
*
|
||||
* @property-read \GeoIp2\Record\Traits $traits Data for the traits of the
|
||||
* requested IP address.
|
||||
*/
|
||||
class Enterprise extends City
|
||||
{
|
||||
}
|
56
lib/maxmind/GeoIp2/Model/Insights.php
Normal file
56
lib/maxmind/GeoIp2/Model/Insights.php
Normal file
@ -0,0 +1,56 @@
|
||||
<?php
|
||||
|
||||
namespace GeoIp2\Model;
|
||||
|
||||
/**
|
||||
* Model class for the data returned by GeoIP2 Precision: Insights web service.
|
||||
*
|
||||
* The only difference between the City and Insights model classes is which
|
||||
* fields in each record may be populated. See
|
||||
* http://dev.maxmind.com/geoip/geoip2/web-services more details.
|
||||
*
|
||||
* @property-read \GeoIp2\Record\City $city City data for the requested IP
|
||||
* address.
|
||||
*
|
||||
* @property-read \GeoIp2\Record\Continent $continent Continent data for the
|
||||
* requested IP address.
|
||||
*
|
||||
* @property-read \GeoIp2\Record\Country $country Country data for the requested
|
||||
* IP address. This object represents the country where MaxMind believes the
|
||||
* end user is located.
|
||||
*
|
||||
* @property-read \GeoIp2\Record\Location $location Location data for the
|
||||
* requested IP address.
|
||||
*
|
||||
* @property-read \GeoIp2\Record\MaxMind $maxmind Data related to your MaxMind
|
||||
* account.
|
||||
*
|
||||
* @property-read \GeoIp2\Record\Country $registeredCountry Registered country
|
||||
* data for the requested IP address. This record represents the country
|
||||
* where the ISP has registered a given IP block and may differ from the
|
||||
* user's country.
|
||||
*
|
||||
* @property-read \GeoIp2\Record\RepresentedCountry $representedCountry
|
||||
* Represented country data for the requested IP address. The represented
|
||||
* country is used for things like military bases. It is only present when
|
||||
* the represented country differs from the country.
|
||||
*
|
||||
* @property-read array $subdivisions An array of {@link \GeoIp2\Record\Subdivision}
|
||||
* objects representing the country subdivisions for the requested IP
|
||||
* address. The number and type of subdivisions varies by country, but a
|
||||
* subdivision is typically a state, province, county, etc. Subdivisions
|
||||
* are ordered from most general (largest) to most specific (smallest).
|
||||
* If the response did not contain any subdivisions, this method returns
|
||||
* an empty array.
|
||||
*
|
||||
* @property-read \GeoIp2\Record\Subdivision $mostSpecificSubdivision An object
|
||||
* representing the most specific subdivision returned. If the response
|
||||
* did not contain any subdivisions, this method returns an empty
|
||||
* {@link \GeoIp2\Record\Subdivision} object.
|
||||
*
|
||||
* @property-read \GeoIp2\Record\Traits $traits Data for the traits of the
|
||||
* requested IP address.
|
||||
*/
|
||||
class Insights extends City
|
||||
{
|
||||
}
|
47
lib/maxmind/GeoIp2/Model/Isp.php
Normal file
47
lib/maxmind/GeoIp2/Model/Isp.php
Normal file
@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
namespace GeoIp2\Model;
|
||||
|
||||
/**
|
||||
* This class provides the GeoIP2 Connection-Type model.
|
||||
*
|
||||
* @property-read integer|null $autonomousSystemNumber The autonomous system number
|
||||
* associated with the IP address.
|
||||
*
|
||||
* @property-read string|null $autonomousSystemOrganization The organization
|
||||
* associated with the registered autonomous system number for the IP
|
||||
* address.
|
||||
*
|
||||
* @property-read string|null $isp The name of the ISP associated with the IP
|
||||
* address.
|
||||
*
|
||||
* @property-read string|null $organization The name of the organization associated
|
||||
* with the IP address.
|
||||
*
|
||||
* @property-read string $ipAddress The IP address that the data in the model is
|
||||
* for.
|
||||
*
|
||||
*/
|
||||
class Isp extends AbstractModel
|
||||
{
|
||||
protected $autonomousSystemNumber;
|
||||
protected $autonomousSystemOrganization;
|
||||
protected $isp;
|
||||
protected $organization;
|
||||
protected $ipAddress;
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
public function __construct($raw)
|
||||
{
|
||||
parent::__construct($raw);
|
||||
$this->autonomousSystemNumber = $this->get('autonomous_system_number');
|
||||
$this->autonomousSystemOrganization =
|
||||
$this->get('autonomous_system_organization');
|
||||
$this->isp = $this->get('isp');
|
||||
$this->organization = $this->get('organization');
|
||||
|
||||
$this->ipAddress = $this->get('ip_address');
|
||||
}
|
||||
}
|
20
lib/maxmind/GeoIp2/ProviderInterface.php
Normal file
20
lib/maxmind/GeoIp2/ProviderInterface.php
Normal file
@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
namespace GeoIp2;
|
||||
|
||||
interface ProviderInterface
|
||||
{
|
||||
/**
|
||||
* @param ipAddress
|
||||
* IPv4 or IPv6 address to lookup.
|
||||
* @return \GeoIp2\Model\Country A Country model for the requested IP address.
|
||||
*/
|
||||
public function country($ipAddress);
|
||||
|
||||
/**
|
||||
* @param ipAddress
|
||||
* IPv4 or IPv6 address to lookup.
|
||||
* @return \GeoIp2\Model\City A City model for the requested IP address.
|
||||
*/
|
||||
public function city($ipAddress);
|
||||
}
|
38
lib/maxmind/GeoIp2/Record/AbstractPlaceRecord.php
Normal file
38
lib/maxmind/GeoIp2/Record/AbstractPlaceRecord.php
Normal file
@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
namespace GeoIp2\Record;
|
||||
|
||||
abstract class AbstractPlaceRecord extends AbstractRecord
|
||||
{
|
||||
private $locales;
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
public function __construct($record, $locales = array('en'))
|
||||
{
|
||||
$this->locales = $locales;
|
||||
parent::__construct($record);
|
||||
}
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
public function __get($attr)
|
||||
{
|
||||
if ($attr == 'name') {
|
||||
return $this->name();
|
||||
} else {
|
||||
return parent::__get($attr);
|
||||
}
|
||||
}
|
||||
|
||||
private function name()
|
||||
{
|
||||
foreach ($this->locales as $locale) {
|
||||
if (isset($this->names[$locale])) {
|
||||
return $this->names[$locale];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
60
lib/maxmind/GeoIp2/Record/AbstractRecord.php
Normal file
60
lib/maxmind/GeoIp2/Record/AbstractRecord.php
Normal file
@ -0,0 +1,60 @@
|
||||
<?php
|
||||
|
||||
namespace GeoIp2\Record;
|
||||
|
||||
use GeoIp2\Compat\JsonSerializable;
|
||||
|
||||
abstract class AbstractRecord implements JsonSerializable
|
||||
{
|
||||
private $record;
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
public function __construct($record)
|
||||
{
|
||||
$this->record = isset($record) ? $record : array();
|
||||
}
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
public function __get($attr)
|
||||
{
|
||||
// XXX - kind of ugly but greatly reduces boilerplate code
|
||||
$key = $this->attributeToKey($attr);
|
||||
|
||||
if ($this->__isset($attr)) {
|
||||
return $this->record[$key];
|
||||
} elseif ($this->validAttribute($attr)) {
|
||||
if (preg_match('/^is_/', $key)) {
|
||||
return false;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
throw new \RuntimeException("Unknown attribute: $attr");
|
||||
}
|
||||
}
|
||||
|
||||
public function __isset($attr)
|
||||
{
|
||||
return $this->validAttribute($attr) &&
|
||||
isset($this->record[$this->attributeToKey($attr)]);
|
||||
}
|
||||
|
||||
private function attributeToKey($attr)
|
||||
{
|
||||
return strtolower(preg_replace('/([A-Z])/', '_\1', $attr));
|
||||
}
|
||||
|
||||
private function validAttribute($attr)
|
||||
{
|
||||
return in_array($attr, $this->validAttributes);
|
||||
}
|
||||
|
||||
public function jsonSerialize()
|
||||
{
|
||||
return $this->record;
|
||||
}
|
||||
}
|
32
lib/maxmind/GeoIp2/Record/City.php
Normal file
32
lib/maxmind/GeoIp2/Record/City.php
Normal file
@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
namespace GeoIp2\Record;
|
||||
|
||||
/**
|
||||
* City-level data associated with an IP address.
|
||||
*
|
||||
* This record is returned by all location services and databases besides
|
||||
* Country.
|
||||
*
|
||||
* @property-read int|null $confidence A value from 0-100 indicating MaxMind's
|
||||
* confidence that the city is correct. This attribute is only available
|
||||
* from the Insights service and the GeoIP2 Enterprise database.
|
||||
*
|
||||
* @property-read int|null $geonameId The GeoName ID for the city. This attribute
|
||||
* is returned by all location services and databases.
|
||||
*
|
||||
* @property-read string|null $name The name of the city based on the locales list
|
||||
* passed to the constructor. This attribute is returned by all location
|
||||
* services and databases.
|
||||
*
|
||||
* @property-read array|null $names A array map where the keys are locale codes
|
||||
* and the values are names. This attribute is returned by all location
|
||||
* services and databases.
|
||||
*/
|
||||
class City extends AbstractPlaceRecord
|
||||
{
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
protected $validAttributes = array('confidence', 'geonameId', 'names');
|
||||
}
|
35
lib/maxmind/GeoIp2/Record/Continent.php
Normal file
35
lib/maxmind/GeoIp2/Record/Continent.php
Normal file
@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
namespace GeoIp2\Record;
|
||||
|
||||
/**
|
||||
* Contains data for the continent record associated with an IP address
|
||||
*
|
||||
* This record is returned by all location services and databases.
|
||||
*
|
||||
* @property-read string|null $code A two character continent code like "NA" (North
|
||||
* America) or "OC" (Oceania). This attribute is returned by all location
|
||||
* services and databases.
|
||||
*
|
||||
* @property-read int|null $geonameId The GeoName ID for the continent. This
|
||||
* attribute is returned by all location services and databases.
|
||||
*
|
||||
* @property-read string|null $name Returns the name of the continent based on the
|
||||
* locales list passed to the constructor. This attribute is returned by all location
|
||||
* services and databases.
|
||||
*
|
||||
* @property-read array|null $names An array map where the keys are locale codes
|
||||
* and the values are names. This attribute is returned by all location
|
||||
* services and databases.
|
||||
*/
|
||||
class Continent extends AbstractPlaceRecord
|
||||
{
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
protected $validAttributes = array(
|
||||
'code',
|
||||
'geonameId',
|
||||
'names'
|
||||
);
|
||||
}
|
41
lib/maxmind/GeoIp2/Record/Country.php
Normal file
41
lib/maxmind/GeoIp2/Record/Country.php
Normal file
@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
namespace GeoIp2\Record;
|
||||
|
||||
/**
|
||||
* Contains data for the country record associated with an IP address
|
||||
*
|
||||
* This record is returned by all location services and databases.
|
||||
*
|
||||
* @property-read int|null $confidence A value from 0-100 indicating MaxMind's
|
||||
* confidence that the country is correct. This attribute is only available
|
||||
* from the Insights service and the GeoIP2 Enterprise database.
|
||||
*
|
||||
* @property-read int|null $geonameId The GeoName ID for the country. This
|
||||
* attribute is returned by location services and databases.
|
||||
*
|
||||
* @property-read string|null $isoCode The {@link
|
||||
* http://en.wikipedia.org/wiki/ISO_3166-1 two-character ISO 3166-1 alpha
|
||||
* code} for the country. This attribute is returned by all location services
|
||||
* and databases.
|
||||
*
|
||||
* @property-read string|null $name The name of the country based on the locales
|
||||
* list passed to the constructor. This attribute is returned by all location
|
||||
* services and databases.
|
||||
*
|
||||
* @property-read array|null $names An array map where the keys are locale codes
|
||||
* and the values are names. This attribute is returned by all location
|
||||
* services and databases.
|
||||
*/
|
||||
class Country extends AbstractPlaceRecord
|
||||
{
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
protected $validAttributes = array(
|
||||
'confidence',
|
||||
'geonameId',
|
||||
'isoCode',
|
||||
'names'
|
||||
);
|
||||
}
|
59
lib/maxmind/GeoIp2/Record/Location.php
Normal file
59
lib/maxmind/GeoIp2/Record/Location.php
Normal file
@ -0,0 +1,59 @@
|
||||
<?php
|
||||
|
||||
namespace GeoIp2\Record;
|
||||
|
||||
/**
|
||||
* Contains data for the location record associated with an IP address
|
||||
*
|
||||
* This record is returned by all location services and databases besides
|
||||
* Country.
|
||||
*
|
||||
* @property-read int|null $averageIncome The average income in US dollars
|
||||
* associated with the requested IP address. This attribute is only available
|
||||
* from the Insights service.
|
||||
*
|
||||
* @property-read int|null $accuracyRadius The approximate accuracy radius in
|
||||
* kilometers around the latitude and longitude for the IP address. This is
|
||||
* the radius where we have a 67% confidence that the device using the IP
|
||||
* address resides within the circle centered at the latitude and longitude
|
||||
* with the provided radius.
|
||||
*
|
||||
* @property-read float|null $latitude The approximate latitude of the location
|
||||
* associated with the IP address. This value is not precise and should not be
|
||||
* used to identify a particular address or household.
|
||||
*
|
||||
* @property-read float|null $longitude The approximate longitude of the location
|
||||
* associated with the IP address. This value is not precise and should not be
|
||||
* used to identify a particular address or household.
|
||||
*
|
||||
* @property-read int|null $populationDensity The estimated population per square
|
||||
* kilometer associated with the IP address. This attribute is only available
|
||||
* from the Insights service.
|
||||
*
|
||||
* @property-read int|null $metroCode The metro code of the location if the location
|
||||
* is in the US. MaxMind returns the same metro codes as the
|
||||
* {@link
|
||||
* https://developers.google.com/adwords/api/docs/appendix/cities-DMAregions
|
||||
* Google AdWords API}.
|
||||
*
|
||||
* @property-read string|null $timeZone The time zone associated with location, as
|
||||
* specified by the {@link http://www.iana.org/time-zones IANA Time Zone
|
||||
* Database}, e.g., "America/New_York".
|
||||
*/
|
||||
class Location extends AbstractRecord
|
||||
{
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
protected $validAttributes = array(
|
||||
'averageIncome',
|
||||
'accuracyRadius',
|
||||
'latitude',
|
||||
'longitude',
|
||||
'metroCode',
|
||||
'populationDensity',
|
||||
'postalCode',
|
||||
'postalConfidence',
|
||||
'timeZone'
|
||||
);
|
||||
}
|
19
lib/maxmind/GeoIp2/Record/MaxMind.php
Normal file
19
lib/maxmind/GeoIp2/Record/MaxMind.php
Normal file
@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace GeoIp2\Record;
|
||||
|
||||
/**
|
||||
* Contains data about your account.
|
||||
*
|
||||
* This record is returned by all location services and databases.
|
||||
*
|
||||
* @property-read int|null $queriesRemaining The number of remaining queries you
|
||||
* have for the service you are calling.
|
||||
*/
|
||||
class MaxMind extends AbstractRecord
|
||||
{
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
protected $validAttributes = array('queriesRemaining');
|
||||
}
|
27
lib/maxmind/GeoIp2/Record/Postal.php
Normal file
27
lib/maxmind/GeoIp2/Record/Postal.php
Normal file
@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
namespace GeoIp2\Record;
|
||||
|
||||
/**
|
||||
* Contains data for the postal record associated with an IP address
|
||||
*
|
||||
* This record is returned by all location databases and services besides
|
||||
* Country.
|
||||
*
|
||||
* @property-read string|null $code The postal code of the location. Postal codes
|
||||
* are not available for all countries. In some countries, this will only
|
||||
* contain part of the postal code. This attribute is returned by all location
|
||||
* databases and services besides Country.
|
||||
*
|
||||
* @property-read int|null $confidence A value from 0-100 indicating MaxMind's
|
||||
* confidence that the postal code is correct. This attribute is only
|
||||
* available from the Insights service and the GeoIP2 Enterprise
|
||||
* database.
|
||||
*/
|
||||
class Postal extends AbstractRecord
|
||||
{
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
protected $validAttributes = array('code', 'confidence');
|
||||
}
|
40
lib/maxmind/GeoIp2/Record/RepresentedCountry.php
Normal file
40
lib/maxmind/GeoIp2/Record/RepresentedCountry.php
Normal file
@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
namespace GeoIp2\Record;
|
||||
|
||||
/**
|
||||
* Contains data for the represented country associated with an IP address
|
||||
*
|
||||
* This class contains the country-level data associated with an IP address
|
||||
* for the IP's represented country. The represented country is the country
|
||||
* represented by something like a military base.
|
||||
*
|
||||
* @property-read int|null $confidence A value from 0-100 indicating MaxMind's
|
||||
* confidence that the country is correct. This attribute is only available
|
||||
* from the Insights service and the GeoIP2 Enterprise database.
|
||||
*
|
||||
* @property-read int|null $geonameId The GeoName ID for the country.
|
||||
*
|
||||
* @property-read string|null $isoCode The {@link http://en.wikipedia.org/wiki/ISO_3166-1
|
||||
* two-character ISO 3166-1 alpha code} for the country.
|
||||
*
|
||||
* @property-read string|null $name The name of the country based on the locales list
|
||||
* passed to the constructor.
|
||||
*
|
||||
* @property-read array|null $names An array map where the keys are locale codes and
|
||||
* the values are names.
|
||||
*
|
||||
* @property-read string|null $type A string indicating the type of entity that is
|
||||
* representing the country. Currently we only return <code>military</code>
|
||||
* but this could expand to include other types in the future.
|
||||
*/
|
||||
class RepresentedCountry extends Country
|
||||
{
|
||||
protected $validAttributes = array(
|
||||
'confidence',
|
||||
'geonameId',
|
||||
'isoCode',
|
||||
'names',
|
||||
'type'
|
||||
);
|
||||
}
|
45
lib/maxmind/GeoIp2/Record/Subdivision.php
Normal file
45
lib/maxmind/GeoIp2/Record/Subdivision.php
Normal file
@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
namespace GeoIp2\Record;
|
||||
|
||||
/**
|
||||
*
|
||||
* Contains data for the subdivisions associated with an IP address
|
||||
*
|
||||
* This record is returned by all location databases and services besides
|
||||
* Country.
|
||||
*
|
||||
* @property-read int|null $confidence This is a value from 0-100 indicating
|
||||
* MaxMind's confidence that the subdivision is correct. This attribute is
|
||||
* only available from the Insights service and the GeoIP2 Enterprise
|
||||
* database.
|
||||
*
|
||||
* @property-read int|null $geonameId This is a GeoName ID for the subdivision.
|
||||
* This attribute is returned by all location databases and services besides
|
||||
* Country.
|
||||
*
|
||||
* @property-read string|null $isoCode This is a string up to three characters long
|
||||
* contain the subdivision portion of the {@link
|
||||
* http://en.wikipedia.org/wiki/ISO_3166-2 ISO 3166-2 code}. This attribute
|
||||
* is returned by all location databases and services except Country.
|
||||
*
|
||||
* @property-read string|null $name The name of the subdivision based on the
|
||||
* locales list passed to the constructor. This attribute is returned by all
|
||||
* location databases and services besides Country.
|
||||
*
|
||||
* @property-read array|null $names An array map where the keys are locale codes
|
||||
* and the values are names. This attribute is returned by all location
|
||||
* databases and services besides Country.
|
||||
*/
|
||||
class Subdivision extends AbstractPlaceRecord
|
||||
{
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
protected $validAttributes = array(
|
||||
'confidence',
|
||||
'geonameId',
|
||||
'isoCode',
|
||||
'names'
|
||||
);
|
||||
}
|
107
lib/maxmind/GeoIp2/Record/Traits.php
Normal file
107
lib/maxmind/GeoIp2/Record/Traits.php
Normal file
@ -0,0 +1,107 @@
|
||||
<?php
|
||||
|
||||
namespace GeoIp2\Record;
|
||||
|
||||
/**
|
||||
*
|
||||
* Contains data for the traits record associated with an IP address
|
||||
*
|
||||
* This record is returned by all location services and databases.
|
||||
*
|
||||
* @property-read int|null $autonomousSystemNumber The {@link
|
||||
* http://en.wikipedia.org/wiki/Autonomous_system_(Internet) autonomous
|
||||
* system number} associated with the IP address. This attribute is only
|
||||
* available from the City and Insights web service and the GeoIP2
|
||||
* Enterprise database.
|
||||
*
|
||||
* @property-read string|null $autonomousSystemOrganization The organization
|
||||
* associated with the registered {@link
|
||||
* http://en.wikipedia.org/wiki/Autonomous_system_(Internet) autonomous
|
||||
* system number} for the IP address. This attribute is only available from
|
||||
* the City and Insights web service and the GeoIP2 Enterprise
|
||||
* database.
|
||||
*
|
||||
* @property-read string|null $connectionType The connection type may take the
|
||||
* following values: "Dialup", "Cable/DSL", "Corporate", "Cellular".
|
||||
* Additional values may be added in the future. This attribute is only
|
||||
* available in the GeoIP2 Enterprise database.
|
||||
*
|
||||
* @property-read string|null $domain The second level domain associated with the
|
||||
* IP address. This will be something like "example.com" or "example.co.uk",
|
||||
* not "foo.example.com". This attribute is only available from the
|
||||
* City and Insights web service and the GeoIP2 Enterprise
|
||||
* database.
|
||||
*
|
||||
* @property-read string $ipAddress The IP address that the data in the model
|
||||
* is for. If you performed a "me" lookup against the web service, this
|
||||
* will be the externally routable IP address for the system the code is
|
||||
* running on. If the system is behind a NAT, this may differ from the IP
|
||||
* address locally assigned to it. This attribute is returned by all end
|
||||
* points.
|
||||
*
|
||||
* @property-read boolean $isAnonymousProxy *Deprecated.* Please see our {@link
|
||||
* https://www.maxmind.com/en/geoip2-anonymous-ip-database GeoIP2
|
||||
* Anonymous IP database} to determine whether the IP address is used by an
|
||||
* anonymizing service.
|
||||
*
|
||||
* @property-read boolean $isLegitimateProxy This attribute is true if MaxMind
|
||||
* believes this IP address to be a legitimate proxy, such as an internal
|
||||
* VPN used by a corporation. This attribute is only available in the GeoIP2
|
||||
* Enterprise database.
|
||||
*
|
||||
* @property-read boolean $isSatelliteProvider *Deprecated.* Due to the
|
||||
* increased coverage by mobile carriers, very few satellite providers now
|
||||
* serve multiple countries. As a result, the output does not provide
|
||||
* sufficiently relevant data for us to maintain it.
|
||||
*
|
||||
* @property-read string|null $isp The name of the ISP associated with the IP
|
||||
* address. This attribute is only available from the City and Insights web
|
||||
* services and the GeoIP2 Enterprise database.
|
||||
*
|
||||
* @property-read string|null $organization The name of the organization associated
|
||||
* with the IP address. This attribute is only available from the City and
|
||||
* Insights web services and the GeoIP2 Enterprise database.
|
||||
*
|
||||
* @property-read string|null $userType <p>The user type associated with the IP
|
||||
* address. This can be one of the following values:</p>
|
||||
* <ul>
|
||||
* <li>business
|
||||
* <li>cafe
|
||||
* <li>cellular
|
||||
* <li>college
|
||||
* <li>content_delivery_network
|
||||
* <li>dialup
|
||||
* <li>government
|
||||
* <li>hosting
|
||||
* <li>library
|
||||
* <li>military
|
||||
* <li>residential
|
||||
* <li>router
|
||||
* <li>school
|
||||
* <li>search_engine_spider
|
||||
* <li>traveler
|
||||
* </ul>
|
||||
* <p>
|
||||
* This attribute is only available from the Insights web service and the
|
||||
* GeoIP2 Enterprise database.
|
||||
* </p>
|
||||
*/
|
||||
class Traits extends AbstractRecord
|
||||
{
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
protected $validAttributes = array(
|
||||
'autonomousSystemNumber',
|
||||
'autonomousSystemOrganization',
|
||||
'connectionType',
|
||||
'domain',
|
||||
'isAnonymousProxy',
|
||||
'isLegitimateProxy',
|
||||
'isSatelliteProvider',
|
||||
'isp',
|
||||
'ipAddress',
|
||||
'organization',
|
||||
'userType'
|
||||
);
|
||||
}
|
242
lib/maxmind/GeoIp2/WebService/Client.php
Normal file
242
lib/maxmind/GeoIp2/WebService/Client.php
Normal file
@ -0,0 +1,242 @@
|
||||
<?php
|
||||
|
||||
namespace GeoIp2\WebService;
|
||||
|
||||
use GeoIp2\Exception\AddressNotFoundException;
|
||||
use GeoIp2\Exception\AuthenticationException;
|
||||
use GeoIp2\Exception\GeoIp2Exception;
|
||||
use GeoIp2\Exception\HttpException;
|
||||
use GeoIp2\Exception\InvalidRequestException;
|
||||
use GeoIp2\Exception\OutOfQueriesException;
|
||||
use GeoIp2\ProviderInterface;
|
||||
use MaxMind\Exception\InvalidInputException;
|
||||
use MaxMind\WebService\Client as WsClient;
|
||||
|
||||
/**
|
||||
* This class provides a client API for all the GeoIP2 Precision web services.
|
||||
* The services are Country, City, and Insights. Each service returns a
|
||||
* different set of data about an IP address, with Country returning the
|
||||
* least data and Insights the most.
|
||||
*
|
||||
* Each web service is represented by a different model class, and these model
|
||||
* classes in turn contain multiple record classes. The record classes have
|
||||
* attributes which contain data about the IP address.
|
||||
*
|
||||
* If the web service does not return a particular piece of data for an IP
|
||||
* address, the associated attribute is not populated.
|
||||
*
|
||||
* The web service may not return any information for an entire record, in
|
||||
* which case all of the attributes for that record class will be empty.
|
||||
*
|
||||
* ## Usage ##
|
||||
*
|
||||
* The basic API for this class is the same for all of the web service end
|
||||
* points. First you create a web service object with your MaxMind `$userId`
|
||||
* and `$licenseKey`, then you call the method corresponding to a specific end
|
||||
* point, passing it the IP address you want to look up.
|
||||
*
|
||||
* If the request succeeds, the method call will return a model class for
|
||||
* the service you called. This model in turn contains multiple record
|
||||
* classes, each of which represents part of the data returned by the web
|
||||
* service.
|
||||
*
|
||||
* If the request fails, the client class throws an exception.
|
||||
*/
|
||||
class Client implements ProviderInterface
|
||||
{
|
||||
private $locales;
|
||||
private $client;
|
||||
private static $basePath = '/geoip/v2.1';
|
||||
|
||||
const VERSION = 'v2.4.2';
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param int $userId Your MaxMind user ID
|
||||
* @param string $licenseKey Your MaxMind license key
|
||||
* @param array $locales List of locale codes to use in name property
|
||||
* from most preferred to least preferred.
|
||||
* @param array $options Array of options. Valid options include:
|
||||
* * `host` - The host to use when querying the web service.
|
||||
* * `timeout` - Timeout in seconds.
|
||||
* * `connectTimeout` - Initial connection timeout in seconds.
|
||||
* * `proxy` - The HTTP proxy to use. May include a schema, port,
|
||||
* username, and password, e.g.,
|
||||
* `http://username:password@127.0.0.1:10`.
|
||||
*/
|
||||
public function __construct(
|
||||
$userId,
|
||||
$licenseKey,
|
||||
$locales = array('en'),
|
||||
$options = array()
|
||||
) {
|
||||
$this->locales = $locales;
|
||||
|
||||
// This is for backwards compatibility. Do not remove except for a
|
||||
// major version bump.
|
||||
if (is_string($options)) {
|
||||
$options = array( 'host' => $options );
|
||||
}
|
||||
|
||||
if (!isset($options['host'])) {
|
||||
$options['host'] = 'geoip.maxmind.com';
|
||||
}
|
||||
|
||||
$options['userAgent'] = $this->userAgent();
|
||||
|
||||
$this->client = new WsClient($userId, $licenseKey, $options);
|
||||
}
|
||||
|
||||
private function userAgent()
|
||||
{
|
||||
return 'GeoIP2-API/' . Client::VERSION;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method calls the GeoIP2 Precision: City service.
|
||||
*
|
||||
* @param string $ipAddress IPv4 or IPv6 address as a string. If no
|
||||
* address is provided, the address that the web service is called
|
||||
* from will be used.
|
||||
*
|
||||
* @return \GeoIp2\Model\City
|
||||
*
|
||||
* @throws \GeoIp2\Exception\AddressNotFoundException if the address you
|
||||
* provided is not in our database (e.g., a private address).
|
||||
* @throws \GeoIp2\Exception\AuthenticationException if there is a problem
|
||||
* with the user ID or license key that you provided.
|
||||
* @throws \GeoIp2\Exception\OutOfQueriesException if your account is out
|
||||
* of queries.
|
||||
* @throws \GeoIp2\Exception\InvalidRequestException} if your request was
|
||||
* received by the web service but is invalid for some other reason.
|
||||
* This may indicate an issue with this API. Please report the error to
|
||||
* MaxMind.
|
||||
* @throws \GeoIp2\Exception\HttpException if an unexpected HTTP error
|
||||
* code or message was returned. This could indicate a problem with the
|
||||
* connection between your server and the web service or that the web
|
||||
* service returned an invalid document or 500 error code.
|
||||
* @throws \GeoIp2\Exception\GeoIp2Exception This serves as the parent
|
||||
* class to the above exceptions. It will be thrown directly if a 200
|
||||
* status code is returned but the body is invalid.
|
||||
*/
|
||||
public function city($ipAddress = 'me')
|
||||
{
|
||||
return $this->responseFor('city', 'City', $ipAddress);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method calls the GeoIP2 Precision: Country service.
|
||||
*
|
||||
* @param string $ipAddress IPv4 or IPv6 address as a string. If no
|
||||
* address is provided, the address that the web service is called
|
||||
* from will be used.
|
||||
*
|
||||
* @return \GeoIp2\Model\Country
|
||||
*
|
||||
* @throws \GeoIp2\Exception\AddressNotFoundException if the address you
|
||||
* provided is not in our database (e.g., a private address).
|
||||
* @throws \GeoIp2\Exception\AuthenticationException if there is a problem
|
||||
* with the user ID or license key that you provided.
|
||||
* @throws \GeoIp2\Exception\OutOfQueriesException if your account is out
|
||||
* of queries.
|
||||
* @throws \GeoIp2\Exception\InvalidRequestException} if your request was
|
||||
* received by the web service but is invalid for some other reason.
|
||||
* This may indicate an issue with this API. Please report the error to
|
||||
* MaxMind.
|
||||
* @throws \GeoIp2\Exception\HttpException if an unexpected HTTP error
|
||||
* code or message was returned. This could indicate a problem with the
|
||||
* connection between your server and the web service or that the web
|
||||
* service returned an invalid document or 500 error code.
|
||||
* @throws \GeoIp2\Exception\GeoIp2Exception This serves as the parent
|
||||
* class to the above exceptions. It will be thrown directly if a 200
|
||||
* status code is returned but the body is invalid.
|
||||
*/
|
||||
public function country($ipAddress = 'me')
|
||||
{
|
||||
return $this->responseFor('country', 'Country', $ipAddress);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method calls the GeoIP2 Precision: Insights service.
|
||||
*
|
||||
* @param string $ipAddress IPv4 or IPv6 address as a string. If no
|
||||
* address is provided, the address that the web service is called
|
||||
* from will be used.
|
||||
*
|
||||
* @return \GeoIp2\Model\Insights
|
||||
*
|
||||
* @throws \GeoIp2\Exception\AddressNotFoundException if the address you
|
||||
* provided is not in our database (e.g., a private address).
|
||||
* @throws \GeoIp2\Exception\AuthenticationException if there is a problem
|
||||
* with the user ID or license key that you provided.
|
||||
* @throws \GeoIp2\Exception\OutOfQueriesException if your account is out
|
||||
* of queries.
|
||||
* @throws \GeoIp2\Exception\InvalidRequestException} if your request was
|
||||
* received by the web service but is invalid for some other reason.
|
||||
* This may indicate an issue with this API. Please report the error to
|
||||
* MaxMind.
|
||||
* @throws \GeoIp2\Exception\HttpException if an unexpected HTTP error
|
||||
* code or message was returned. This could indicate a problem with the
|
||||
* connection between your server and the web service or that the web
|
||||
* service returned an invalid document or 500 error code.
|
||||
* @throws \GeoIp2\Exception\GeoIp2Exception This serves as the parent
|
||||
* class to the above exceptions. It will be thrown directly if a 200
|
||||
* status code is returned but the body is invalid.
|
||||
*/
|
||||
public function insights($ipAddress = 'me')
|
||||
{
|
||||
return $this->responseFor('insights', 'Insights', $ipAddress);
|
||||
}
|
||||
|
||||
private function responseFor($endpoint, $class, $ipAddress)
|
||||
{
|
||||
$path = implode('/', array(self::$basePath, $endpoint, $ipAddress));
|
||||
|
||||
try {
|
||||
$body = $this->client->get('GeoIP2 ' . $class, $path);
|
||||
} catch (\MaxMind\Exception\IpAddressNotFoundException $ex) {
|
||||
throw new AddressNotFoundException(
|
||||
$ex->getMessage(),
|
||||
$ex->getStatusCode(),
|
||||
$ex
|
||||
);
|
||||
} catch (\MaxMind\Exception\AuthenticationException $ex) {
|
||||
throw new AuthenticationException(
|
||||
$ex->getMessage(),
|
||||
$ex->getStatusCode(),
|
||||
$ex
|
||||
);
|
||||
} catch (\MaxMind\Exception\InsufficientFundsException $ex) {
|
||||
throw new OutOfQueriesException(
|
||||
$ex->getMessage(),
|
||||
$ex->getStatusCode(),
|
||||
$ex
|
||||
);
|
||||
} catch (\MaxMind\Exception\InvalidRequestException $ex) {
|
||||
throw new InvalidRequestException(
|
||||
$ex->getMessage(),
|
||||
$ex->getErrorCode(),
|
||||
$ex->getStatusCode(),
|
||||
$ex->getUri(),
|
||||
$ex
|
||||
);
|
||||
} catch (\MaxMind\Exception\HttpException $ex) {
|
||||
throw new HttpException(
|
||||
$ex->getMessage(),
|
||||
$ex->getStatusCode(),
|
||||
$ex->getUri(),
|
||||
$ex
|
||||
);
|
||||
} catch (\MaxMind\Exception\WebServiceException $ex) {
|
||||
throw new GeoIp2Exception(
|
||||
$ex->getMessage(),
|
||||
$ex->getCode(),
|
||||
$ex
|
||||
);
|
||||
}
|
||||
|
||||
$class = "GeoIp2\\Model\\" . $class;
|
||||
return new $class($body, $this->locales);
|
||||
}
|
||||
}
|
296
lib/maxmind/MaxMind/Db/Reader.php
Normal file
296
lib/maxmind/MaxMind/Db/Reader.php
Normal file
@ -0,0 +1,296 @@
|
||||
<?php
|
||||
|
||||
namespace MaxMind\Db;
|
||||
|
||||
use MaxMind\Db\Reader\Decoder;
|
||||
use MaxMind\Db\Reader\InvalidDatabaseException;
|
||||
use MaxMind\Db\Reader\Metadata;
|
||||
use MaxMind\Db\Reader\Util;
|
||||
|
||||
/**
|
||||
* Instances of this class provide a reader for the MaxMind DB format. IP
|
||||
* addresses can be looked up using the <code>get</code> method.
|
||||
*/
|
||||
class Reader
|
||||
{
|
||||
private static $DATA_SECTION_SEPARATOR_SIZE = 16;
|
||||
private static $METADATA_START_MARKER = "\xAB\xCD\xEFMaxMind.com";
|
||||
private static $METADATA_START_MARKER_LENGTH = 14;
|
||||
|
||||
private $decoder;
|
||||
private $fileHandle;
|
||||
private $fileSize;
|
||||
private $ipV4Start;
|
||||
private $metadata;
|
||||
|
||||
/**
|
||||
* Constructs a Reader for the MaxMind DB format. The file passed to it must
|
||||
* be a valid MaxMind DB file such as a GeoIp2 database file.
|
||||
*
|
||||
* @param string $database
|
||||
* the MaxMind DB file to use.
|
||||
* @throws \InvalidArgumentException for invalid database path or unknown arguments
|
||||
* @throws \MaxMind\Db\Reader\InvalidDatabaseException
|
||||
* if the database is invalid or there is an error reading
|
||||
* from it.
|
||||
*/
|
||||
public function __construct($database)
|
||||
{
|
||||
if (func_num_args() != 1) {
|
||||
throw new \InvalidArgumentException(
|
||||
'The constructor takes exactly one argument.'
|
||||
);
|
||||
}
|
||||
|
||||
if (!is_readable($database)) {
|
||||
throw new \InvalidArgumentException(
|
||||
"The file \"$database\" does not exist or is not readable."
|
||||
);
|
||||
}
|
||||
$this->fileHandle = @fopen($database, 'rb');
|
||||
if ($this->fileHandle === false) {
|
||||
throw new \InvalidArgumentException(
|
||||
"Error opening \"$database\"."
|
||||
);
|
||||
}
|
||||
$this->fileSize = @filesize($database);
|
||||
if ($this->fileSize === false) {
|
||||
throw new \UnexpectedValueException(
|
||||
"Error determining the size of \"$database\"."
|
||||
);
|
||||
}
|
||||
|
||||
$start = $this->findMetadataStart($database);
|
||||
$metadataDecoder = new Decoder($this->fileHandle, $start);
|
||||
list($metadataArray) = $metadataDecoder->decode($start);
|
||||
$this->metadata = new Metadata($metadataArray);
|
||||
$this->decoder = new Decoder(
|
||||
$this->fileHandle,
|
||||
$this->metadata->searchTreeSize + self::$DATA_SECTION_SEPARATOR_SIZE
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Looks up the <code>address</code> in the MaxMind DB.
|
||||
*
|
||||
* @param string $ipAddress
|
||||
* the IP address to look up.
|
||||
* @return array the record for the IP address.
|
||||
* @throws \BadMethodCallException if this method is called on a closed database.
|
||||
* @throws \InvalidArgumentException if something other than a single IP address is passed to the method.
|
||||
* @throws InvalidDatabaseException
|
||||
* if the database is invalid or there is an error reading
|
||||
* from it.
|
||||
*/
|
||||
public function get($ipAddress)
|
||||
{
|
||||
if (func_num_args() != 1) {
|
||||
throw new \InvalidArgumentException(
|
||||
'Method takes exactly one argument.'
|
||||
);
|
||||
}
|
||||
|
||||
if (!is_resource($this->fileHandle)) {
|
||||
throw new \BadMethodCallException(
|
||||
'Attempt to read from a closed MaxMind DB.'
|
||||
);
|
||||
}
|
||||
|
||||
if (!filter_var($ipAddress, FILTER_VALIDATE_IP)) {
|
||||
throw new \InvalidArgumentException(
|
||||
"The value \"$ipAddress\" is not a valid IP address."
|
||||
);
|
||||
}
|
||||
|
||||
if ($this->metadata->ipVersion == 4 && strrpos($ipAddress, ':')) {
|
||||
throw new \InvalidArgumentException(
|
||||
"Error looking up $ipAddress. You attempted to look up an"
|
||||
. " IPv6 address in an IPv4-only database."
|
||||
);
|
||||
}
|
||||
$pointer = $this->findAddressInTree($ipAddress);
|
||||
if ($pointer == 0) {
|
||||
return null;
|
||||
}
|
||||
return $this->resolveDataPointer($pointer);
|
||||
}
|
||||
|
||||
private function findAddressInTree($ipAddress)
|
||||
{
|
||||
// XXX - could simplify. Done as a byte array to ease porting
|
||||
$rawAddress = array_merge(unpack('C*', inet_pton($ipAddress)));
|
||||
|
||||
$bitCount = count($rawAddress) * 8;
|
||||
|
||||
// The first node of the tree is always node 0, at the beginning of the
|
||||
// value
|
||||
$node = $this->startNode($bitCount);
|
||||
|
||||
for ($i = 0; $i < $bitCount; $i++) {
|
||||
if ($node >= $this->metadata->nodeCount) {
|
||||
break;
|
||||
}
|
||||
$tempBit = 0xFF & $rawAddress[$i >> 3];
|
||||
$bit = 1 & ($tempBit >> 7 - ($i % 8));
|
||||
|
||||
$node = $this->readNode($node, $bit);
|
||||
}
|
||||
if ($node == $this->metadata->nodeCount) {
|
||||
// Record is empty
|
||||
return 0;
|
||||
} elseif ($node > $this->metadata->nodeCount) {
|
||||
// Record is a data pointer
|
||||
return $node;
|
||||
}
|
||||
throw new InvalidDatabaseException("Something bad happened");
|
||||
}
|
||||
|
||||
|
||||
private function startNode($length)
|
||||
{
|
||||
// Check if we are looking up an IPv4 address in an IPv6 tree. If this
|
||||
// is the case, we can skip over the first 96 nodes.
|
||||
if ($this->metadata->ipVersion == 6 && $length == 32) {
|
||||
return $this->ipV4StartNode();
|
||||
}
|
||||
// The first node of the tree is always node 0, at the beginning of the
|
||||
// value
|
||||
return 0;
|
||||
}
|
||||
|
||||
private function ipV4StartNode()
|
||||
{
|
||||
// This is a defensive check. There is no reason to call this when you
|
||||
// have an IPv4 tree.
|
||||
if ($this->metadata->ipVersion == 4) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ($this->ipV4Start != 0) {
|
||||
return $this->ipV4Start;
|
||||
}
|
||||
$node = 0;
|
||||
|
||||
for ($i = 0; $i < 96 && $node < $this->metadata->nodeCount; $i++) {
|
||||
$node = $this->readNode($node, 0);
|
||||
}
|
||||
$this->ipV4Start = $node;
|
||||
return $node;
|
||||
}
|
||||
|
||||
private function readNode($nodeNumber, $index)
|
||||
{
|
||||
$baseOffset = $nodeNumber * $this->metadata->nodeByteSize;
|
||||
|
||||
// XXX - probably could condense this.
|
||||
switch ($this->metadata->recordSize) {
|
||||
case 24:
|
||||
$bytes = Util::read($this->fileHandle, $baseOffset + $index * 3, 3);
|
||||
list(, $node) = unpack('N', "\x00" . $bytes);
|
||||
return $node;
|
||||
case 28:
|
||||
$middleByte = Util::read($this->fileHandle, $baseOffset + 3, 1);
|
||||
list(, $middle) = unpack('C', $middleByte);
|
||||
if ($index == 0) {
|
||||
$middle = (0xF0 & $middle) >> 4;
|
||||
} else {
|
||||
$middle = 0x0F & $middle;
|
||||
}
|
||||
$bytes = Util::read($this->fileHandle, $baseOffset + $index * 4, 3);
|
||||
list(, $node) = unpack('N', chr($middle) . $bytes);
|
||||
return $node;
|
||||
case 32:
|
||||
$bytes = Util::read($this->fileHandle, $baseOffset + $index * 4, 4);
|
||||
list(, $node) = unpack('N', $bytes);
|
||||
return $node;
|
||||
default:
|
||||
throw new InvalidDatabaseException(
|
||||
'Unknown record size: '
|
||||
. $this->metadata->recordSize
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private function resolveDataPointer($pointer)
|
||||
{
|
||||
$resolved = $pointer - $this->metadata->nodeCount
|
||||
+ $this->metadata->searchTreeSize;
|
||||
if ($resolved > $this->fileSize) {
|
||||
throw new InvalidDatabaseException(
|
||||
"The MaxMind DB file's search tree is corrupt"
|
||||
);
|
||||
}
|
||||
|
||||
list($data) = $this->decoder->decode($resolved);
|
||||
return $data;
|
||||
}
|
||||
|
||||
/*
|
||||
* This is an extremely naive but reasonably readable implementation. There
|
||||
* are much faster algorithms (e.g., Boyer-Moore) for this if speed is ever
|
||||
* an issue, but I suspect it won't be.
|
||||
*/
|
||||
private function findMetadataStart($filename)
|
||||
{
|
||||
$handle = $this->fileHandle;
|
||||
$fstat = fstat($handle);
|
||||
$fileSize = $fstat['size'];
|
||||
$marker = self::$METADATA_START_MARKER;
|
||||
$markerLength = self::$METADATA_START_MARKER_LENGTH;
|
||||
|
||||
for ($i = 0; $i < $fileSize - $markerLength + 1; $i++) {
|
||||
for ($j = 0; $j < $markerLength; $j++) {
|
||||
fseek($handle, $fileSize - $i - $j - 1);
|
||||
$matchBit = fgetc($handle);
|
||||
if ($matchBit != $marker[$markerLength - $j - 1]) {
|
||||
continue 2;
|
||||
}
|
||||
}
|
||||
return $fileSize - $i;
|
||||
}
|
||||
throw new InvalidDatabaseException(
|
||||
"Error opening database file ($filename). " .
|
||||
'Is this a valid MaxMind DB file?'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \InvalidArgumentException if arguments are passed to the method.
|
||||
* @throws \BadMethodCallException if the database has been closed.
|
||||
* @return Metadata object for the database.
|
||||
*/
|
||||
public function metadata()
|
||||
{
|
||||
if (func_num_args()) {
|
||||
throw new \InvalidArgumentException(
|
||||
'Method takes no arguments.'
|
||||
);
|
||||
}
|
||||
|
||||
// Not technically required, but this makes it consistent with
|
||||
// C extension and it allows us to change our implementation later.
|
||||
if (!is_resource($this->fileHandle)) {
|
||||
throw new \BadMethodCallException(
|
||||
'Attempt to read from a closed MaxMind DB.'
|
||||
);
|
||||
}
|
||||
|
||||
return $this->metadata;
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the MaxMind DB and returns resources to the system.
|
||||
*
|
||||
* @throws \Exception
|
||||
* if an I/O error occurs.
|
||||
*/
|
||||
public function close()
|
||||
{
|
||||
if (!is_resource($this->fileHandle)) {
|
||||
throw new \BadMethodCallException(
|
||||
'Attempt to close a closed MaxMind DB.'
|
||||
);
|
||||
}
|
||||
fclose($this->fileHandle);
|
||||
}
|
||||
}
|
309
lib/maxmind/MaxMind/Db/Reader/Decoder.php
Normal file
309
lib/maxmind/MaxMind/Db/Reader/Decoder.php
Normal file
@ -0,0 +1,309 @@
|
||||
<?php
|
||||
|
||||
namespace MaxMind\Db\Reader;
|
||||
|
||||
use MaxMind\Db\Reader\InvalidDatabaseException;
|
||||
use MaxMind\Db\Reader\Util;
|
||||
|
||||
class Decoder
|
||||
{
|
||||
|
||||
private $fileStream;
|
||||
private $pointerBase;
|
||||
// This is only used for unit testing
|
||||
private $pointerTestHack;
|
||||
private $switchByteOrder;
|
||||
|
||||
private $types = array(
|
||||
0 => 'extended',
|
||||
1 => 'pointer',
|
||||
2 => 'utf8_string',
|
||||
3 => 'double',
|
||||
4 => 'bytes',
|
||||
5 => 'uint16',
|
||||
6 => 'uint32',
|
||||
7 => 'map',
|
||||
8 => 'int32',
|
||||
9 => 'uint64',
|
||||
10 => 'uint128',
|
||||
11 => 'array',
|
||||
12 => 'container',
|
||||
13 => 'end_marker',
|
||||
14 => 'boolean',
|
||||
15 => 'float',
|
||||
);
|
||||
|
||||
public function __construct(
|
||||
$fileStream,
|
||||
$pointerBase = 0,
|
||||
$pointerTestHack = false
|
||||
) {
|
||||
$this->fileStream = $fileStream;
|
||||
$this->pointerBase = $pointerBase;
|
||||
$this->pointerTestHack = $pointerTestHack;
|
||||
|
||||
$this->switchByteOrder = $this->isPlatformLittleEndian();
|
||||
}
|
||||
|
||||
|
||||
public function decode($offset)
|
||||
{
|
||||
list(, $ctrlByte) = unpack(
|
||||
'C',
|
||||
Util::read($this->fileStream, $offset, 1)
|
||||
);
|
||||
$offset++;
|
||||
|
||||
$type = $this->types[$ctrlByte >> 5];
|
||||
|
||||
// Pointers are a special case, we don't read the next $size bytes, we
|
||||
// use the size to determine the length of the pointer and then follow
|
||||
// it.
|
||||
if ($type == 'pointer') {
|
||||
list($pointer, $offset) = $this->decodePointer($ctrlByte, $offset);
|
||||
|
||||
// for unit testing
|
||||
if ($this->pointerTestHack) {
|
||||
return array($pointer);
|
||||
}
|
||||
|
||||
list($result) = $this->decode($pointer);
|
||||
|
||||
return array($result, $offset);
|
||||
}
|
||||
|
||||
if ($type == 'extended') {
|
||||
list(, $nextByte) = unpack(
|
||||
'C',
|
||||
Util::read($this->fileStream, $offset, 1)
|
||||
);
|
||||
|
||||
$typeNum = $nextByte + 7;
|
||||
|
||||
if ($typeNum < 8) {
|
||||
throw new InvalidDatabaseException(
|
||||
"Something went horribly wrong in the decoder. An extended type "
|
||||
. "resolved to a type number < 8 ("
|
||||
. $this->types[$typeNum]
|
||||
. ")"
|
||||
);
|
||||
}
|
||||
|
||||
$type = $this->types[$typeNum];
|
||||
$offset++;
|
||||
}
|
||||
|
||||
list($size, $offset) = $this->sizeFromCtrlByte($ctrlByte, $offset);
|
||||
|
||||
return $this->decodeByType($type, $offset, $size);
|
||||
}
|
||||
|
||||
private function decodeByType($type, $offset, $size)
|
||||
{
|
||||
switch ($type) {
|
||||
case 'map':
|
||||
return $this->decodeMap($size, $offset);
|
||||
case 'array':
|
||||
return $this->decodeArray($size, $offset);
|
||||
case 'boolean':
|
||||
return array($this->decodeBoolean($size), $offset);
|
||||
}
|
||||
|
||||
$newOffset = $offset + $size;
|
||||
$bytes = Util::read($this->fileStream, $offset, $size);
|
||||
switch ($type) {
|
||||
case 'utf8_string':
|
||||
return array($this->decodeString($bytes), $newOffset);
|
||||
case 'double':
|
||||
$this->verifySize(8, $size);
|
||||
return array($this->decodeDouble($bytes), $newOffset);
|
||||
case 'float':
|
||||
$this->verifySize(4, $size);
|
||||
return array($this->decodeFloat($bytes), $newOffset);
|
||||
case 'bytes':
|
||||
return array($bytes, $newOffset);
|
||||
case 'uint16':
|
||||
case 'uint32':
|
||||
return array($this->decodeUint($bytes), $newOffset);
|
||||
case 'int32':
|
||||
return array($this->decodeInt32($bytes), $newOffset);
|
||||
case 'uint64':
|
||||
case 'uint128':
|
||||
return array($this->decodeBigUint($bytes, $size), $newOffset);
|
||||
default:
|
||||
throw new InvalidDatabaseException(
|
||||
"Unknown or unexpected type: " . $type
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private function verifySize($expected, $actual)
|
||||
{
|
||||
if ($expected != $actual) {
|
||||
throw new InvalidDatabaseException(
|
||||
"The MaxMind DB file's data section contains bad data (unknown data type or corrupt data)"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private function decodeArray($size, $offset)
|
||||
{
|
||||
$array = array();
|
||||
|
||||
for ($i = 0; $i < $size; $i++) {
|
||||
list($value, $offset) = $this->decode($offset);
|
||||
array_push($array, $value);
|
||||
}
|
||||
|
||||
return array($array, $offset);
|
||||
}
|
||||
|
||||
private function decodeBoolean($size)
|
||||
{
|
||||
return $size == 0 ? false : true;
|
||||
}
|
||||
|
||||
private function decodeDouble($bits)
|
||||
{
|
||||
// XXX - Assumes IEEE 754 double on platform
|
||||
list(, $double) = unpack('d', $this->maybeSwitchByteOrder($bits));
|
||||
return $double;
|
||||
}
|
||||
|
||||
private function decodeFloat($bits)
|
||||
{
|
||||
// XXX - Assumes IEEE 754 floats on platform
|
||||
list(, $float) = unpack('f', $this->maybeSwitchByteOrder($bits));
|
||||
return $float;
|
||||
}
|
||||
|
||||
private function decodeInt32($bytes)
|
||||
{
|
||||
$bytes = $this->zeroPadLeft($bytes, 4);
|
||||
list(, $int) = unpack('l', $this->maybeSwitchByteOrder($bytes));
|
||||
return $int;
|
||||
}
|
||||
|
||||
private function decodeMap($size, $offset)
|
||||
{
|
||||
|
||||
$map = array();
|
||||
|
||||
for ($i = 0; $i < $size; $i++) {
|
||||
list($key, $offset) = $this->decode($offset);
|
||||
list($value, $offset) = $this->decode($offset);
|
||||
$map[$key] = $value;
|
||||
}
|
||||
|
||||
return array($map, $offset);
|
||||
}
|
||||
|
||||
private $pointerValueOffset = array(
|
||||
1 => 0,
|
||||
2 => 2048,
|
||||
3 => 526336,
|
||||
4 => 0,
|
||||
);
|
||||
|
||||
private function decodePointer($ctrlByte, $offset)
|
||||
{
|
||||
$pointerSize = (($ctrlByte >> 3) & 0x3) + 1;
|
||||
|
||||
$buffer = Util::read($this->fileStream, $offset, $pointerSize);
|
||||
$offset = $offset + $pointerSize;
|
||||
|
||||
$packed = $pointerSize == 4
|
||||
? $buffer
|
||||
: (pack('C', $ctrlByte & 0x7)) . $buffer;
|
||||
|
||||
$unpacked = $this->decodeUint($packed);
|
||||
$pointer = $unpacked + $this->pointerBase
|
||||
+ $this->pointerValueOffset[$pointerSize];
|
||||
|
||||
return array($pointer, $offset);
|
||||
}
|
||||
|
||||
private function decodeUint($bytes)
|
||||
{
|
||||
list(, $int) = unpack('N', $this->zeroPadLeft($bytes, 4));
|
||||
return $int;
|
||||
}
|
||||
|
||||
private function decodeBigUint($bytes, $byteLength)
|
||||
{
|
||||
$maxUintBytes = log(PHP_INT_MAX, 2) / 8;
|
||||
|
||||
if ($byteLength == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$numberOfLongs = ceil($byteLength / 4);
|
||||
$paddedLength = $numberOfLongs * 4;
|
||||
$paddedBytes = $this->zeroPadLeft($bytes, $paddedLength);
|
||||
$unpacked = array_merge(unpack("N$numberOfLongs", $paddedBytes));
|
||||
|
||||
$integer = 0;
|
||||
|
||||
// 2^32
|
||||
$twoTo32 = '4294967296';
|
||||
|
||||
foreach ($unpacked as $part) {
|
||||
// We only use gmp or bcmath if the final value is too big
|
||||
if ($byteLength <= $maxUintBytes) {
|
||||
$integer = ($integer << 32) + $part;
|
||||
} elseif (extension_loaded('gmp')) {
|
||||
$integer = gmp_strval(gmp_add(gmp_mul($integer, $twoTo32), $part));
|
||||
} elseif (extension_loaded('bcmath')) {
|
||||
$integer = bcadd(bcmul($integer, $twoTo32), $part);
|
||||
} else {
|
||||
throw new \RuntimeException(
|
||||
'The gmp or bcmath extension must be installed to read this database.'
|
||||
);
|
||||
}
|
||||
}
|
||||
return $integer;
|
||||
}
|
||||
|
||||
private function decodeString($bytes)
|
||||
{
|
||||
// XXX - NOOP. As far as I know, the end user has to explicitly set the
|
||||
// encoding in PHP. Strings are just bytes.
|
||||
return $bytes;
|
||||
}
|
||||
|
||||
private function sizeFromCtrlByte($ctrlByte, $offset)
|
||||
{
|
||||
$size = $ctrlByte & 0x1f;
|
||||
$bytesToRead = $size < 29 ? 0 : $size - 28;
|
||||
$bytes = Util::read($this->fileStream, $offset, $bytesToRead);
|
||||
$decoded = $this->decodeUint($bytes);
|
||||
|
||||
if ($size == 29) {
|
||||
$size = 29 + $decoded;
|
||||
} elseif ($size == 30) {
|
||||
$size = 285 + $decoded;
|
||||
} elseif ($size > 30) {
|
||||
$size = ($decoded & (0x0FFFFFFF >> (32 - (8 * $bytesToRead))))
|
||||
+ 65821;
|
||||
}
|
||||
|
||||
return array($size, $offset + $bytesToRead);
|
||||
}
|
||||
|
||||
private function zeroPadLeft($content, $desiredLength)
|
||||
{
|
||||
return str_pad($content, $desiredLength, "\x00", STR_PAD_LEFT);
|
||||
}
|
||||
|
||||
private function maybeSwitchByteOrder($bytes)
|
||||
{
|
||||
return $this->switchByteOrder ? strrev($bytes) : $bytes;
|
||||
}
|
||||
|
||||
private function isPlatformLittleEndian()
|
||||
{
|
||||
$testint = 0x00FF;
|
||||
$packed = pack('S', $testint);
|
||||
return $testint === current(unpack('v', $packed));
|
||||
}
|
||||
}
|
10
lib/maxmind/MaxMind/Db/Reader/InvalidDatabaseException.php
Normal file
10
lib/maxmind/MaxMind/Db/Reader/InvalidDatabaseException.php
Normal file
@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace MaxMind\Db\Reader;
|
||||
|
||||
/**
|
||||
* This class should be thrown when unexpected data is found in the database.
|
||||
*/
|
||||
class InvalidDatabaseException extends \Exception
|
||||
{
|
||||
}
|
77
lib/maxmind/MaxMind/Db/Reader/Metadata.php
Normal file
77
lib/maxmind/MaxMind/Db/Reader/Metadata.php
Normal file
@ -0,0 +1,77 @@
|
||||
<?php
|
||||
|
||||
namespace MaxMind\Db\Reader;
|
||||
|
||||
/**
|
||||
* This class provides the metadata for the MaxMind DB file.
|
||||
*
|
||||
* @property integer nodeCount This is an unsigned 32-bit integer indicating
|
||||
* the number of nodes in the search tree.
|
||||
*
|
||||
* @property integer recordSize This is an unsigned 16-bit integer. It
|
||||
* indicates the number of bits in a record in the search tree. Note that each
|
||||
* node consists of two records.
|
||||
*
|
||||
* @property integer ipVersion This is an unsigned 16-bit integer which is
|
||||
* always 4 or 6. It indicates whether the database contains IPv4 or IPv6
|
||||
* address data.
|
||||
*
|
||||
* @property string databaseType This is a string that indicates the structure
|
||||
* of each data record associated with an IP address. The actual definition of
|
||||
* these structures is left up to the database creator.
|
||||
*
|
||||
* @property array languages An array of strings, each of which is a language
|
||||
* code. A given record may contain data items that have been localized to
|
||||
* some or all of these languages. This may be undefined.
|
||||
*
|
||||
* @property integer binaryFormatMajorVersion This is an unsigned 16-bit
|
||||
* integer indicating the major version number for the database's binary
|
||||
* format.
|
||||
*
|
||||
* @property integer binaryFormatMinorVersion This is an unsigned 16-bit
|
||||
* integer indicating the minor version number for the database's binary format.
|
||||
*
|
||||
* @property integer buildEpoch This is an unsigned 64-bit integer that
|
||||
* contains the database build timestamp as a Unix epoch value.
|
||||
*
|
||||
* @property array description This key will always point to a map
|
||||
* (associative array). The keys of that map will be language codes, and the
|
||||
* values will be a description in that language as a UTF-8 string. May be
|
||||
* undefined for some databases.
|
||||
*/
|
||||
class Metadata
|
||||
{
|
||||
private $binaryFormatMajorVersion;
|
||||
private $binaryFormatMinorVersion;
|
||||
private $buildEpoch;
|
||||
private $databaseType;
|
||||
private $description;
|
||||
private $ipVersion;
|
||||
private $languages;
|
||||
private $nodeByteSize;
|
||||
private $nodeCount;
|
||||
private $recordSize;
|
||||
private $searchTreeSize;
|
||||
|
||||
public function __construct($metadata)
|
||||
{
|
||||
$this->binaryFormatMajorVersion =
|
||||
$metadata['binary_format_major_version'];
|
||||
$this->binaryFormatMinorVersion =
|
||||
$metadata['binary_format_minor_version'];
|
||||
$this->buildEpoch = $metadata['build_epoch'];
|
||||
$this->databaseType = $metadata['database_type'];
|
||||
$this->languages = $metadata['languages'];
|
||||
$this->description = $metadata['description'];
|
||||
$this->ipVersion = $metadata['ip_version'];
|
||||
$this->nodeCount = $metadata['node_count'];
|
||||
$this->recordSize = $metadata['record_size'];
|
||||
$this->nodeByteSize = $this->recordSize / 4;
|
||||
$this->searchTreeSize = $this->nodeCount * $this->nodeByteSize;
|
||||
}
|
||||
|
||||
public function __get($var)
|
||||
{
|
||||
return $this->$var;
|
||||
}
|
||||
}
|
28
lib/maxmind/MaxMind/Db/Reader/Util.php
Normal file
28
lib/maxmind/MaxMind/Db/Reader/Util.php
Normal file
@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
namespace MaxMind\Db\Reader;
|
||||
|
||||
use MaxMind\Db\Reader\InvalidDatabaseException;
|
||||
|
||||
class Util
|
||||
{
|
||||
public static function read($stream, $offset, $numberOfBytes)
|
||||
{
|
||||
if ($numberOfBytes == 0) {
|
||||
return '';
|
||||
}
|
||||
if (fseek($stream, $offset) == 0) {
|
||||
$value = fread($stream, $numberOfBytes);
|
||||
|
||||
// We check that the number of bytes read is equal to the number
|
||||
// asked for. We use ftell as getting the length of $value is
|
||||
// much slower.
|
||||
if (ftell($stream) - $offset === $numberOfBytes) {
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
throw new InvalidDatabaseException(
|
||||
"The MaxMind DB file contains bad data"
|
||||
);
|
||||
}
|
||||
}
|
30
lib/maxmind/README_moodle.txt
Normal file
30
lib/maxmind/README_moodle.txt
Normal file
@ -0,0 +1,30 @@
|
||||
GeoIP2 PHP API
|
||||
==============
|
||||
|
||||
No changes from the upstream version have been made, it is recommended by upstream
|
||||
to install these depdencies via composer - but the composer installation is bundled
|
||||
with a load of test files, shell scripts etc (and we don't use composer to manage
|
||||
'production depdendencies') so we have to do it manually.
|
||||
|
||||
Information
|
||||
-----------
|
||||
|
||||
URL: http://maxmind.github.io/GeoIP2-php/
|
||||
License: Apache License, Version 2.0.
|
||||
|
||||
Installation
|
||||
------------
|
||||
|
||||
1) Download the latest versions of GeoIP2-php and MaxMind-DB-Reader-php
|
||||
wget https://github.com/maxmind/GeoIP2-php/archive/v2.4.2.zip
|
||||
wget https://github.com/maxmind/MaxMind-DB-Reader-php/archive/v1.1.0.zip
|
||||
|
||||
2) Unzip the archives
|
||||
unzip v2.4.2.zip
|
||||
unzip v1.1.0.zip
|
||||
|
||||
3) Move the source code directories into place
|
||||
mv GeoIP2-php-2.4.2/src/ /path/to/moodle/lib/maxmind/GeoIp2/
|
||||
mv MaxMind-DB-Reader-php-1.1.0/src/MaxMind/ /path/to/moodle/lib/maxmind/MaxMind/
|
||||
|
||||
4) Run unit tests on iplookup/tests/geoip_test.php with PHPUNIT_LONGTEST defined.
|
@ -260,4 +260,16 @@
|
||||
<license>MIT</license>
|
||||
<version>2.1.6</version>
|
||||
</library>
|
||||
<library>
|
||||
<location>maxmind/GeoIP2</location>
|
||||
<name>GeoIP2 PHP API</name>
|
||||
<license>Apache 2.0</license>
|
||||
<version>2.4.2</version>
|
||||
</library>
|
||||
<library>
|
||||
<location>maxmind/MaxMind</location>
|
||||
<name>MaxMind DB Reader API</name>
|
||||
<license>Apache 2.0</license>
|
||||
<version>1.1.0</version>
|
||||
</library>
|
||||
</libraries>
|
||||
|
@ -29,7 +29,7 @@
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$version = 2016091500.00; // YYYYMMDD = weekly release date of this DEV branch.
|
||||
$version = 2016091501.00; // YYYYMMDD = weekly release date of this DEV branch.
|
||||
// RR = release increments - 00 in DEV branches.
|
||||
// .XX = incremental changes.
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user