aboutsummaryrefslogtreecommitdiff
path: root/includes/vendor/maxmind-db
diff options
context:
space:
mode:
Diffstat (limited to 'includes/vendor/maxmind-db')
-rw-r--r--includes/vendor/maxmind-db/reader/README.md156
-rw-r--r--includes/vendor/maxmind-db/reader/src/MaxMind/Db/Reader.php309
-rw-r--r--includes/vendor/maxmind-db/reader/src/MaxMind/Db/Reader/Decoder.php341
-rw-r--r--includes/vendor/maxmind-db/reader/src/MaxMind/Db/Reader/InvalidDatabaseException.php10
-rw-r--r--includes/vendor/maxmind-db/reader/src/MaxMind/Db/Reader/Metadata.php69
-rw-r--r--includes/vendor/maxmind-db/reader/src/MaxMind/Db/Reader/Util.php26
6 files changed, 911 insertions, 0 deletions
diff --git a/includes/vendor/maxmind-db/reader/README.md b/includes/vendor/maxmind-db/reader/README.md
new file mode 100644
index 0000000..4da03cf
--- /dev/null
+++ b/includes/vendor/maxmind-db/reader/README.md
@@ -0,0 +1,156 @@
+# 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](http://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');
+```
+
+## Usage ##
+
+## Example ##
+
+```php
+<?php
+require_once 'vendor/autoload.php';
+
+use MaxMind\Db\Reader;
+
+$ipAddress = '24.24.24.24';
+$databaseFile = 'GeoIP2-City.mmdb';
+
+$reader = new Reader($databaseFile);
+
+print_r($reader->get($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](http://www.maxmind.com/en/support).
+
+## Requirements ##
+
+This library requires PHP 5.4 or greater. The pure PHP reader included is
+compatible with HHVM.
+
+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](http://semver.org/).
+
+## Copyright and License ##
+
+This software is Copyright (c) 2014-2018 by MaxMind, Inc.
+
+This is free software, licensed under the Apache License, Version 2.0.
diff --git a/includes/vendor/maxmind-db/reader/src/MaxMind/Db/Reader.php b/includes/vendor/maxmind-db/reader/src/MaxMind/Db/Reader.php
new file mode 100644
index 0000000..745f7bb
--- /dev/null
+++ b/includes/vendor/maxmind-db/reader/src/MaxMind/Db/Reader.php
@@ -0,0 +1,309 @@
+<?php
+
+namespace MaxMind\Db;
+
+use MaxMind\Db\Reader\Decoder;
+use MaxMind\Db\Reader\InvalidDatabaseException;
+use MaxMind\Db\Reader\Metadata;
+use MaxMind\Db\Reader\Util;
+
+/**
+ * Instances of this class provide a reader for the MaxMind DB format. IP
+ * addresses can be looked up using the <code>get</code> method.
+ */
+class Reader
+{
+ private static $DATA_SECTION_SEPARATOR_SIZE = 16;
+ private static $METADATA_START_MARKER = "\xAB\xCD\xEFMaxMind.com";
+ private static $METADATA_START_MARKER_LENGTH = 14;
+ private static $METADATA_MAX_SIZE = 131072; // 128 * 1024 = 128KB
+
+ private $decoder;
+ private $fileHandle;
+ private $fileSize;
+ private $ipV4Start;
+ private $metadata;
+
+ /**
+ * Constructs a Reader for the MaxMind DB format. The file passed to it must
+ * be a valid MaxMind DB file such as a GeoIp2 database file.
+ *
+ * @param string $database
+ * the MaxMind DB file to use
+ *
+ * @throws \InvalidArgumentException for invalid database path or unknown arguments
+ * @throws \MaxMind\Db\Reader\InvalidDatabaseException
+ * if the database is invalid or there is an error reading
+ * from it
+ */
+ public function __construct($database)
+ {
+ if (\func_num_args() !== 1) {
+ throw new \InvalidArgumentException(
+ 'The constructor takes exactly one argument.'
+ );
+ }
+
+ if (!is_readable($database)) {
+ throw new \InvalidArgumentException(
+ "The file \"$database\" does not exist or is not readable."
+ );
+ }
+ $this->fileHandle = @fopen($database, 'rb');
+ if ($this->fileHandle === false) {
+ throw new \InvalidArgumentException(
+ "Error opening \"$database\"."
+ );
+ }
+ $this->fileSize = @filesize($database);
+ if ($this->fileSize === false) {
+ throw new \UnexpectedValueException(
+ "Error determining the size of \"$database\"."
+ );
+ }
+
+ $start = $this->findMetadataStart($database);
+ $metadataDecoder = new Decoder($this->fileHandle, $start);
+ list($metadataArray) = $metadataDecoder->decode($start);
+ $this->metadata = new Metadata($metadataArray);
+ $this->decoder = new Decoder(
+ $this->fileHandle,
+ $this->metadata->searchTreeSize + self::$DATA_SECTION_SEPARATOR_SIZE
+ );
+ }
+
+ /**
+ * Looks up the <code>address</code> in the MaxMind DB.
+ *
+ * @param string $ipAddress
+ * the IP address to look up
+ *
+ * @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 the record for the IP address
+ */
+ public function get($ipAddress)
+ {
+ if (\func_num_args() !== 1) {
+ throw new \InvalidArgumentException(
+ 'Method takes exactly one argument.'
+ );
+ }
+
+ if (!\is_resource($this->fileHandle)) {
+ throw new \BadMethodCallException(
+ 'Attempt to read from a closed MaxMind DB.'
+ );
+ }
+
+ if (!filter_var($ipAddress, FILTER_VALIDATE_IP)) {
+ throw new \InvalidArgumentException(
+ "The value \"$ipAddress\" is not a valid IP address."
+ );
+ }
+
+ if ($this->metadata->ipVersion === 4 && strrpos($ipAddress, ':')) {
+ throw new \InvalidArgumentException(
+ "Error looking up $ipAddress. You attempted to look up an"
+ . ' IPv6 address in an IPv4-only database.'
+ );
+ }
+ $pointer = $this->findAddressInTree($ipAddress);
+ if ($pointer === 0) {
+ return null;
+ }
+
+ return $this->resolveDataPointer($pointer);
+ }
+
+ private function findAddressInTree($ipAddress)
+ {
+ // XXX - could simplify. Done as a byte array to ease porting
+ $rawAddress = array_merge(unpack('C*', inet_pton($ipAddress)));
+
+ $bitCount = \count($rawAddress) * 8;
+
+ // The first node of the tree is always node 0, at the beginning of the
+ // value
+ $node = $this->startNode($bitCount);
+
+ for ($i = 0; $i < $bitCount; ++$i) {
+ if ($node >= $this->metadata->nodeCount) {
+ break;
+ }
+ $tempBit = 0xFF & $rawAddress[$i >> 3];
+ $bit = 1 & ($tempBit >> 7 - ($i % 8));
+
+ $node = $this->readNode($node, $bit);
+ }
+ if ($node === $this->metadata->nodeCount) {
+ // Record is empty
+ return 0;
+ } elseif ($node > $this->metadata->nodeCount) {
+ // Record is a data pointer
+ return $node;
+ }
+ throw new InvalidDatabaseException('Something bad happened');
+ }
+
+ private function startNode($length)
+ {
+ // Check if we are looking up an IPv4 address in an IPv6 tree. If this
+ // is the case, we can skip over the first 96 nodes.
+ if ($this->metadata->ipVersion === 6 && $length === 32) {
+ return $this->ipV4StartNode();
+ }
+ // The first node of the tree is always node 0, at the beginning of the
+ // value
+ return 0;
+ }
+
+ private function ipV4StartNode()
+ {
+ // This is a defensive check. There is no reason to call this when you
+ // have an IPv4 tree.
+ if ($this->metadata->ipVersion === 4) {
+ return 0;
+ }
+
+ if ($this->ipV4Start) {
+ return $this->ipV4Start;
+ }
+ $node = 0;
+
+ for ($i = 0; $i < 96 && $node < $this->metadata->nodeCount; ++$i) {
+ $node = $this->readNode($node, 0);
+ }
+ $this->ipV4Start = $node;
+
+ return $node;
+ }
+
+ private function readNode($nodeNumber, $index)
+ {
+ $baseOffset = $nodeNumber * $this->metadata->nodeByteSize;
+
+ // XXX - probably could condense this.
+ switch ($this->metadata->recordSize) {
+ case 24:
+ $bytes = Util::read($this->fileHandle, $baseOffset + $index * 3, 3);
+ list(, $node) = unpack('N', "\x00" . $bytes);
+
+ return $node;
+ case 28:
+ $middleByte = Util::read($this->fileHandle, $baseOffset + 3, 1);
+ list(, $middle) = unpack('C', $middleByte);
+ if ($index === 0) {
+ $middle = (0xF0 & $middle) >> 4;
+ } else {
+ $middle = 0x0F & $middle;
+ }
+ $bytes = Util::read($this->fileHandle, $baseOffset + $index * 4, 3);
+ list(, $node) = unpack('N', \chr($middle) . $bytes);
+
+ return $node;
+ case 32:
+ $bytes = Util::read($this->fileHandle, $baseOffset + $index * 4, 4);
+ list(, $node) = unpack('N', $bytes);
+
+ return $node;
+ default:
+ throw new InvalidDatabaseException(
+ 'Unknown record size: '
+ . $this->metadata->recordSize
+ );
+ }
+ }
+
+ private function resolveDataPointer($pointer)
+ {
+ $resolved = $pointer - $this->metadata->nodeCount
+ + $this->metadata->searchTreeSize;
+ if ($resolved > $this->fileSize) {
+ throw new InvalidDatabaseException(
+ "The MaxMind DB file's search tree is corrupt"
+ );
+ }
+
+ list($data) = $this->decoder->decode($resolved);
+
+ return $data;
+ }
+
+ /*
+ * This is an extremely naive but reasonably readable implementation. There
+ * are much faster algorithms (e.g., Boyer-Moore) for this if speed is ever
+ * an issue, but I suspect it won't be.
+ */
+ private function findMetadataStart($filename)
+ {
+ $handle = $this->fileHandle;
+ $fstat = fstat($handle);
+ $fileSize = $fstat['size'];
+ $marker = self::$METADATA_START_MARKER;
+ $markerLength = self::$METADATA_START_MARKER_LENGTH;
+ $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;
+ }
+ }
+
+ return $fileSize - $i;
+ }
+ throw new InvalidDatabaseException(
+ "Error opening database file ($filename). " .
+ 'Is this a valid MaxMind DB file?'
+ );
+ }
+
+ /**
+ * @throws \InvalidArgumentException if arguments are passed to the method
+ * @throws \BadMethodCallException if the database has been closed
+ *
+ * @return Metadata object for the database
+ */
+ public function metadata()
+ {
+ if (\func_num_args()) {
+ throw new \InvalidArgumentException(
+ 'Method takes no arguments.'
+ );
+ }
+
+ // Not technically required, but this makes it consistent with
+ // C extension and it allows us to change our implementation later.
+ if (!\is_resource($this->fileHandle)) {
+ throw new \BadMethodCallException(
+ 'Attempt to read from a closed MaxMind DB.'
+ );
+ }
+
+ return $this->metadata;
+ }
+
+ /**
+ * Closes the MaxMind DB and returns resources to the system.
+ *
+ * @throws \Exception
+ * if an I/O error occurs
+ */
+ public function close()
+ {
+ if (!\is_resource($this->fileHandle)) {
+ throw new \BadMethodCallException(
+ 'Attempt to close a closed MaxMind DB.'
+ );
+ }
+ fclose($this->fileHandle);
+ }
+}
diff --git a/includes/vendor/maxmind-db/reader/src/MaxMind/Db/Reader/Decoder.php b/includes/vendor/maxmind-db/reader/src/MaxMind/Db/Reader/Decoder.php
new file mode 100644
index 0000000..a71b3de
--- /dev/null
+++ b/includes/vendor/maxmind-db/reader/src/MaxMind/Db/Reader/Decoder.php
@@ -0,0 +1,341 @@
+<?php
+
+namespace MaxMind\Db\Reader;
+
+// @codingStandardsIgnoreLine
+// 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
+{
+ private $fileStream;
+ private $pointerBase;
+ private $pointerBaseByteSize;
+ // This is only used for unit testing
+ private $pointerTestHack;
+ private $switchByteOrder;
+
+ const _EXTENDED = 0;
+ const _POINTER = 1;
+ const _UTF8_STRING = 2;
+ const _DOUBLE = 3;
+ const _BYTES = 4;
+ const _UINT16 = 5;
+ const _UINT32 = 6;
+ const _MAP = 7;
+ const _INT32 = 8;
+ const _UINT64 = 9;
+ const _UINT128 = 10;
+ const _ARRAY = 11;
+ const _CONTAINER = 12;
+ const _END_MARKER = 13;
+ const _BOOLEAN = 14;
+ const _FLOAT = 15;
+
+ public function __construct(
+ $fileStream,
+ $pointerBase = 0,
+ $pointerTestHack = false
+ ) {
+ $this->fileStream = $fileStream;
+ $this->pointerBase = $pointerBase;
+
+ $this->pointerBaseByteSize = $pointerBase > 0 ? log($pointerBase, 2) / 8 : 0;
+ $this->pointerTestHack = $pointerTestHack;
+
+ $this->switchByteOrder = $this->isPlatformLittleEndian();
+ }
+
+ public function decode($offset)
+ {
+ list(, $ctrlByte) = unpack(
+ 'C',
+ Util::read($this->fileStream, $offset, 1)
+ );
+ ++$offset;
+
+ $type = $ctrlByte >> 5;
+
+ // Pointers are a special case, we don't read the next $size bytes, we
+ // use the size to determine the length of the pointer and then follow
+ // it.
+ if ($type === self::_POINTER) {
+ list($pointer, $offset) = $this->decodePointer($ctrlByte, $offset);
+
+ // for unit testing
+ if ($this->pointerTestHack) {
+ return [$pointer];
+ }
+
+ list($result) = $this->decode($pointer);
+
+ return [$result, $offset];
+ }
+
+ if ($type === self::_EXTENDED) {
+ list(, $nextByte) = unpack(
+ 'C',
+ Util::read($this->fileStream, $offset, 1)
+ );
+
+ $type = $nextByte + 7;
+
+ if ($type < 8) {
+ throw new InvalidDatabaseException(
+ 'Something went horribly wrong in the decoder. An extended type '
+ . 'resolved to a type number < 8 ('
+ . $type
+ . ')'
+ );
+ }
+
+ ++$offset;
+ }
+
+ list($size, $offset) = $this->sizeFromCtrlByte($ctrlByte, $offset);
+
+ return $this->decodeByType($type, $offset, $size);
+ }
+
+ private function decodeByType($type, $offset, $size)
+ {
+ switch ($type) {
+ case self::_MAP:
+ return $this->decodeMap($size, $offset);
+ case self::_ARRAY:
+ return $this->decodeArray($size, $offset);
+ case self::_BOOLEAN:
+ return [$this->decodeBoolean($size), $offset];
+ }
+
+ $newOffset = $offset + $size;
+ $bytes = Util::read($this->fileStream, $offset, $size);
+ switch ($type) {
+ case self::_BYTES:
+ case self::_UTF8_STRING:
+ return [$bytes, $newOffset];
+ case self::_DOUBLE:
+ $this->verifySize(8, $size);
+
+ return [$this->decodeDouble($bytes), $newOffset];
+ case self::_FLOAT:
+ $this->verifySize(4, $size);
+
+ return [$this->decodeFloat($bytes), $newOffset];
+ case self::_INT32:
+ return [$this->decodeInt32($bytes, $size), $newOffset];
+ case self::_UINT16:
+ case self::_UINT32:
+ case self::_UINT64:
+ case self::_UINT128:
+ return [$this->decodeUint($bytes, $size), $newOffset];
+ default:
+ throw new InvalidDatabaseException(
+ 'Unknown or unexpected type: ' . $type
+ );
+ }
+ }
+
+ private function verifySize($expected, $actual)
+ {
+ if ($expected !== $actual) {
+ throw new InvalidDatabaseException(
+ "The MaxMind DB file's data section contains bad data (unknown data type or corrupt data)"
+ );
+ }
+ }
+
+ private function decodeArray($size, $offset)
+ {
+ $array = [];
+
+ for ($i = 0; $i < $size; ++$i) {
+ list($value, $offset) = $this->decode($offset);
+ array_push($array, $value);
+ }
+
+ return [$array, $offset];
+ }
+
+ private function decodeBoolean($size)
+ {
+ return $size === 0 ? false : true;
+ }
+
+ private function decodeDouble($bits)
+ {
+ // This assumes IEEE 754 doubles, but most (all?) modern platforms
+ // use them.
+ //
+ // We are not using the "E" format as that was only added in
+ // 7.0.15 and 7.1.1. As such, we must switch byte order on
+ // little endian machines.
+ list(, $double) = unpack('d', $this->maybeSwitchByteOrder($bits));
+
+ return $double;
+ }
+
+ private function decodeFloat($bits)
+ {
+ // This assumes IEEE 754 floats, but most (all?) modern platforms
+ // use them.
+ //
+ // We are not using the "G" format as that was only added in
+ // 7.0.15 and 7.1.1. As such, we must switch byte order on
+ // little endian machines.
+ list(, $float) = unpack('f', $this->maybeSwitchByteOrder($bits));
+
+ return $float;
+ }
+
+ private function decodeInt32($bytes, $size)
+ {
+ switch ($size) {
+ case 0:
+ return 0;
+ case 1:
+ case 2:
+ case 3:
+ $bytes = str_pad($bytes, 4, "\x00", STR_PAD_LEFT);
+ break;
+ case 4:
+ break;
+ default:
+ throw new InvalidDatabaseException(
+ "The MaxMind DB file's data section contains bad data (unknown data type or corrupt data)"
+ );
+ }
+
+ list(, $int) = unpack('l', $this->maybeSwitchByteOrder($bytes));
+
+ return $int;
+ }
+
+ private function decodeMap($size, $offset)
+ {
+ $map = [];
+
+ for ($i = 0; $i < $size; ++$i) {
+ list($key, $offset) = $this->decode($offset);
+ list($value, $offset) = $this->decode($offset);
+ $map[$key] = $value;
+ }
+
+ return [$map, $offset];
+ }
+
+ private function decodePointer($ctrlByte, $offset)
+ {
+ $pointerSize = (($ctrlByte >> 3) & 0x3) + 1;
+
+ $buffer = Util::read($this->fileStream, $offset, $pointerSize);
+ $offset = $offset + $pointerSize;
+
+ switch ($pointerSize) {
+ case 1:
+ $packed = (pack('C', $ctrlByte & 0x7)) . $buffer;
+ list(, $pointer) = unpack('n', $packed);
+ $pointer += $this->pointerBase;
+ break;
+ case 2:
+ $packed = "\x00" . (pack('C', $ctrlByte & 0x7)) . $buffer;
+ list(, $pointer) = unpack('N', $packed);
+ $pointer += $this->pointerBase + 2048;
+ break;
+ case 3:
+ $packed = (pack('C', $ctrlByte & 0x7)) . $buffer;
+
+ // It is safe to use 'N' here, even on 32 bit machines as the
+ // first bit is 0.
+ list(, $pointer) = unpack('N', $packed);
+ $pointer += $this->pointerBase + 526336;
+ break;
+ case 4:
+ // We cannot use unpack here as we might overflow on 32 bit
+ // machines
+ $pointerOffset = $this->decodeUint($buffer, $pointerSize);
+
+ $byteLength = $pointerSize + $this->pointerBaseByteSize;
+
+ if ($byteLength <= _MM_MAX_INT_BYTES) {
+ $pointer = $pointerOffset + $this->pointerBase;
+ } elseif (\extension_loaded('gmp')) {
+ $pointer = gmp_strval(gmp_add($pointerOffset, $this->pointerBase));
+ } elseif (\extension_loaded('bcmath')) {
+ $pointer = bcadd($pointerOffset, $this->pointerBase);
+ } else {
+ throw new \RuntimeException(
+ 'The gmp or bcmath extension must be installed to read this database.'
+ );
+ }
+ }
+
+ return [$pointer, $offset];
+ }
+
+ private function decodeUint($bytes, $byteLength)
+ {
+ if ($byteLength === 0) {
+ return 0;
+ }
+
+ $integer = 0;
+
+ for ($i = 0; $i < $byteLength; ++$i) {
+ $part = \ord($bytes[$i]);
+
+ // We only use gmp or bcmath if the final value is too big
+ if ($byteLength <= _MM_MAX_INT_BYTES) {
+ $integer = ($integer << 8) + $part;
+ } elseif (\extension_loaded('gmp')) {
+ $integer = gmp_strval(gmp_add(gmp_mul($integer, 256), $part));
+ } elseif (\extension_loaded('bcmath')) {
+ $integer = bcadd(bcmul($integer, 256), $part);
+ } else {
+ throw new \RuntimeException(
+ 'The gmp or bcmath extension must be installed to read this database.'
+ );
+ }
+ }
+
+ return $integer;
+ }
+
+ private function sizeFromCtrlByte($ctrlByte, $offset)
+ {
+ $size = $ctrlByte & 0x1f;
+
+ if ($size < 29) {
+ return [$size, $offset];
+ }
+
+ $bytesToRead = $size - 28;
+ $bytes = Util::read($this->fileStream, $offset, $bytesToRead);
+
+ if ($size === 29) {
+ $size = 29 + \ord($bytes);
+ } elseif ($size === 30) {
+ list(, $adjust) = unpack('n', $bytes);
+ $size = 285 + $adjust;
+ } elseif ($size > 30) {
+ list(, $adjust) = unpack('N', "\x00" . $bytes);
+ $size = ($adjust & (0x0FFFFFFF >> (32 - (8 * $bytesToRead))))
+ + 65821;
+ }
+
+ return [$size, $offset + $bytesToRead];
+ }
+
+ private function maybeSwitchByteOrder($bytes)
+ {
+ return $this->switchByteOrder ? strrev($bytes) : $bytes;
+ }
+
+ private function isPlatformLittleEndian()
+ {
+ $testint = 0x00FF;
+ $packed = pack('S', $testint);
+
+ return $testint === current(unpack('v', $packed));
+ }
+}
diff --git a/includes/vendor/maxmind-db/reader/src/MaxMind/Db/Reader/InvalidDatabaseException.php b/includes/vendor/maxmind-db/reader/src/MaxMind/Db/Reader/InvalidDatabaseException.php
new file mode 100644
index 0000000..d2a9a77
--- /dev/null
+++ b/includes/vendor/maxmind-db/reader/src/MaxMind/Db/Reader/InvalidDatabaseException.php
@@ -0,0 +1,10 @@
+<?php
+
+namespace MaxMind\Db\Reader;
+
+/**
+ * This class should be thrown when unexpected data is found in the database.
+ */
+class InvalidDatabaseException extends \Exception
+{
+}
diff --git a/includes/vendor/maxmind-db/reader/src/MaxMind/Db/Reader/Metadata.php b/includes/vendor/maxmind-db/reader/src/MaxMind/Db/Reader/Metadata.php
new file mode 100644
index 0000000..4efdd3d
--- /dev/null
+++ b/includes/vendor/maxmind-db/reader/src/MaxMind/Db/Reader/Metadata.php
@@ -0,0 +1,69 @@
+<?php
+
+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.
+ */
+class Metadata
+{
+ private $binaryFormatMajorVersion;
+ private $binaryFormatMinorVersion;
+ private $buildEpoch;
+ private $databaseType;
+ private $description;
+ private $ipVersion;
+ private $languages;
+ private $nodeByteSize;
+ private $nodeCount;
+ private $recordSize;
+ private $searchTreeSize;
+
+ public function __construct($metadata)
+ {
+ $this->binaryFormatMajorVersion =
+ $metadata['binary_format_major_version'];
+ $this->binaryFormatMinorVersion =
+ $metadata['binary_format_minor_version'];
+ $this->buildEpoch = $metadata['build_epoch'];
+ $this->databaseType = $metadata['database_type'];
+ $this->languages = $metadata['languages'];
+ $this->description = $metadata['description'];
+ $this->ipVersion = $metadata['ip_version'];
+ $this->nodeCount = $metadata['node_count'];
+ $this->recordSize = $metadata['record_size'];
+ $this->nodeByteSize = $this->recordSize / 4;
+ $this->searchTreeSize = $this->nodeCount * $this->nodeByteSize;
+ }
+
+ public function __get($var)
+ {
+ return $this->$var;
+ }
+}
diff --git a/includes/vendor/maxmind-db/reader/src/MaxMind/Db/Reader/Util.php b/includes/vendor/maxmind-db/reader/src/MaxMind/Db/Reader/Util.php
new file mode 100644
index 0000000..87ebbf1
--- /dev/null
+++ b/includes/vendor/maxmind-db/reader/src/MaxMind/Db/Reader/Util.php
@@ -0,0 +1,26 @@
+<?php
+
+namespace MaxMind\Db\Reader;
+
+class Util
+{
+ public static function read($stream, $offset, $numberOfBytes)
+ {
+ if ($numberOfBytes === 0) {
+ return '';
+ }
+ if (fseek($stream, $offset) === 0) {
+ $value = fread($stream, $numberOfBytes);
+
+ // We check that the number of bytes read is equal to the number
+ // asked for. We use ftell as getting the length of $value is
+ // much slower.
+ if (ftell($stream) - $offset === $numberOfBytes) {
+ return $value;
+ }
+ }
+ throw new InvalidDatabaseException(
+ 'The MaxMind DB file contains bad data'
+ );
+ }
+}