diff --git a/lib/maxmind/MaxMind/CHANGELOG.md b/lib/maxmind/MaxMind/CHANGELOG.md
new file mode 100644
index 00000000000..9ed49bd416d
--- /dev/null
+++ b/lib/maxmind/MaxMind/CHANGELOG.md
@@ -0,0 +1,167 @@
+CHANGELOG
+=========
+
+1.5.1 (2019-12-12)
+------------------
+
+* Minor performance improvements.
+* Make tests pass with older versions of libmaxminddb. PR by Remi
+ Collet. GitHub #90.
+* Test enhancements. PR by Chun-Sheng, Li. GitHub #91.
+
+1.5.0 (2019-09-30)
+------------------
+
+* PHP 5.6 or greater is now required.
+* The C extension now supports PHP 8. Pull request by John Boehr.
+ GitHub #87.
+* A new method, `getWithPrefixLen`, was added to the `Reader` class.
+ This method returns an array containing the record and the prefix
+ length for that record. GitHub #89.
+
+1.4.1 (2019-01-04)
+------------------
+
+* The `maxminddb` extension now returns a string when a `uint32`
+ value is greater than `LONG_MAX`. Previously, the value would
+ overflow. This generally only affects 32-bit machines. Reported
+ by Remi Collet. GitHub #79.
+* For `uint64` values, the `maxminddb` extension now returns an
+ integer rather than a string when the value is less than or equal
+ to `LONG_MAX`. This more closely matches the behavior of the pure
+ PHP reader.
+
+1.4.0 (2018-11-20)
+------------------
+
+* The `maxminddb` extension now has the arginfo when using reflection.
+ PR by Remi Collet. GitHub #75.
+* The `maxminddb` extension now provides `MINFO()` function that
+ displays the extension version and the libmaxminddb version. PR by
+ Remi Collet. GitHub #74.
+* The `maxminddb` `configure` script now uses `pkg-config` when
+ available to get libmaxmindb build info. PR by Remi Collet.
+ GitHub #73.
+* The pure PHP reader now correctly decodes integers on 32-bit platforms.
+ Previously, large integers would overflow. Reported by Remi Collet.
+ GitHub #77.
+* There are small performance improvements for the pure PHP reader.
+
+1.3.0 (2018-02-21)
+------------------
+
+* IMPORTANT: The `maxminddb` extension now obeys `open_basedir`. If
+ `open_basedir` is set, you _must_ store the database within the
+ specified directory. Placing the file outside of this directory
+ will result in an exception. Please test your integration before
+ upgrading the extension. This does not affect the pure PHP
+ implementation, which has always had this restriction. Reported
+ by BenoƮt Burnichon. GitHub #61.
+* A custom `autoload.php` file is provided for installations without
+ Composer. GitHub #56.
+
+1.2.0 (2017-10-27)
+------------------
+
+* PHP 5.4 or greater is now required.
+* The `Reader` class for the `maxminddb` extension is no longer final.
+ This was change to match the behavior of the pure PHP class.
+ Reported and fixed by venyii. GitHub #52 & #54.
+
+1.1.3 (2017-01-19)
+------------------
+
+* Fix incorrect version in `ext/php_maxminddb.h`. GitHub #48.
+
+1.1.2 (2016-11-22)
+------------------
+
+* Searching for database metadata only occurs within the last 128KB
+ (128 * 1024 bytes) of the file, speeding detection of corrupt
+ datafiles. Reported by Eric Teubert. GitHub #42.
+* Suggest relevant extensions when installing with Composer. GitHub #37.
+
+1.1.1 (2016-09-15)
+------------------
+
+* Development files were added to the `.gitattributes` as `export-ignore` so
+ that they are not part of the Composer release. Pull request by Michele
+ Locati. GitHub #39.
+
+1.1.0 (2016-01-04)
+------------------
+
+* The MaxMind DB extension now supports PHP 7. Pull request by John Boehr.
+ GitHub #27.
+
+1.0.3 (2015-03-13)
+------------------
+
+* All uses of `strlen` were removed. This should prevent issues in situations
+ where the function is overloaded or otherwise broken.
+
+1.0.2 (2015-01-19)
+------------------
+
+* Previously the MaxMind DB extension would cause a segfault if the Reader
+ object's destructor was called without first having called the constructor.
+ (Reported by Matthias Saou & Juan Peri. GitHub #20.)
+
+1.0.1 (2015-01-12)
+------------------
+
+* In the last several releases, the version number in the extension was
+ incorrect. This release is being done to correct it. No other code changes
+ are included.
+
+1.0.0 (2014-09-22)
+------------------
+
+* First production release.
+* In the pure PHP reader, a string length test after `fread()` was replaced
+ with the difference between the start pointer and the end pointer. This
+ provided a 15% speed increase.
+
+0.3.3 (2014-09-15)
+------------------
+
+* Clarified behavior of 128-bit type in documentation.
+* Updated phpunit and fixed some test breakage from the newer version.
+
+0.3.2 (2014-09-10)
+------------------
+
+* Fixed invalid reference to global class RuntimeException from namespaced
+ code. Fixed by Steven Don. GitHub issue #15.
+* Additional documentation of `Metadata` class as well as misc. documentation
+ cleanup.
+
+0.3.1 (2014-05-01)
+------------------
+
+* The API now works when `mbstring.func_overload` is set.
+* BCMath is no longer required. If the decoder encounters a big integer,
+ it will try to use GMP and then BCMath. If both of those fail, it will
+ throw an exception. No databases released by MaxMind currently use big
+ integers.
+* The API now officially supports HHVM when using the pure PHP reader.
+
+0.3.0 (2014-02-19)
+------------------
+
+* This API is now licensed under the Apache License, Version 2.0.
+* The code for the C extension was cleaned up, fixing several potential
+ issues.
+
+0.2.0 (2013-10-21)
+------------------
+
+* Added optional C extension for using libmaxminddb in place of the pure PHP
+ reader.
+* Significantly improved error handling in pure PHP reader.
+* Improved performance for IPv4 lookups in an IPv6 database.
+
+0.1.0 (2013-07-16)
+------------------
+
+* Initial release
diff --git a/lib/maxmind/MaxMind/Db/Reader.php b/lib/maxmind/MaxMind/Db/Reader.php
index 745f7bb3ae0..3d5a8291d95 100644
--- a/lib/maxmind/MaxMind/Db/Reader.php
+++ b/lib/maxmind/MaxMind/Db/Reader.php
@@ -2,14 +2,18 @@
namespace MaxMind\Db;
+use BadMethodCallException;
+use Exception;
+use InvalidArgumentException;
use MaxMind\Db\Reader\Decoder;
use MaxMind\Db\Reader\InvalidDatabaseException;
use MaxMind\Db\Reader\Metadata;
use MaxMind\Db\Reader\Util;
+use UnexpectedValueException;
/**
* Instances of this class provide a reader for the MaxMind DB format. IP
- * addresses can be looked up using the 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"
+ }
+ }
+}