diff --git a/lib/maxmind/GeoIp2/Compat/JsonSerializable.php b/lib/maxmind/GeoIp2/Compat/JsonSerializable.php
deleted file mode 100644
index 4846ce71626..00000000000
--- a/lib/maxmind/GeoIp2/Compat/JsonSerializable.php
+++ /dev/null
@@ -1,27 +0,0 @@
-dbReader = new DbReader($filename);
+ $this->dbType = $this->dbReader->metadata()->databaseType;
$this->locales = $locales;
}
@@ -212,9 +214,11 @@ class Reader implements ProviderInterface
private function modelFor($class, $type, $ipAddress)
{
- $record = $this->getRecord($class, $type, $ipAddress);
+ list($record, $prefixLen) = $this->getRecord($class, $type, $ipAddress);
$record['traits']['ip_address'] = $ipAddress;
+ $record['traits']['prefix_len'] = $prefixLen;
+
$class = 'GeoIp2\\Model\\' . $class;
return new $class($record, $this->locales);
@@ -222,9 +226,10 @@ class Reader implements ProviderInterface
private function flatModelFor($class, $type, $ipAddress)
{
- $record = $this->getRecord($class, $type, $ipAddress);
+ list($record, $prefixLen) = $this->getRecord($class, $type, $ipAddress);
$record['ip_address'] = $ipAddress;
+ $record['prefix_len'] = $prefixLen;
$class = 'GeoIp2\\Model\\' . $class;
return new $class($record);
@@ -232,20 +237,19 @@ class Reader implements ProviderInterface
private function getRecord($class, $type, $ipAddress)
{
- if (strpos($this->metadata()->databaseType, $type) === false) {
+ if (strpos($this->dbType, $type) === false) {
$method = lcfirst($class);
throw new \BadMethodCallException(
- "The $method method cannot be used to open a "
- . $this->metadata()->databaseType . ' database'
+ "The $method method cannot be used to open a {$this->dbType} database"
);
}
- $record = $this->dbReader->get($ipAddress);
+ list($record, $prefixLen) = $this->dbReader->getWithPrefixLen($ipAddress);
if ($record === null) {
throw new AddressNotFoundException(
"The address $ipAddress is not in the database."
);
}
- if (!is_array($record)) {
+ if (!\is_array($record)) {
// This can happen on corrupt databases. Generally,
// MaxMind\Db\Reader will throw a
// MaxMind\Db\Reader\InvalidDatabaseException, but occasionally
@@ -255,11 +259,11 @@ class Reader implements ProviderInterface
// exceptions go unnoticed.
throw new InvalidDatabaseException(
"Expected an array when looking up $ipAddress but received: "
- . gettype($record)
+ . \gettype($record)
);
}
- return $record;
+ return [$record, $prefixLen];
}
/**
diff --git a/lib/maxmind/GeoIp2/Model/AnonymousIp.php b/lib/maxmind/GeoIp2/Model/AnonymousIp.php
index bdaeb898105..a8f946ee865 100644
--- a/lib/maxmind/GeoIp2/Model/AnonymousIp.php
+++ b/lib/maxmind/GeoIp2/Model/AnonymousIp.php
@@ -2,21 +2,28 @@
namespace GeoIp2\Model;
+use GeoIp2\Util;
+
/**
* This class provides the GeoIP2 Anonymous IP model.
*
* @property-read bool $isAnonymous This is true if the IP address belongs to
* any sort of anonymous network.
- * @property-read bool $isAnonymousVpn This is true if the IP address belongs to
- * an anonymous VPN system.
+ * @property-read bool $isAnonymousVpn This is true if the IP address is
+ * registered to an anonymous VPN provider. If a VPN provider does not
+ * register subnets under names associated with them, we will likely only
+ * flag their IP ranges using the isHostingProvider property.
* @property-read bool $isHostingProvider This is true if the IP address belongs
- * to a hosting provider.
+ * to a hosting or VPN provider (see description of isAnonymousVpn property).
* @property-read bool $isPublicProxy This is true if the IP address belongs to
* a public proxy.
* @property-read bool $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.
+ * @property-read string $network The network in CIDR notation associated with
+ * the record. In particular, this is the largest network where all of the
+ * fields besides $ipAddress have the same value.
*/
class AnonymousIp extends AbstractModel
{
@@ -26,6 +33,7 @@ class AnonymousIp extends AbstractModel
protected $isPublicProxy;
protected $isTorExitNode;
protected $ipAddress;
+ protected $network;
/**
* @ignore
@@ -41,6 +49,8 @@ class AnonymousIp extends AbstractModel
$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');
+ $ipAddress = $this->get('ip_address');
+ $this->ipAddress = $ipAddress;
+ $this->network = Util::cidr($ipAddress, $this->get('prefix_len'));
}
}
diff --git a/lib/maxmind/GeoIp2/Model/Asn.php b/lib/maxmind/GeoIp2/Model/Asn.php
index 4144142fe02..8e7c802eeba 100644
--- a/lib/maxmind/GeoIp2/Model/Asn.php
+++ b/lib/maxmind/GeoIp2/Model/Asn.php
@@ -2,6 +2,8 @@
namespace GeoIp2\Model;
+use GeoIp2\Util;
+
/**
* This class provides the GeoLite2 ASN model.
*
@@ -12,12 +14,16 @@ namespace GeoIp2\Model;
* address.
* @property-read string $ipAddress The IP address that the data in the model is
* for.
+ * @property-read string $network The network in CIDR notation associated with
+ * the record. In particular, this is the largest network where all of the
+ * fields besides $ipAddress have the same value.
*/
class Asn extends AbstractModel
{
protected $autonomousSystemNumber;
protected $autonomousSystemOrganization;
protected $ipAddress;
+ protected $network;
/**
* @ignore
@@ -30,6 +36,8 @@ class Asn extends AbstractModel
$this->autonomousSystemNumber = $this->get('autonomous_system_number');
$this->autonomousSystemOrganization =
$this->get('autonomous_system_organization');
- $this->ipAddress = $this->get('ip_address');
+ $ipAddress = $this->get('ip_address');
+ $this->ipAddress = $ipAddress;
+ $this->network = Util::cidr($ipAddress, $this->get('prefix_len'));
}
}
diff --git a/lib/maxmind/GeoIp2/Model/City.php b/lib/maxmind/GeoIp2/Model/City.php
index 32859035a1e..3e78c4f14c4 100644
--- a/lib/maxmind/GeoIp2/Model/City.php
+++ b/lib/maxmind/GeoIp2/Model/City.php
@@ -7,42 +7,25 @@ namespace GeoIp2\Model;
*
* 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.
+ * https://dev.maxmind.com/geoip/geoip2/web-services for 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}
+ * @property-read array $subdivisions An array \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
+ * @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.
+ * \GeoIp2\Record\Subdivision object.
*/
class City extends Country
{
diff --git a/lib/maxmind/GeoIp2/Model/ConnectionType.php b/lib/maxmind/GeoIp2/Model/ConnectionType.php
index 169e7c11792..8091e26ce50 100644
--- a/lib/maxmind/GeoIp2/Model/ConnectionType.php
+++ b/lib/maxmind/GeoIp2/Model/ConnectionType.php
@@ -2,6 +2,8 @@
namespace GeoIp2\Model;
+use GeoIp2\Util;
+
/**
* This class provides the GeoIP2 Connection-Type model.
*
@@ -10,11 +12,15 @@ namespace GeoIp2\Model;
* Additional values may be added in the future.
* @property-read string $ipAddress The IP address that the data in the model is
* for.
+ * @property-read string $network The network in CIDR notation associated with
+ * the record. In particular, this is the largest network where all of the
+ * fields besides $ipAddress have the same value.
*/
class ConnectionType extends AbstractModel
{
protected $connectionType;
protected $ipAddress;
+ protected $network;
/**
* @ignore
@@ -26,6 +32,8 @@ class ConnectionType extends AbstractModel
parent::__construct($raw);
$this->connectionType = $this->get('connection_type');
- $this->ipAddress = $this->get('ip_address');
+ $ipAddress = $this->get('ip_address');
+ $this->ipAddress = $ipAddress;
+ $this->network = Util::cidr($ipAddress, $this->get('prefix_len'));
}
}
diff --git a/lib/maxmind/GeoIp2/Model/Country.php b/lib/maxmind/GeoIp2/Model/Country.php
index 17833a152ca..a589d25f43f 100644
--- a/lib/maxmind/GeoIp2/Model/Country.php
+++ b/lib/maxmind/GeoIp2/Model/Country.php
@@ -7,7 +7,7 @@ namespace GeoIp2\Model;
*
* 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.
+ * https://dev.maxmind.com/geoip/geoip2/web-services for more details.
*
* @property-read \GeoIp2\Record\Continent $continent Continent data for the
* requested IP address.
diff --git a/lib/maxmind/GeoIp2/Model/Domain.php b/lib/maxmind/GeoIp2/Model/Domain.php
index f452e866917..5e2cf346dde 100644
--- a/lib/maxmind/GeoIp2/Model/Domain.php
+++ b/lib/maxmind/GeoIp2/Model/Domain.php
@@ -2,6 +2,8 @@
namespace GeoIp2\Model;
+use GeoIp2\Util;
+
/**
* This class provides the GeoIP2 Domain model.
*
@@ -10,11 +12,15 @@ namespace GeoIp2\Model;
* "example.co.uk", not "foo.example.com".
* @property-read string $ipAddress The IP address that the data in the model is
* for.
+ * @property-read string $network The network in CIDR notation associated with
+ * the record. In particular, this is the largest network where all of the
+ * fields besides $ipAddress have the same value.
*/
class Domain extends AbstractModel
{
protected $domain;
protected $ipAddress;
+ protected $network;
/**
* @ignore
@@ -26,6 +32,8 @@ class Domain extends AbstractModel
parent::__construct($raw);
$this->domain = $this->get('domain');
- $this->ipAddress = $this->get('ip_address');
+ $ipAddress = $this->get('ip_address');
+ $this->ipAddress = $ipAddress;
+ $this->network = Util::cidr($ipAddress, $this->get('prefix_len'));
}
}
diff --git a/lib/maxmind/GeoIp2/Model/Enterprise.php b/lib/maxmind/GeoIp2/Model/Enterprise.php
index 6b98c0553de..c50fb81db70 100644
--- a/lib/maxmind/GeoIp2/Model/Enterprise.php
+++ b/lib/maxmind/GeoIp2/Model/Enterprise.php
@@ -7,40 +7,7 @@ namespace GeoIp2\Model;
*
* 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.
+ * https://dev.maxmind.com/geoip/geoip2/web-services for more details.
*/
class Enterprise extends City
{
diff --git a/lib/maxmind/GeoIp2/Model/Insights.php b/lib/maxmind/GeoIp2/Model/Insights.php
index cefcfb916c9..61beb2ed6e3 100644
--- a/lib/maxmind/GeoIp2/Model/Insights.php
+++ b/lib/maxmind/GeoIp2/Model/Insights.php
@@ -7,40 +7,7 @@ namespace GeoIp2\Model;
*
* 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.
+ * https://dev.maxmind.com/geoip/geoip2/web-services for more details.
*/
class Insights extends City
{
diff --git a/lib/maxmind/GeoIp2/Model/Isp.php b/lib/maxmind/GeoIp2/Model/Isp.php
index 51e0b680ecb..1a7b5153880 100644
--- a/lib/maxmind/GeoIp2/Model/Isp.php
+++ b/lib/maxmind/GeoIp2/Model/Isp.php
@@ -2,6 +2,8 @@
namespace GeoIp2\Model;
+use GeoIp2\Util;
+
/**
* This class provides the GeoIP2 ISP model.
*
@@ -16,6 +18,9 @@ namespace GeoIp2\Model;
* with the IP address.
* @property-read string $ipAddress The IP address that the data in the model is
* for.
+ * @property-read string $network The network in CIDR notation associated with
+ * the record. In particular, this is the largest network where all of the
+ * fields besides $ipAddress have the same value.
*/
class Isp extends AbstractModel
{
@@ -24,6 +29,7 @@ class Isp extends AbstractModel
protected $isp;
protected $organization;
protected $ipAddress;
+ protected $network;
/**
* @ignore
@@ -39,6 +45,8 @@ class Isp extends AbstractModel
$this->isp = $this->get('isp');
$this->organization = $this->get('organization');
- $this->ipAddress = $this->get('ip_address');
+ $ipAddress = $this->get('ip_address');
+ $this->ipAddress = $ipAddress;
+ $this->network = Util::cidr($ipAddress, $this->get('prefix_len'));
}
}
diff --git a/lib/maxmind/GeoIp2/Record/AbstractRecord.php b/lib/maxmind/GeoIp2/Record/AbstractRecord.php
index 5d8cb0bf10d..dad2fd3f376 100644
--- a/lib/maxmind/GeoIp2/Record/AbstractRecord.php
+++ b/lib/maxmind/GeoIp2/Record/AbstractRecord.php
@@ -51,7 +51,7 @@ abstract class AbstractRecord implements \JsonSerializable
private function validAttribute($attr)
{
- return in_array($attr, $this->validAttributes, true);
+ return \in_array($attr, $this->validAttributes, true);
}
public function jsonSerialize()
diff --git a/lib/maxmind/GeoIp2/Record/Country.php b/lib/maxmind/GeoIp2/Record/Country.php
index 477bc1d63f1..ff9ecc7cd02 100644
--- a/lib/maxmind/GeoIp2/Record/Country.php
+++ b/lib/maxmind/GeoIp2/Record/Country.php
@@ -15,10 +15,9 @@ namespace GeoIp2\Record;
* @property-read bool $isInEuropeanUnion This is true if the country is a
* member state of the European Union. This attribute is returned by all
* 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 $isoCode The two-character ISO 3166-1 alpha code
+ * for the country. See https://en.wikipedia.org/wiki/ISO_3166-1. 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.
diff --git a/lib/maxmind/GeoIp2/Record/Location.php b/lib/maxmind/GeoIp2/Record/Location.php
index 9b81adf33e4..b59b3ee70c1 100644
--- a/lib/maxmind/GeoIp2/Record/Location.php
+++ b/lib/maxmind/GeoIp2/Record/Location.php
@@ -27,11 +27,11 @@ namespace GeoIp2\Record;
* 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}.
+ * Google AdWords API. See
+ * https://developers.google.com/adwords/api/docs/appendix/cities-DMAregions.
* @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".
+ * specified by the IANA Time Zone Database, e.g., "America/New_York". See
+ * https://www.iana.org/time-zones.
*/
class Location extends AbstractRecord
{
diff --git a/lib/maxmind/GeoIp2/Record/RepresentedCountry.php b/lib/maxmind/GeoIp2/Record/RepresentedCountry.php
index 13082dd0fb7..bc79ee15742 100644
--- a/lib/maxmind/GeoIp2/Record/RepresentedCountry.php
+++ b/lib/maxmind/GeoIp2/Record/RepresentedCountry.php
@@ -9,19 +9,6 @@ namespace GeoIp2\Record;
* 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 bool $isInEuropeanUnion This is true if the country is a
- * member state of the European Union. This attribute is returned by all
- * 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.
- * @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 military
* but this could expand to include other types in the future.
diff --git a/lib/maxmind/GeoIp2/Record/Subdivision.php b/lib/maxmind/GeoIp2/Record/Subdivision.php
index 386c68d8fa7..74ae3e2caad 100644
--- a/lib/maxmind/GeoIp2/Record/Subdivision.php
+++ b/lib/maxmind/GeoIp2/Record/Subdivision.php
@@ -16,9 +16,9 @@ namespace GeoIp2\Record;
* 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.
+ * contain the subdivision portion of the ISO 3166-2 code. See
+ * https://en.wikipedia.org/wiki/ISO_3166-2. 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.
diff --git a/lib/maxmind/GeoIp2/Record/Traits.php b/lib/maxmind/GeoIp2/Record/Traits.php
index bc5f07d547c..e6b798f41ca 100644
--- a/lib/maxmind/GeoIp2/Record/Traits.php
+++ b/lib/maxmind/GeoIp2/Record/Traits.php
@@ -2,21 +2,23 @@
namespace GeoIp2\Record;
+use GeoIp2\Util;
+
/**
* 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
+ * @property-read int|null $autonomousSystemNumber The autonomous system number
+ * associated with the IP address. See
+ * https://en.wikipedia.org/wiki/Autonomous_system_(Internet%29. 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.
+ * associated with the registered autonomous system number for the IP address.
+ * See https://en.wikipedia.org/wiki/Autonomous_system_(Internet%29. 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
@@ -35,16 +37,18 @@ namespace GeoIp2\Record;
* @property-read bool $isAnonymous This is true if the IP address belongs to
* any sort of anonymous network. This property is only available from GeoIP2
* Precision Insights.
- * @property-read bool $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 bool $isAnonymousVpn This is true if the IP address belongs to
- * an anonymous VPN system. This property is only available from GeoIP2
- * Precision Insights.
+ * @property-read bool $isAnonymousProxy *Deprecated.* Please see our GeoIP2
+ * Anonymous IP database
+ * (https://www.maxmind.com/en/geoip2-anonymous-ip-database) to determine
+ * whether the IP address is used by an anonymizing service.
+ * @property-read bool $isAnonymousVpn This is true if the IP address is
+ * registered to an anonymous VPN provider. If a VPN provider does not register
+ * subnets under names associated with them, we will likely only flag their IP
+ * ranges using the isHostingProvider property. This property is only available
+ * from GeoIP2 Precision Insights.
* @property-read bool $isHostingProvider This is true if the IP address belongs
- * to a hosting provider. This property is only available from GeoIP2
- * Precision Insights.
+ * to a hosting or VPN provider (see description of isAnonymousVpn property).
+ * This property is only available from GeoIP2 Precision Insights.
* @property-read bool $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
@@ -61,9 +65,19 @@ namespace GeoIp2\Record;
* @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 $network The network in CIDR notation associated with
+ * the record. In particular, this is the largest network where all of the
+ * fields besides $ipAddress have the same value.
* @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 float|null $staticIPScore An indicator of how static or
+ * dynamic an IP address is. This property is only available from GeoIP2
+ * Precision Insights.
+ * @property-read int|null $userCount The estimated number of users sharing
+ * the IP/network during the past 24 hours. For IPv4, the count is for the
+ * individual IP. For IPv6, the count is for the /64 network. This property is
+ * only available from GeoIP2 Precision Insights.
* @property-read string|null $userType
The user type associated with the IP * address. This can be one of the following values:
*get method.
+ * addresses can be looked up using the get method.
*/
class Reader
{
@@ -31,7 +35,7 @@ class Reader
* @param string $database
* the MaxMind DB file to use
*
- * @throws \InvalidArgumentException for invalid database path or unknown arguments
+ * @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
@@ -39,25 +43,25 @@ class Reader
public function __construct($database)
{
if (\func_num_args() !== 1) {
- throw new \InvalidArgumentException(
+ throw new InvalidArgumentException(
'The constructor takes exactly one argument.'
);
}
if (!is_readable($database)) {
- throw new \InvalidArgumentException(
+ 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(
+ throw new InvalidArgumentException(
"Error opening \"$database\"."
);
}
$this->fileSize = @filesize($database);
if ($this->fileSize === false) {
- throw new \UnexpectedValueException(
+ throw new UnexpectedValueException(
"Error determining the size of \"$database\"."
);
}
@@ -70,115 +74,133 @@ class Reader
$this->fileHandle,
$this->metadata->searchTreeSize + self::$DATA_SECTION_SEPARATOR_SIZE
);
+ $this->ipV4Start = $this->ipV4StartNode();
}
/**
- * Looks up the address in the MaxMind DB.
+ * Retrieves the record for the IP address.
*
* @param string $ipAddress
* the IP address to look up
*
- * @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 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
+ * if the database is invalid or there is an error reading
+ * from it
*
- * @return array the record for the IP address
+ * @return mixed the record for the IP address
*/
public function get($ipAddress)
{
if (\func_num_args() !== 1) {
- throw new \InvalidArgumentException(
+ throw new InvalidArgumentException(
+ 'Method takes exactly one argument.'
+ );
+ }
+ list($record) = $this->getWithPrefixLen($ipAddress);
+
+ return $record;
+ }
+
+ /**
+ * Retrieves the record for the IP address and its associated network prefix length.
+ *
+ * @param string $ipAddress
+ * the IP address to look up
+ *
+ * @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
+ *
+ * @return array an array where the first element is the record and the
+ * second the network prefix length for the record
+ */
+ public function getWithPrefixLen($ipAddress)
+ {
+ if (\func_num_args() !== 1) {
+ throw new InvalidArgumentException(
'Method takes exactly one argument.'
);
}
if (!\is_resource($this->fileHandle)) {
- throw new \BadMethodCallException(
+ throw new BadMethodCallException(
'Attempt to read from a closed MaxMind DB.'
);
}
if (!filter_var($ipAddress, FILTER_VALIDATE_IP)) {
- throw new \InvalidArgumentException(
+ 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);
+ list($pointer, $prefixLen) = $this->findAddressInTree($ipAddress);
if ($pointer === 0) {
- return null;
+ return [null, $prefixLen];
}
- return $this->resolveDataPointer($pointer);
+ return [$this->resolveDataPointer($pointer), $prefixLen];
}
private function findAddressInTree($ipAddress)
{
- // XXX - could simplify. Done as a byte array to ease porting
- $rawAddress = array_merge(unpack('C*', inet_pton($ipAddress)));
+ $rawAddress = 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);
+ $node = 0;
- for ($i = 0; $i < $bitCount; ++$i) {
- if ($node >= $this->metadata->nodeCount) {
- break;
+ $metadata = $this->metadata;
+
+ // 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 ($metadata->ipVersion === 6) {
+ if ($bitCount === 32) {
+ $node = $this->ipV4Start;
}
- $tempBit = 0xFF & $rawAddress[$i >> 3];
+ } elseif ($metadata->ipVersion === 4 && $bitCount === 128) {
+ throw new InvalidArgumentException(
+ "Error looking up $ipAddress. You attempted to look up an"
+ . ' IPv6 address in an IPv4-only database.'
+ );
+ }
+
+ $nodeCount = $metadata->nodeCount;
+
+ for ($i = 0; $i < $bitCount && $node < $nodeCount; ++$i) {
+ $tempBit = 0xFF & $rawAddress[($i >> 3) + 1];
$bit = 1 & ($tempBit >> 7 - ($i % 8));
$node = $this->readNode($node, $bit);
}
- if ($node === $this->metadata->nodeCount) {
+ if ($node === $nodeCount) {
// Record is empty
- return 0;
- } elseif ($node > $this->metadata->nodeCount) {
+ return [0, $i];
+ } elseif ($node > $nodeCount) {
// Record is a data pointer
- return $node;
+ return [$node, $i];
}
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 we have an IPv4 database, the start node is the first node
if ($this->metadata->ipVersion === 4) {
return 0;
}
- if ($this->ipV4Start) {
- 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;
}
@@ -187,7 +209,6 @@ class Reader
{
$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);
@@ -195,15 +216,13 @@ class Reader
return $node;
case 28:
- $middleByte = Util::read($this->fileHandle, $baseOffset + 3, 1);
- list(, $middle) = unpack('C', $middleByte);
+ $bytes = Util::read($this->fileHandle, $baseOffset + 3 * $index, 4);
if ($index === 0) {
- $middle = (0xF0 & $middle) >> 4;
+ $middle = (0xF0 & \ord($bytes[3])) >> 4;
} else {
- $middle = 0x0F & $middle;
+ $middle = 0x0F & \ord($bytes[0]);
}
- $bytes = Util::read($this->fileHandle, $baseOffset + $index * 4, 3);
- list(, $node) = unpack('N', \chr($middle) . $bytes);
+ list(, $node) = unpack('N', \chr($middle) . substr($bytes, $index, 3));
return $node;
case 32:
@@ -223,7 +242,7 @@ class Reader
{
$resolved = $pointer - $this->metadata->nodeCount
+ $this->metadata->searchTreeSize;
- if ($resolved > $this->fileSize) {
+ if ($resolved >= $this->fileSize) {
throw new InvalidDatabaseException(
"The MaxMind DB file's search tree is corrupt"
);
@@ -246,19 +265,18 @@ class Reader
$fileSize = $fstat['size'];
$marker = self::$METADATA_START_MARKER;
$markerLength = self::$METADATA_START_MARKER_LENGTH;
- $metadataMaxLengthExcludingMarker
- = min(self::$METADATA_MAX_SIZE, $fileSize) - $markerLength;
- for ($i = 0; $i <= $metadataMaxLengthExcludingMarker; ++$i) {
- for ($j = 0; $j < $markerLength; ++$j) {
- fseek($handle, $fileSize - $i - $j - 1);
- $matchBit = fgetc($handle);
- if ($matchBit !== $marker[$markerLength - $j - 1]) {
- continue 2;
- }
+ $minStart = $fileSize - min(self::$METADATA_MAX_SIZE, $fileSize);
+
+ for ($offset = $fileSize - $markerLength; $offset >= $minStart; --$offset) {
+ if (fseek($handle, $offset) !== 0) {
+ break;
}
- return $fileSize - $i;
+ $value = fread($handle, $markerLength);
+ if ($value === $marker) {
+ return $offset + $markerLength;
+ }
}
throw new InvalidDatabaseException(
"Error opening database file ($filename). " .
@@ -267,15 +285,15 @@ class Reader
}
/**
- * @throws \InvalidArgumentException if arguments are passed to the method
- * @throws \BadMethodCallException if the database has been closed
+ * @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(
+ throw new InvalidArgumentException(
'Method takes no arguments.'
);
}
@@ -283,7 +301,7 @@ class Reader
// 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(
+ throw new BadMethodCallException(
'Attempt to read from a closed MaxMind DB.'
);
}
@@ -294,13 +312,13 @@ class Reader
/**
* Closes the MaxMind DB and returns resources to the system.
*
- * @throws \Exception
- * if an I/O error occurs
+ * @throws Exception
+ * if an I/O error occurs
*/
public function close()
{
if (!\is_resource($this->fileHandle)) {
- throw new \BadMethodCallException(
+ throw new BadMethodCallException(
'Attempt to close a closed MaxMind DB.'
);
}
diff --git a/lib/maxmind/MaxMind/Db/Reader/Decoder.php b/lib/maxmind/MaxMind/Db/Reader/Decoder.php
index a71b3de8ec5..132dae82c22 100644
--- a/lib/maxmind/MaxMind/Db/Reader/Decoder.php
+++ b/lib/maxmind/MaxMind/Db/Reader/Decoder.php
@@ -3,7 +3,13 @@
namespace MaxMind\Db\Reader;
// @codingStandardsIgnoreLine
-// We subtract 1 from the log to protect against precision loss.
+use RuntimeException;
+
+/**
+ * @ignore
+ *
+ * We subtract 1 from the log to protect against precision loss.
+ */
\define(__NAMESPACE__ . '\_MM_MAX_INT_BYTES', (log(PHP_INT_MAX, 2) - 1) / 8);
class Decoder
@@ -15,21 +21,37 @@ class Decoder
private $pointerTestHack;
private $switchByteOrder;
+ /** @ignore */
const _EXTENDED = 0;
+ /** @ignore */
const _POINTER = 1;
+ /** @ignore */
const _UTF8_STRING = 2;
+ /** @ignore */
const _DOUBLE = 3;
+ /** @ignore */
const _BYTES = 4;
+ /** @ignore */
const _UINT16 = 5;
+ /** @ignore */
const _UINT32 = 6;
+ /** @ignore */
const _MAP = 7;
+ /** @ignore */
const _INT32 = 8;
+ /** @ignore */
const _UINT64 = 9;
+ /** @ignore */
const _UINT128 = 10;
+ /** @ignore */
const _ARRAY = 11;
+ /** @ignore */
const _CONTAINER = 12;
+ /** @ignore */
const _END_MARKER = 13;
+ /** @ignore */
const _BOOLEAN = 14;
+ /** @ignore */
const _FLOAT = 15;
public function __construct(
@@ -48,10 +70,7 @@ class Decoder
public function decode($offset)
{
- list(, $ctrlByte) = unpack(
- 'C',
- Util::read($this->fileStream, $offset, 1)
- );
+ $ctrlByte = \ord(Util::read($this->fileStream, $offset, 1));
++$offset;
$type = $ctrlByte >> 5;
@@ -73,10 +92,7 @@ class Decoder
}
if ($type === self::_EXTENDED) {
- list(, $nextByte) = unpack(
- 'C',
- Util::read($this->fileStream, $offset, 1)
- );
+ $nextByte = \ord(Util::read($this->fileStream, $offset, 1));
$type = $nextByte + 7;
@@ -233,17 +249,17 @@ class Decoder
switch ($pointerSize) {
case 1:
- $packed = (pack('C', $ctrlByte & 0x7)) . $buffer;
+ $packed = \chr($ctrlByte & 0x7) . $buffer;
list(, $pointer) = unpack('n', $packed);
$pointer += $this->pointerBase;
break;
case 2:
- $packed = "\x00" . (pack('C', $ctrlByte & 0x7)) . $buffer;
+ $packed = "\x00" . \chr($ctrlByte & 0x7) . $buffer;
list(, $pointer) = unpack('N', $packed);
$pointer += $this->pointerBase + 2048;
break;
case 3:
- $packed = (pack('C', $ctrlByte & 0x7)) . $buffer;
+ $packed = \chr($ctrlByte & 0x7) . $buffer;
// It is safe to use 'N' here, even on 32 bit machines as the
// first bit is 0.
@@ -264,7 +280,7 @@ class Decoder
} elseif (\extension_loaded('bcmath')) {
$pointer = bcadd($pointerOffset, $this->pointerBase);
} else {
- throw new \RuntimeException(
+ throw new RuntimeException(
'The gmp or bcmath extension must be installed to read this database.'
);
}
@@ -292,7 +308,7 @@ class Decoder
} elseif (\extension_loaded('bcmath')) {
$integer = bcadd(bcmul($integer, 256), $part);
} else {
- throw new \RuntimeException(
+ throw new RuntimeException(
'The gmp or bcmath extension must be installed to read this database.'
);
}
@@ -319,8 +335,7 @@ class Decoder
$size = 285 + $adjust;
} elseif ($size > 30) {
list(, $adjust) = unpack('N', "\x00" . $bytes);
- $size = ($adjust & (0x0FFFFFFF >> (32 - (8 * $bytesToRead))))
- + 65821;
+ $size = $adjust + 65821;
}
return [$size, $offset + $bytesToRead];
diff --git a/lib/maxmind/MaxMind/Db/Reader/InvalidDatabaseException.php b/lib/maxmind/MaxMind/Db/Reader/InvalidDatabaseException.php
index d2a9a775f28..478a22c5563 100644
--- a/lib/maxmind/MaxMind/Db/Reader/InvalidDatabaseException.php
+++ b/lib/maxmind/MaxMind/Db/Reader/InvalidDatabaseException.php
@@ -2,9 +2,11 @@
namespace MaxMind\Db\Reader;
+use Exception;
+
/**
* This class should be thrown when unexpected data is found in the database.
*/
-class InvalidDatabaseException extends \Exception
+class InvalidDatabaseException extends Exception
{
}
diff --git a/lib/maxmind/MaxMind/Db/Reader/Metadata.php b/lib/maxmind/MaxMind/Db/Reader/Metadata.php
index 4efdd3dedac..0d67c6e0420 100644
--- a/lib/maxmind/MaxMind/Db/Reader/Metadata.php
+++ b/lib/maxmind/MaxMind/Db/Reader/Metadata.php
@@ -5,31 +5,50 @@ namespace MaxMind\Db\Reader;
/**
* This class provides the metadata for the MaxMind DB file.
*
- * @property int nodeCount This is an unsigned 32-bit integer indicating
- * the number of nodes in the search tree.
- * @property int 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 int 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 int binaryFormatMajorVersion This is an unsigned 16-bit
- * integer indicating the major version number for the database's binary
- * format.
- * @property int binaryFormatMinorVersion This is an unsigned 16-bit
- * integer indicating the minor version number for the database's binary format.
- * @property int 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.
+ * @property int $nodeCount This is an unsigned 32-bit
+ * integer indicating the number of
+ * nodes in the search tree.
+ * @property int $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 int $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 int $binaryFormatMajorVersion This is an unsigned 16-bit
+ * integer indicating the major
+ * version number for the database's
+ * binary format.
+ * @property int $binaryFormatMinorVersion This is an unsigned 16-bit
+ * integer indicating the minor
+ * version number for the database's
+ * binary format.
+ * @property int $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
{
diff --git a/lib/maxmind/MaxMind/LICENSE b/lib/maxmind/MaxMind/LICENSE
new file mode 100644
index 00000000000..d6456956733
--- /dev/null
+++ b/lib/maxmind/MaxMind/LICENSE
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/lib/maxmind/MaxMind/README.md b/lib/maxmind/MaxMind/README.md
new file mode 100644
index 00000000000..d0600e871b1
--- /dev/null
+++ b/lib/maxmind/MaxMind/README.md
@@ -0,0 +1,178 @@
+# MaxMind DB Reader PHP API #
+
+## Description ##
+
+This is the PHP API for reading MaxMind DB files. MaxMind DB is a binary file
+format that stores data indexed by IP address subnets (IPv4 or IPv6).
+
+## Installation (Composer) ##
+
+We recommend installing this package with [Composer](https://getcomposer.org/).
+
+### Download Composer ###
+
+To download Composer, run in the root directory of your project:
+
+```bash
+curl -sS https://getcomposer.org/installer | php
+```
+
+You should now have the file `composer.phar` in your project directory.
+
+### Install Dependencies ###
+
+Run in your project root:
+
+```
+php composer.phar require maxmind-db/reader:~1.0
+```
+
+You should now have the files `composer.json` and `composer.lock` as well as
+the directory `vendor` in your project directory. If you use a version control
+system, `composer.json` should be added to it.
+
+### Require Autoloader ###
+
+After installing the dependencies, you need to require the Composer autoloader
+from your code:
+
+```php
+require 'vendor/autoload.php';
+```
+
+## Installation (Standalone) ##
+
+If you don't want to use Composer for some reason, a custom
+`autoload.php` is provided for you in the project root. To use the
+library, simply include that file,
+
+```php
+require('/path/to/MaxMind-DB-Reader-php/autoload.php');
+```
+
+and then instantiate the reader class normally:
+
+```php
+use MaxMind\Db\Reader;
+$reader = new Reader('example.mmdb');
+```
+
+## Installation (RPM)
+
+RPMs are available in the [official Fedora repository](https://apps.fedoraproject.org/packages/php-maxminddb).
+
+To install on Fedora, run:
+
+```bash
+dnf install php-maxminddb
+```
+
+To install on CentOS or RHEL 7, first [enable the EPEL repository](https://fedoraproject.org/wiki/EPEL)
+and then run:
+
+```bash
+yum install php-maxminddb
+```
+
+Please note that these packages are *not* maintained by MaxMind.
+
+## Usage ##
+
+## Example ##
+
+```php
+get($ipAddress));
+
+// getWithPrefixLen returns an array containing the record and the
+// associated prefix length for that record.
+print_r($reader->getWithPrefixLen($ipAddress));
+
+$reader->close();
+```
+
+## Optional PHP C Extension ##
+
+MaxMind provides an optional C extension that is a drop-in replacement for
+`MaxMind\Db\Reader`. In order to use this extension, you must install the
+Reader API as described above and install the extension as described below. If
+you are using an autoloader, no changes to your code should be necessary.
+
+### Installing Extension ###
+
+First install [libmaxminddb](https://github.com/maxmind/libmaxminddb) as
+described in its [README.md
+file](https://github.com/maxmind/libmaxminddb/blob/master/README.md#installing-from-a-tarball).
+After successfully installing libmaxmindb, run the following commands from the
+top-level directory of this distribution:
+
+```
+cd ext
+phpize
+./configure
+make
+make test
+sudo make install
+```
+
+You then must load your extension. The recommend method is to add the
+following to your `php.ini` file:
+
+```
+extension=maxminddb.so
+```
+
+Note: You may need to install the PHP development package on your OS such as
+php5-dev for Debian-based systems or php-devel for RedHat/Fedora-based ones.
+
+## 128-bit Integer Support ##
+
+The MaxMind DB format includes 128-bit unsigned integer as a type. Although
+no MaxMind-distributed database currently makes use of this type, both the
+pure PHP reader and the C extension support this type. The pure PHP reader
+requires gmp or bcmath to read databases with 128-bit unsigned integers.
+
+The integer is currently returned as a hexadecimal string (prefixed with "0x")
+by the C extension and a decimal string (no prefix) by the pure PHP reader.
+Any change to make the reader implementations always return either a
+hexadecimal or decimal representation of the integer will NOT be considered a
+breaking change.
+
+## Support ##
+
+Please report all issues with this code using the [GitHub issue tracker](https://github.com/maxmind/MaxMind-DB-Reader-php/issues).
+
+If you are having an issue with a MaxMind service that is not specific to the
+client API, please see [our support page](https://www.maxmind.com/en/support).
+
+## Requirements ##
+
+This library requires PHP 5.6 or greater.
+
+The GMP or BCMath extension may be required to read some databases
+using the pure PHP API.
+
+## Contributing ##
+
+Patches and pull requests are encouraged. All code should follow the PSR-1 and
+PSR-2 style guidelines. Please include unit tests whenever possible.
+
+## Versioning ##
+
+The MaxMind DB Reader PHP API uses [Semantic Versioning](https://semver.org/).
+
+## Copyright and License ##
+
+This software is Copyright (c) 2014-2019 by MaxMind, Inc.
+
+This is free software, licensed under the Apache License, Version 2.0.
diff --git a/lib/maxmind/MaxMind/autoload.php b/lib/maxmind/MaxMind/autoload.php
new file mode 100644
index 00000000000..1314b698e64
--- /dev/null
+++ b/lib/maxmind/MaxMind/autoload.php
@@ -0,0 +1,45 @@
+class.
+ *
+ * @param string $class
+ * the name of the class to load
+ */
+function mmdb_autoload($class)
+{
+ /*
+ * A project-specific mapping between the namespaces and where
+ * they're located. By convention, we include the trailing
+ * slashes. The one-element array here simply makes things easy
+ * to extend in the future if (for example) the test classes
+ * begin to use one another.
+ */
+ $namespace_map = ['MaxMind\\Db\\' => __DIR__ . '/src/MaxMind/Db/'];
+
+ foreach ($namespace_map as $prefix => $dir) {
+ /* First swap out the namespace prefix with a directory... */
+ $path = str_replace($prefix, $dir, $class);
+
+ /* replace the namespace separator with a directory separator... */
+ $path = str_replace('\\', '/', $path);
+
+ /* and finally, add the PHP file extension to the result. */
+ $path = $path . '.php';
+
+ /* $path should now contain the path to a PHP file defining $class */
+ if (file_exists($path)) {
+ include $path;
+ }
+ }
+}
+
+spl_autoload_register('mmdb_autoload');
diff --git a/lib/maxmind/MaxMind/composer.json b/lib/maxmind/MaxMind/composer.json
new file mode 100644
index 00000000000..4ddcc362d96
--- /dev/null
+++ b/lib/maxmind/MaxMind/composer.json
@@ -0,0 +1,40 @@
+{
+ "name": "maxmind-db/reader",
+ "description": "MaxMind DB Reader API",
+ "keywords": ["database", "geoip", "geoip2", "geolocation", "maxmind"],
+ "homepage": "https://github.com/maxmind/MaxMind-DB-Reader-php",
+ "type": "library",
+ "license": "Apache-2.0",
+ "authors": [
+ {
+ "name": "Gregory J. Oschwald",
+ "email": "goschwald@maxmind.com",
+ "homepage": "https://www.maxmind.com/"
+ }
+ ],
+ "require": {
+ "php": ">=5.6"
+ },
+ "suggest": {
+ "ext-bcmath": "bcmath or gmp is required for decoding larger integers with the pure PHP decoder",
+ "ext-gmp": "bcmath or gmp is required for decoding larger integers with the pure PHP decoder",
+ "ext-maxminddb": "A C-based database decoder that provides significantly faster lookups"
+ },
+ "require-dev": {
+ "friendsofphp/php-cs-fixer": "2.*",
+ "phpunit/phpunit": "5.*",
+ "php-coveralls/php-coveralls": "^2.1",
+ "phpunit/phpcov": "^3.0",
+ "squizlabs/php_codesniffer": "3.*"
+ },
+ "autoload": {
+ "psr-4": {
+ "MaxMind\\Db\\": "src/MaxMind/Db"
+ }
+ },
+ "autoload-dev": {
+ "psr-4": {
+ "MaxMind\\Db\\Test\\Reader\\": "tests/MaxMind/Db/Test/Reader"
+ }
+ }
+}
diff --git a/lib/maxmind/readme_moodle.txt b/lib/maxmind/readme_moodle.txt
index 8b90c90685a..50e1c11242b 100644
--- a/lib/maxmind/readme_moodle.txt
+++ b/lib/maxmind/readme_moodle.txt
@@ -16,15 +16,15 @@ Installation
------------
1) Download the latest versions of GeoIP2-php and MaxMind-DB-Reader-php
-wget https://github.com/maxmind/GeoIP2-php/archive/v2.9.0.zip
-wget https://github.com/maxmind/MaxMind-DB-Reader-php/archive/v1.4.1.zip
+wget https://github.com/maxmind/GeoIP2-php/archive/v2.10.0.zip
+wget https://github.com/maxmind/MaxMind-DB-Reader-php/archive/v1.5.1.zip
2) Unzip the archives
-unzip v2.9.0.zip
-unzip v1.4.1.zip
+unzip v2.10.0.zip
+unzip v1.5.1.zip
3) Move the source code directories into place
-mv GeoIP2-php-2.9.0/src/ /path/to/moodle/lib/maxmind/GeoIp2/
-mv MaxMind-DB-Reader-php-1.4.1/src/MaxMind/ /path/to/moodle/lib/maxmind/MaxMind/
+mv GeoIP2-php-2.10.0/src/ /path/to/moodle/lib/maxmind/GeoIp2/
+mv MaxMind-DB-Reader-php-1.5.1/src/MaxMind/ /path/to/moodle/lib/maxmind/MaxMind/
4) Run unit tests on iplookup/tests/geoip_test.php with PHPUNIT_LONGTEST defined.
diff --git a/lib/thirdpartylibs.xml b/lib/thirdpartylibs.xml
index 99f775e2c1a..42d5545a32b 100644
--- a/lib/thirdpartylibs.xml
+++ b/lib/thirdpartylibs.xml
@@ -241,13 +241,13 @@