aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Cleberg <hello@cleberg.net>2023-05-24 21:18:39 -0500
committerChristian Cleberg <hello@cleberg.net>2023-05-24 21:18:39 -0500
commitb3286eb015079950554508e0724fd5f12c71833f (patch)
tree8ac93accb2465c0b3dc34e78686beeac879eaf68
parent864f1349e47f924bcde20c1cc83d838b5c5c7316 (diff)
downloadifconfig.php-b3286eb015079950554508e0724fd5f12c71833f.tar.gz
ifconfig.php-b3286eb015079950554508e0724fd5f12c71833f.tar.bz2
ifconfig.php-b3286eb015079950554508e0724fd5f12c71833f.zip
add geolocation functionality
-rw-r--r--GeoLite2-City.mmdbbin0 -> 57411507 bytes
-rw-r--r--README.md26
-rw-r--r--composer.json5
-rw-r--r--composer.lock84
-rw-r--r--ifconfig.php56
-rw-r--r--vendor/autoload.php25
-rw-r--r--vendor/composer/ClassLoader.php585
-rw-r--r--vendor/composer/InstalledVersions.php359
-rw-r--r--vendor/composer/LICENSE19
-rw-r--r--vendor/composer/autoload_classmap.php10
-rw-r--r--vendor/composer/autoload_namespaces.php9
-rw-r--r--vendor/composer/autoload_psr4.php10
-rw-r--r--vendor/composer/autoload_real.php38
-rw-r--r--vendor/composer/autoload_static.php36
-rw-r--r--vendor/composer/installed.json74
-rw-r--r--vendor/composer/installed.php32
-rw-r--r--vendor/composer/platform_check.php26
-rw-r--r--vendor/maxmind-db/reader/CHANGELOG.md230
-rw-r--r--vendor/maxmind-db/reader/LICENSE202
-rw-r--r--vendor/maxmind-db/reader/README.md185
-rw-r--r--vendor/maxmind-db/reader/autoload.php47
-rw-r--r--vendor/maxmind-db/reader/composer.json44
-rw-r--r--vendor/maxmind-db/reader/ext/config.m440
-rw-r--r--vendor/maxmind-db/reader/ext/config.w3210
-rw-r--r--vendor/maxmind-db/reader/ext/maxminddb.c811
-rw-r--r--vendor/maxmind-db/reader/ext/php_maxminddb.h24
-rw-r--r--vendor/maxmind-db/reader/ext/tests/001-load.phpt12
-rw-r--r--vendor/maxmind-db/reader/ext/tests/002-final.phpt13
-rw-r--r--vendor/maxmind-db/reader/ext/tests/003-open-basedir.phpt12
-rw-r--r--vendor/maxmind-db/reader/package.xml63
-rw-r--r--vendor/maxmind-db/reader/src/MaxMind/Db/Reader.php373
-rw-r--r--vendor/maxmind-db/reader/src/MaxMind/Db/Reader/Decoder.php374
-rw-r--r--vendor/maxmind-db/reader/src/MaxMind/Db/Reader/InvalidDatabaseException.php14
-rw-r--r--vendor/maxmind-db/reader/src/MaxMind/Db/Reader/Metadata.php112
-rw-r--r--vendor/maxmind-db/reader/src/MaxMind/Db/Reader/Util.php32
35 files changed, 3973 insertions, 19 deletions
diff --git a/GeoLite2-City.mmdb b/GeoLite2-City.mmdb
new file mode 100644
index 0000000..2028238
--- /dev/null
+++ b/GeoLite2-City.mmdb
Binary files differ
diff --git a/README.md b/README.md
index 39f6c48..e1231b3 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,4 @@
-ifconfig.php
-============
+# ifconfig.php
**Simple PHP script to show IP address, UserAgent and other info**
@@ -27,3 +26,26 @@ With this code in the .htaccess file there is no need to type out the full URL,
Instead, you can just open 'ifconfig/xml' to get XML output or 'ifconfig/ua' to determine useragent.
Run `curl -L -X GET https://ip.cleberg.net/\?q\=text` in Linux terminal to get some info.
+
+## Development
+
+First, install PHP and Composer. For Fedora, run:
+
+```bash
+sudo dnf install php-cli composer
+```
+
+If applicable, install or update the maxmind-db dependency:
+
+```bash
+composer require maxmind-db/reader:~1.0
+
+# to update, run:
+composer update
+```
+
+Next, you can launch a dev server to test any of your changes:
+
+```bash
+sudo php --server localhost:8080 --docroot .
+```
diff --git a/composer.json b/composer.json
new file mode 100644
index 0000000..c387eef
--- /dev/null
+++ b/composer.json
@@ -0,0 +1,5 @@
+{
+ "require": {
+ "maxmind-db/reader": "~1.0"
+ }
+}
diff --git a/composer.lock b/composer.lock
new file mode 100644
index 0000000..3e3efcf
--- /dev/null
+++ b/composer.lock
@@ -0,0 +1,84 @@
+{
+ "_readme": [
+ "This file locks the dependencies of your project to a known state",
+ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
+ "This file is @generated automatically"
+ ],
+ "content-hash": "ccf38c391dd2003a7c8899a77fd6b1f4",
+ "packages": [
+ {
+ "name": "maxmind-db/reader",
+ "version": "v1.11.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/maxmind/MaxMind-DB-Reader-php.git",
+ "reference": "b1f3c0699525336d09cc5161a2861268d9f2ae5b"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/maxmind/MaxMind-DB-Reader-php/zipball/b1f3c0699525336d09cc5161a2861268d9f2ae5b",
+ "reference": "b1f3c0699525336d09cc5161a2861268d9f2ae5b",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.2"
+ },
+ "conflict": {
+ "ext-maxminddb": "<1.10.1,>=2.0.0"
+ },
+ "require-dev": {
+ "friendsofphp/php-cs-fixer": "3.*",
+ "php-coveralls/php-coveralls": "^2.1",
+ "phpstan/phpstan": "*",
+ "phpunit/phpcov": ">=6.0.0",
+ "phpunit/phpunit": ">=8.0.0,<10.0.0",
+ "squizlabs/php_codesniffer": "3.*"
+ },
+ "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"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "MaxMind\\Db\\": "src/MaxMind/Db"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "Apache-2.0"
+ ],
+ "authors": [
+ {
+ "name": "Gregory J. Oschwald",
+ "email": "goschwald@maxmind.com",
+ "homepage": "https://www.maxmind.com/"
+ }
+ ],
+ "description": "MaxMind DB Reader API",
+ "homepage": "https://github.com/maxmind/MaxMind-DB-Reader-php",
+ "keywords": [
+ "database",
+ "geoip",
+ "geoip2",
+ "geolocation",
+ "maxmind"
+ ],
+ "support": {
+ "issues": "https://github.com/maxmind/MaxMind-DB-Reader-php/issues",
+ "source": "https://github.com/maxmind/MaxMind-DB-Reader-php/tree/v1.11.0"
+ },
+ "time": "2021-10-18T15:23:10+00:00"
+ }
+ ],
+ "packages-dev": [],
+ "aliases": [],
+ "minimum-stability": "stable",
+ "stability-flags": [],
+ "prefer-stable": false,
+ "prefer-lowest": false,
+ "platform": [],
+ "platform-dev": [],
+ "plugin-api-version": "2.3.0"
+}
diff --git a/ifconfig.php b/ifconfig.php
index 8ece6ba..fc4dd30 100644
--- a/ifconfig.php
+++ b/ifconfig.php
@@ -1,28 +1,50 @@
<?php
+require 'vendor/autoload.php';
+use MaxMind\Db\Reader;
+
+function loadGeo(string $ipAddress): ?array
+{
+ $databaseFile = 'GeoLite2-City.mmdb';
+ $reader = new Reader($databaseFile);
+ $results = $reader->get($ipAddress);
+ $reader->close();
+
+ return $results;
+}
+
+// Set top-level variables for HTML
$site_title = 'ip.cleberg.net';
$site_owner_name = 'Christian Cleberg';
$site_owner_url = 'https://cleberg.net';
$source_repository = 'https://git.sr.ht/~cmc/ifconfig.php';
+// Extract geolocation
+$geo = loadGeo($_SERVER['REMOTE_ADDR']);
+
// Create array of values
$user = array(
- 'ip' => $_SERVER['REMOTE_ADDR'],
- 'host' => (isset($_SERVER['REMOTE_ADDR']) ? gethostbyaddr($_SERVER['REMOTE_ADDR']) : ""),
- 'port' => $_SERVER['REMOTE_PORT'],
- 'ua' => $_SERVER['HTTP_USER_AGENT'],
- 'lang' => $_SERVER['HTTP_ACCEPT_LANGUAGE'],
- 'mime' => $_SERVER['HTTP_ACCEPT'],
- 'encoding' => $_SERVER['HTTP_ACCEPT_ENCODING'],
- 'charset' => $_SERVER['HTTP_ACCEPT_CHARSET'],
- 'connection' => $_SERVER['HTTP_CONNECTION'],
- 'cache' => $_SERVER['HTTP_CACHE_CONTROL'],
- 'cookie' => $_SERVER['HTTP_COOKIE'],
- 'referer' => $_SERVER['HTTP_REFERER'],
- 'real_ip' => $_SERVER['HTTP_X_REAL_IP'],
- 'fwd_ip' => $_SERVER['HTTP_X_FORWARDED_FOR'],
- 'fwd_host' => (isset($_SERVER['HTTP_X_FORWARDED_FOR']) ? gethostbyaddr($_SERVER['HTTP_X_FORWARDED_FOR']) : ""),
- 'dnt' => $_SERVER['HTTP_DNT']
+ 'ip' => $_SERVER['REMOTE_ADDR'],
+ 'host' => (isset($_SERVER['REMOTE_ADDR']) ? gethostbyaddr($_SERVER['REMOTE_ADDR']) : ""),
+ 'port' => $_SERVER['REMOTE_PORT'],
+ 'ua' => $_SERVER['HTTP_USER_AGENT'],
+ 'lang' => $_SERVER['HTTP_ACCEPT_LANGUAGE'],
+ 'mime' => $_SERVER['HTTP_ACCEPT'],
+ 'encoding' => $_SERVER['HTTP_ACCEPT_ENCODING'],
+ 'charset' => $_SERVER['HTTP_ACCEPT_CHARSET'],
+ 'connection' => $_SERVER['HTTP_CONNECTION'],
+ 'cache' => $_SERVER['HTTP_CACHE_CONTROL'],
+ 'cookie' => $_SERVER['HTTP_COOKIE'],
+ 'referer' => $_SERVER['HTTP_REFERER'],
+ 'real_ip' => $_SERVER['HTTP_X_REAL_IP'],
+ 'fwd_ip' => $_SERVER['HTTP_X_FORWARDED_FOR'],
+ 'fwd_host' => (isset($_SERVER['HTTP_X_FORWARDED_FOR']) ? gethostbyaddr($_SERVER['HTTP_X_FORWARDED_FOR']) : ""),
+ 'dnt' => $_SERVER['HTTP_DNT'],
+ 'continent_code' => $geo['continent']['code'],
+ 'continent_name' => $geo['continent']['names']['en'],
+ 'country_code' => $geo['country']['geoname_id'],
+ 'country_iso' => $geo['country']['iso_code'],
+ 'country_name' => $geo['country']['names']['en']
);
// Check request (ex. ifconfig.php?q=ip)
@@ -104,7 +126,7 @@ elseif (isset($query) && (($query=="text") || ($query=="all"))) {
$date = date("Y");
echo <<<EOD
<br>
- <p><small>Copyright &copy; {$date} <a href="{$site_owner_url}">{$site_owner_name}</a>.
+ <p><small>Copyright &copy; {$date} <a href="{$site_owner_url}">{$site_owner_name}</a>
<br><a target="_blank" rel="noreferrer" href="{$source_repository}">Source Code</a></small></p>
</body>
</html>
diff --git a/vendor/autoload.php b/vendor/autoload.php
new file mode 100644
index 0000000..8c140f7
--- /dev/null
+++ b/vendor/autoload.php
@@ -0,0 +1,25 @@
+<?php
+
+// autoload.php @generated by Composer
+
+if (PHP_VERSION_ID < 50600) {
+ if (!headers_sent()) {
+ header('HTTP/1.1 500 Internal Server Error');
+ }
+ $err = 'Composer 2.3.0 dropped support for autoloading on PHP <5.6 and you are running '.PHP_VERSION.', please upgrade PHP or use Composer 2.2 LTS via "composer self-update --2.2". Aborting.'.PHP_EOL;
+ if (!ini_get('display_errors')) {
+ if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') {
+ fwrite(STDERR, $err);
+ } elseif (!headers_sent()) {
+ echo $err;
+ }
+ }
+ trigger_error(
+ $err,
+ E_USER_ERROR
+ );
+}
+
+require_once __DIR__ . '/composer/autoload_real.php';
+
+return ComposerAutoloaderInit50ddf2d71e933dcf3091cee659a80047::getLoader();
diff --git a/vendor/composer/ClassLoader.php b/vendor/composer/ClassLoader.php
new file mode 100644
index 0000000..a72151c
--- /dev/null
+++ b/vendor/composer/ClassLoader.php
@@ -0,0 +1,585 @@
+<?php
+
+/*
+ * This file is part of Composer.
+ *
+ * (c) Nils Adermann <naderman@naderman.de>
+ * Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Composer\Autoload;
+
+/**
+ * ClassLoader implements a PSR-0, PSR-4 and classmap class loader.
+ *
+ * $loader = new \Composer\Autoload\ClassLoader();
+ *
+ * // register classes with namespaces
+ * $loader->add('Symfony\Component', __DIR__.'/component');
+ * $loader->add('Symfony', __DIR__.'/framework');
+ *
+ * // activate the autoloader
+ * $loader->register();
+ *
+ * // to enable searching the include path (eg. for PEAR packages)
+ * $loader->setUseIncludePath(true);
+ *
+ * In this example, if you try to use a class in the Symfony\Component
+ * namespace or one of its children (Symfony\Component\Console for instance),
+ * the autoloader will first look for the class under the component/
+ * directory, and it will then fallback to the framework/ directory if not
+ * found before giving up.
+ *
+ * This class is loosely based on the Symfony UniversalClassLoader.
+ *
+ * @author Fabien Potencier <fabien@symfony.com>
+ * @author Jordi Boggiano <j.boggiano@seld.be>
+ * @see https://www.php-fig.org/psr/psr-0/
+ * @see https://www.php-fig.org/psr/psr-4/
+ */
+class ClassLoader
+{
+ /** @var \Closure(string):void */
+ private static $includeFile;
+
+ /** @var ?string */
+ private $vendorDir;
+
+ // PSR-4
+ /**
+ * @var array[]
+ * @psalm-var array<string, array<string, int>>
+ */
+ private $prefixLengthsPsr4 = array();
+ /**
+ * @var array[]
+ * @psalm-var array<string, array<int, string>>
+ */
+ private $prefixDirsPsr4 = array();
+ /**
+ * @var array[]
+ * @psalm-var array<string, string>
+ */
+ private $fallbackDirsPsr4 = array();
+
+ // PSR-0
+ /**
+ * @var array[]
+ * @psalm-var array<string, array<string, string[]>>
+ */
+ private $prefixesPsr0 = array();
+ /**
+ * @var array[]
+ * @psalm-var array<string, string>
+ */
+ private $fallbackDirsPsr0 = array();
+
+ /** @var bool */
+ private $useIncludePath = false;
+
+ /**
+ * @var string[]
+ * @psalm-var array<string, string>
+ */
+ private $classMap = array();
+
+ /** @var bool */
+ private $classMapAuthoritative = false;
+
+ /**
+ * @var bool[]
+ * @psalm-var array<string, bool>
+ */
+ private $missingClasses = array();
+
+ /** @var ?string */
+ private $apcuPrefix;
+
+ /**
+ * @var self[]
+ */
+ private static $registeredLoaders = array();
+
+ /**
+ * @param ?string $vendorDir
+ */
+ public function __construct($vendorDir = null)
+ {
+ $this->vendorDir = $vendorDir;
+ self::initializeIncludeClosure();
+ }
+
+ /**
+ * @return string[]
+ */
+ public function getPrefixes()
+ {
+ if (!empty($this->prefixesPsr0)) {
+ return call_user_func_array('array_merge', array_values($this->prefixesPsr0));
+ }
+
+ return array();
+ }
+
+ /**
+ * @return array[]
+ * @psalm-return array<string, array<int, string>>
+ */
+ public function getPrefixesPsr4()
+ {
+ return $this->prefixDirsPsr4;
+ }
+
+ /**
+ * @return array[]
+ * @psalm-return array<string, string>
+ */
+ public function getFallbackDirs()
+ {
+ return $this->fallbackDirsPsr0;
+ }
+
+ /**
+ * @return array[]
+ * @psalm-return array<string, string>
+ */
+ public function getFallbackDirsPsr4()
+ {
+ return $this->fallbackDirsPsr4;
+ }
+
+ /**
+ * @return string[] Array of classname => path
+ * @psalm-return array<string, string>
+ */
+ public function getClassMap()
+ {
+ return $this->classMap;
+ }
+
+ /**
+ * @param string[] $classMap Class to filename map
+ * @psalm-param array<string, string> $classMap
+ *
+ * @return void
+ */
+ public function addClassMap(array $classMap)
+ {
+ if ($this->classMap) {
+ $this->classMap = array_merge($this->classMap, $classMap);
+ } else {
+ $this->classMap = $classMap;
+ }
+ }
+
+ /**
+ * Registers a set of PSR-0 directories for a given prefix, either
+ * appending or prepending to the ones previously set for this prefix.
+ *
+ * @param string $prefix The prefix
+ * @param string[]|string $paths The PSR-0 root directories
+ * @param bool $prepend Whether to prepend the directories
+ *
+ * @return void
+ */
+ public function add($prefix, $paths, $prepend = false)
+ {
+ if (!$prefix) {
+ if ($prepend) {
+ $this->fallbackDirsPsr0 = array_merge(
+ (array) $paths,
+ $this->fallbackDirsPsr0
+ );
+ } else {
+ $this->fallbackDirsPsr0 = array_merge(
+ $this->fallbackDirsPsr0,
+ (array) $paths
+ );
+ }
+
+ return;
+ }
+
+ $first = $prefix[0];
+ if (!isset($this->prefixesPsr0[$first][$prefix])) {
+ $this->prefixesPsr0[$first][$prefix] = (array) $paths;
+
+ return;
+ }
+ if ($prepend) {
+ $this->prefixesPsr0[$first][$prefix] = array_merge(
+ (array) $paths,
+ $this->prefixesPsr0[$first][$prefix]
+ );
+ } else {
+ $this->prefixesPsr0[$first][$prefix] = array_merge(
+ $this->prefixesPsr0[$first][$prefix],
+ (array) $paths
+ );
+ }
+ }
+
+ /**
+ * Registers a set of PSR-4 directories for a given namespace, either
+ * appending or prepending to the ones previously set for this namespace.
+ *
+ * @param string $prefix The prefix/namespace, with trailing '\\'
+ * @param string[]|string $paths The PSR-4 base directories
+ * @param bool $prepend Whether to prepend the directories
+ *
+ * @throws \InvalidArgumentException
+ *
+ * @return void
+ */
+ public function addPsr4($prefix, $paths, $prepend = false)
+ {
+ if (!$prefix) {
+ // Register directories for the root namespace.
+ if ($prepend) {
+ $this->fallbackDirsPsr4 = array_merge(
+ (array) $paths,
+ $this->fallbackDirsPsr4
+ );
+ } else {
+ $this->fallbackDirsPsr4 = array_merge(
+ $this->fallbackDirsPsr4,
+ (array) $paths
+ );
+ }
+ } elseif (!isset($this->prefixDirsPsr4[$prefix])) {
+ // Register directories for a new namespace.
+ $length = strlen($prefix);
+ if ('\\' !== $prefix[$length - 1]) {
+ throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
+ }
+ $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
+ $this->prefixDirsPsr4[$prefix] = (array) $paths;
+ } elseif ($prepend) {
+ // Prepend directories for an already registered namespace.
+ $this->prefixDirsPsr4[$prefix] = array_merge(
+ (array) $paths,
+ $this->prefixDirsPsr4[$prefix]
+ );
+ } else {
+ // Append directories for an already registered namespace.
+ $this->prefixDirsPsr4[$prefix] = array_merge(
+ $this->prefixDirsPsr4[$prefix],
+ (array) $paths
+ );
+ }
+ }
+
+ /**
+ * Registers a set of PSR-0 directories for a given prefix,
+ * replacing any others previously set for this prefix.
+ *
+ * @param string $prefix The prefix
+ * @param string[]|string $paths The PSR-0 base directories
+ *
+ * @return void
+ */
+ public function set($prefix, $paths)
+ {
+ if (!$prefix) {
+ $this->fallbackDirsPsr0 = (array) $paths;
+ } else {
+ $this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths;
+ }
+ }
+
+ /**
+ * Registers a set of PSR-4 directories for a given namespace,
+ * replacing any others previously set for this namespace.
+ *
+ * @param string $prefix The prefix/namespace, with trailing '\\'
+ * @param string[]|string $paths The PSR-4 base directories
+ *
+ * @throws \InvalidArgumentException
+ *
+ * @return void
+ */
+ public function setPsr4($prefix, $paths)
+ {
+ if (!$prefix) {
+ $this->fallbackDirsPsr4 = (array) $paths;
+ } else {
+ $length = strlen($prefix);
+ if ('\\' !== $prefix[$length - 1]) {
+ throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
+ }
+ $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
+ $this->prefixDirsPsr4[$prefix] = (array) $paths;
+ }
+ }
+
+ /**
+ * Turns on searching the include path for class files.
+ *
+ * @param bool $useIncludePath
+ *
+ * @return void
+ */
+ public function setUseIncludePath($useIncludePath)
+ {
+ $this->useIncludePath = $useIncludePath;
+ }
+
+ /**
+ * Can be used to check if the autoloader uses the include path to check
+ * for classes.
+ *
+ * @return bool
+ */
+ public function getUseIncludePath()
+ {
+ return $this->useIncludePath;
+ }
+
+ /**
+ * Turns off searching the prefix and fallback directories for classes
+ * that have not been registered with the class map.
+ *
+ * @param bool $classMapAuthoritative
+ *
+ * @return void
+ */
+ public function setClassMapAuthoritative($classMapAuthoritative)
+ {
+ $this->classMapAuthoritative = $classMapAuthoritative;
+ }
+
+ /**
+ * Should class lookup fail if not found in the current class map?
+ *
+ * @return bool
+ */
+ public function isClassMapAuthoritative()
+ {
+ return $this->classMapAuthoritative;
+ }
+
+ /**
+ * APCu prefix to use to cache found/not-found classes, if the extension is enabled.
+ *
+ * @param string|null $apcuPrefix
+ *
+ * @return void
+ */
+ public function setApcuPrefix($apcuPrefix)
+ {
+ $this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null;
+ }
+
+ /**
+ * The APCu prefix in use, or null if APCu caching is not enabled.
+ *
+ * @return string|null
+ */
+ public function getApcuPrefix()
+ {
+ return $this->apcuPrefix;
+ }
+
+ /**
+ * Registers this instance as an autoloader.
+ *
+ * @param bool $prepend Whether to prepend the autoloader or not
+ *
+ * @return void
+ */
+ public function register($prepend = false)
+ {
+ spl_autoload_register(array($this, 'loadClass'), true, $prepend);
+
+ if (null === $this->vendorDir) {
+ return;
+ }
+
+ if ($prepend) {
+ self::$registeredLoaders = array($this->vendorDir => $this) + self::$registeredLoaders;
+ } else {
+ unset(self::$registeredLoaders[$this->vendorDir]);
+ self::$registeredLoaders[$this->vendorDir] = $this;
+ }
+ }
+
+ /**
+ * Unregisters this instance as an autoloader.
+ *
+ * @return void
+ */
+ public function unregister()
+ {
+ spl_autoload_unregister(array($this, 'loadClass'));
+
+ if (null !== $this->vendorDir) {
+ unset(self::$registeredLoaders[$this->vendorDir]);
+ }
+ }
+
+ /**
+ * Loads the given class or interface.
+ *
+ * @param string $class The name of the class
+ * @return true|null True if loaded, null otherwise
+ */
+ public function loadClass($class)
+ {
+ if ($file = $this->findFile($class)) {
+ $includeFile = self::$includeFile;
+ $includeFile($file);
+
+ return true;
+ }
+
+ return null;
+ }
+
+ /**
+ * Finds the path to the file where the class is defined.
+ *
+ * @param string $class The name of the class
+ *
+ * @return string|false The path if found, false otherwise
+ */
+ public function findFile($class)
+ {
+ // class map lookup
+ if (isset($this->classMap[$class])) {
+ return $this->classMap[$class];
+ }
+ if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) {
+ return false;
+ }
+ if (null !== $this->apcuPrefix) {
+ $file = apcu_fetch($this->apcuPrefix.$class, $hit);
+ if ($hit) {
+ return $file;
+ }
+ }
+
+ $file = $this->findFileWithExtension($class, '.php');
+
+ // Search for Hack files if we are running on HHVM
+ if (false === $file && defined('HHVM_VERSION')) {
+ $file = $this->findFileWithExtension($class, '.hh');
+ }
+
+ if (null !== $this->apcuPrefix) {
+ apcu_add($this->apcuPrefix.$class, $file);
+ }
+
+ if (false === $file) {
+ // Remember that this class does not exist.
+ $this->missingClasses[$class] = true;
+ }
+
+ return $file;
+ }
+
+ /**
+ * Returns the currently registered loaders indexed by their corresponding vendor directories.
+ *
+ * @return self[]
+ */
+ public static function getRegisteredLoaders()
+ {
+ return self::$registeredLoaders;
+ }
+
+ /**
+ * @param string $class
+ * @param string $ext
+ * @return string|false
+ */
+ private function findFileWithExtension($class, $ext)
+ {
+ // PSR-4 lookup
+ $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext;
+
+ $first = $class[0];
+ if (isset($this->prefixLengthsPsr4[$first])) {
+ $subPath = $class;
+ while (false !== $lastPos = strrpos($subPath, '\\')) {
+ $subPath = substr($subPath, 0, $lastPos);
+ $search = $subPath . '\\';
+ if (isset($this->prefixDirsPsr4[$search])) {
+ $pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1);
+ foreach ($this->prefixDirsPsr4[$search] as $dir) {
+ if (file_exists($file = $dir . $pathEnd)) {
+ return $file;
+ }
+ }
+ }
+ }
+ }
+
+ // PSR-4 fallback dirs
+ foreach ($this->fallbackDirsPsr4 as $dir) {
+ if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) {
+ return $file;
+ }
+ }
+
+ // PSR-0 lookup
+ if (false !== $pos = strrpos($class, '\\')) {
+ // namespaced class name
+ $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1)
+ . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR);
+ } else {
+ // PEAR-like class name
+ $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext;
+ }
+
+ if (isset($this->prefixesPsr0[$first])) {
+ foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) {
+ if (0 === strpos($class, $prefix)) {
+ foreach ($dirs as $dir) {
+ if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
+ return $file;
+ }
+ }
+ }
+ }
+ }
+
+ // PSR-0 fallback dirs
+ foreach ($this->fallbackDirsPsr0 as $dir) {
+ if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
+ return $file;
+ }
+ }
+
+ // PSR-0 include paths.
+ if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) {
+ return $file;
+ }
+
+ return false;
+ }
+
+ /**
+ * @return void
+ */
+ private static function initializeIncludeClosure()
+ {
+ if (self::$includeFile !== null) {
+ return;
+ }
+
+ /**
+ * Scope isolated include.
+ *
+ * Prevents access to $this/self from included files.
+ *
+ * @param string $file
+ * @return void
+ */
+ self::$includeFile = \Closure::bind(static function($file) {
+ include $file;
+ }, null, null);
+ }
+}
diff --git a/vendor/composer/InstalledVersions.php b/vendor/composer/InstalledVersions.php
new file mode 100644
index 0000000..39e55ea
--- /dev/null
+++ b/vendor/composer/InstalledVersions.php
@@ -0,0 +1,359 @@
+<?php
+
+/*
+ * This file is part of Composer.
+ *
+ * (c) Nils Adermann <naderman@naderman.de>
+ * Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Composer;
+
+use Composer\Autoload\ClassLoader;
+use Composer\Semver\VersionParser;
+
+/**
+ * This class is copied in every Composer installed project and available to all
+ *
+ * See also https://getcomposer.org/doc/07-runtime.md#installed-versions
+ *
+ * To require its presence, you can require `composer-runtime-api ^2.0`
+ *
+ * @final
+ */
+class InstalledVersions
+{
+ /**
+ * @var mixed[]|null
+ * @psalm-var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}|array{}|null
+ */
+ private static $installed;
+
+ /**
+ * @var bool|null
+ */
+ private static $canGetVendors;
+
+ /**
+ * @var array[]
+ * @psalm-var array<string, array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
+ */
+ private static $installedByVendor = array();
+
+ /**
+ * Returns a list of all package names which are present, either by being installed, replaced or provided
+ *
+ * @return string[]
+ * @psalm-return list<string>
+ */
+ public static function getInstalledPackages()
+ {
+ $packages = array();
+ foreach (self::getInstalled() as $installed) {
+ $packages[] = array_keys($installed['versions']);
+ }
+
+ if (1 === \count($packages)) {
+ return $packages[0];
+ }
+
+ return array_keys(array_flip(\call_user_func_array('array_merge', $packages)));
+ }
+
+ /**
+ * Returns a list of all package names with a specific type e.g. 'library'
+ *
+ * @param string $type
+ * @return string[]
+ * @psalm-return list<string>
+ */
+ public static function getInstalledPackagesByType($type)
+ {
+ $packagesByType = array();
+
+ foreach (self::getInstalled() as $installed) {
+ foreach ($installed['versions'] as $name => $package) {
+ if (isset($package['type']) && $package['type'] === $type) {
+ $packagesByType[] = $name;
+ }
+ }
+ }
+
+ return $packagesByType;
+ }
+
+ /**
+ * Checks whether the given package is installed
+ *
+ * This also returns true if the package name is provided or replaced by another package
+ *
+ * @param string $packageName
+ * @param bool $includeDevRequirements
+ * @return bool
+ */
+ public static function isInstalled($packageName, $includeDevRequirements = true)
+ {
+ foreach (self::getInstalled() as $installed) {
+ if (isset($installed['versions'][$packageName])) {
+ return $includeDevRequirements || !isset($installed['versions'][$packageName]['dev_requirement']) || $installed['versions'][$packageName]['dev_requirement'] === false;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Checks whether the given package satisfies a version constraint
+ *
+ * e.g. If you want to know whether version 2.3+ of package foo/bar is installed, you would call:
+ *
+ * Composer\InstalledVersions::satisfies(new VersionParser, 'foo/bar', '^2.3')
+ *
+ * @param VersionParser $parser Install composer/semver to have access to this class and functionality
+ * @param string $packageName
+ * @param string|null $constraint A version constraint to check for, if you pass one you have to make sure composer/semver is required by your package
+ * @return bool
+ */
+ public static function satisfies(VersionParser $parser, $packageName, $constraint)
+ {
+ $constraint = $parser->parseConstraints((string) $constraint);
+ $provided = $parser->parseConstraints(self::getVersionRanges($packageName));
+
+ return $provided->matches($constraint);
+ }
+
+ /**
+ * Returns a version constraint representing all the range(s) which are installed for a given package
+ *
+ * It is easier to use this via isInstalled() with the $constraint argument if you need to check
+ * whether a given version of a package is installed, and not just whether it exists
+ *
+ * @param string $packageName
+ * @return string Version constraint usable with composer/semver
+ */
+ public static function getVersionRanges($packageName)
+ {
+ foreach (self::getInstalled() as $installed) {
+ if (!isset($installed['versions'][$packageName])) {
+ continue;
+ }
+
+ $ranges = array();
+ if (isset($installed['versions'][$packageName]['pretty_version'])) {
+ $ranges[] = $installed['versions'][$packageName]['pretty_version'];
+ }
+ if (array_key_exists('aliases', $installed['versions'][$packageName])) {
+ $ranges = array_merge($ranges, $installed['versions'][$packageName]['aliases']);
+ }
+ if (array_key_exists('replaced', $installed['versions'][$packageName])) {
+ $ranges = array_merge($ranges, $installed['versions'][$packageName]['replaced']);
+ }
+ if (array_key_exists('provided', $installed['versions'][$packageName])) {
+ $ranges = array_merge($ranges, $installed['versions'][$packageName]['provided']);
+ }
+
+ return implode(' || ', $ranges);
+ }
+
+ throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
+ }
+
+ /**
+ * @param string $packageName
+ * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present
+ */
+ public static function getVersion($packageName)
+ {
+ foreach (self::getInstalled() as $installed) {
+ if (!isset($installed['versions'][$packageName])) {
+ continue;
+ }
+
+ if (!isset($installed['versions'][$packageName]['version'])) {
+ return null;
+ }
+
+ return $installed['versions'][$packageName]['version'];
+ }
+
+ throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
+ }
+
+ /**
+ * @param string $packageName
+ * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present
+ */
+ public static function getPrettyVersion($packageName)
+ {
+ foreach (self::getInstalled() as $installed) {
+ if (!isset($installed['versions'][$packageName])) {
+ continue;
+ }
+
+ if (!isset($installed['versions'][$packageName]['pretty_version'])) {
+ return null;
+ }
+
+ return $installed['versions'][$packageName]['pretty_version'];
+ }
+
+ throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
+ }
+
+ /**
+ * @param string $packageName
+ * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as reference
+ */
+ public static function getReference($packageName)
+ {
+ foreach (self::getInstalled() as $installed) {
+ if (!isset($installed['versions'][$packageName])) {
+ continue;
+ }
+
+ if (!isset($installed['versions'][$packageName]['reference'])) {
+ return null;
+ }
+
+ return $installed['versions'][$packageName]['reference'];
+ }
+
+ throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
+ }
+
+ /**
+ * @param string $packageName
+ * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as install path. Packages of type metapackages also have a null install path.
+ */
+ public static function getInstallPath($packageName)
+ {
+ foreach (self::getInstalled() as $installed) {
+ if (!isset($installed['versions'][$packageName])) {
+ continue;
+ }
+
+ return isset($installed['versions'][$packageName]['install_path']) ? $installed['versions'][$packageName]['install_path'] : null;
+ }
+
+ throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
+ }
+
+ /**
+ * @return array
+ * @psalm-return array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}
+ */
+ public static function getRootPackage()
+ {
+ $installed = self::getInstalled();
+
+ return $installed[0]['root'];
+ }
+
+ /**
+ * Returns the raw installed.php data for custom implementations
+ *
+ * @deprecated Use getAllRawData() instead which returns all datasets for all autoloaders present in the process. getRawData only returns the first dataset loaded, which may not be what you expect.
+ * @return array[]
+ * @psalm-return array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}
+ */
+ public static function getRawData()
+ {
+ @trigger_error('getRawData only returns the first dataset loaded, which may not be what you expect. Use getAllRawData() instead which returns all datasets for all autoloaders present in the process.', E_USER_DEPRECATED);
+
+ if (null === self::$installed) {
+ // only require the installed.php file if this file is loaded from its dumped location,
+ // and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937
+ if (substr(__DIR__, -8, 1) !== 'C' && is_file(__DIR__ . '/installed.php')) {
+ self::$installed = include __DIR__ . '/installed.php';
+ } else {
+ self::$installed = array();
+ }
+ }
+
+ return self::$installed;
+ }
+
+ /**
+ * Returns the raw data of all installed.php which are currently loaded for custom implementations
+ *
+ * @return array[]
+ * @psalm-return list<array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
+ */
+ public static function getAllRawData()
+ {
+ return self::getInstalled();
+ }
+
+ /**
+ * Lets you reload the static array from another file
+ *
+ * This is only useful for complex integrations in which a project needs to use
+ * this class but then also needs to execute another project's autoloader in process,
+ * and wants to ensure both projects have access to their version of installed.php.
+ *
+ * A typical case would be PHPUnit, where it would need to make sure it reads all
+ * the data it needs from this class, then call reload() with
+ * `require $CWD/vendor/composer/installed.php` (or similar) as input to make sure
+ * the project in which it runs can then also use this class safely, without
+ * interference between PHPUnit's dependencies and the project's dependencies.
+ *
+ * @param array[] $data A vendor/composer/installed.php data set
+ * @return void
+ *
+ * @psalm-param array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $data
+ */
+ public static function reload($data)
+ {
+ self::$installed = $data;
+ self::$installedByVendor = array();
+ }
+
+ /**
+ * @return array[]
+ * @psalm-return list<array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
+ */
+ private static function getInstalled()
+ {
+ if (null === self::$canGetVendors) {
+ self::$canGetVendors = method_exists('Composer\Autoload\ClassLoader', 'getRegisteredLoaders');
+ }
+
+ $installed = array();
+
+ if (self::$canGetVendors) {
+ foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) {
+ if (isset(self::$installedByVendor[$vendorDir])) {
+ $installed[] = self::$installedByVendor[$vendorDir];
+ } elseif (is_file($vendorDir.'/composer/installed.php')) {
+ /** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $required */
+ $required = require $vendorDir.'/composer/installed.php';
+ $installed[] = self::$installedByVendor[$vendorDir] = $required;
+ if (null === self::$installed && strtr($vendorDir.'/composer', '\\', '/') === strtr(__DIR__, '\\', '/')) {
+ self::$installed = $installed[count($installed) - 1];
+ }
+ }
+ }
+ }
+
+ if (null === self::$installed) {
+ // only require the installed.php file if this file is loaded from its dumped location,
+ // and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937
+ if (substr(__DIR__, -8, 1) !== 'C' && is_file(__DIR__ . '/installed.php')) {
+ /** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $required */
+ $required = require __DIR__ . '/installed.php';
+ self::$installed = $required;
+ } else {
+ self::$installed = array();
+ }
+ }
+
+ if (self::$installed !== array()) {
+ $installed[] = self::$installed;
+ }
+
+ return $installed;
+ }
+}
diff --git a/vendor/composer/LICENSE b/vendor/composer/LICENSE
new file mode 100644
index 0000000..62ecfd8
--- /dev/null
+++ b/vendor/composer/LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) Nils Adermann, Jordi Boggiano
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is furnished
+to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/vendor/composer/autoload_classmap.php b/vendor/composer/autoload_classmap.php
new file mode 100644
index 0000000..0fb0a2c
--- /dev/null
+++ b/vendor/composer/autoload_classmap.php
@@ -0,0 +1,10 @@
+<?php
+
+// autoload_classmap.php @generated by Composer
+
+$vendorDir = dirname(__DIR__);
+$baseDir = dirname($vendorDir);
+
+return array(
+ 'Composer\\InstalledVersions' => $vendorDir . '/composer/InstalledVersions.php',
+);
diff --git a/vendor/composer/autoload_namespaces.php b/vendor/composer/autoload_namespaces.php
new file mode 100644
index 0000000..15a2ff3
--- /dev/null
+++ b/vendor/composer/autoload_namespaces.php
@@ -0,0 +1,9 @@
+<?php
+
+// autoload_namespaces.php @generated by Composer
+
+$vendorDir = dirname(__DIR__);
+$baseDir = dirname($vendorDir);
+
+return array(
+);
diff --git a/vendor/composer/autoload_psr4.php b/vendor/composer/autoload_psr4.php
new file mode 100644
index 0000000..9a0371e
--- /dev/null
+++ b/vendor/composer/autoload_psr4.php
@@ -0,0 +1,10 @@
+<?php
+
+// autoload_psr4.php @generated by Composer
+
+$vendorDir = dirname(__DIR__);
+$baseDir = dirname($vendorDir);
+
+return array(
+ 'MaxMind\\Db\\' => array($vendorDir . '/maxmind-db/reader/src/MaxMind/Db'),
+);
diff --git a/vendor/composer/autoload_real.php b/vendor/composer/autoload_real.php
new file mode 100644
index 0000000..62e11e7
--- /dev/null
+++ b/vendor/composer/autoload_real.php
@@ -0,0 +1,38 @@
+<?php
+
+// autoload_real.php @generated by Composer
+
+class ComposerAutoloaderInit50ddf2d71e933dcf3091cee659a80047
+{
+ private static $loader;
+
+ public static function loadClassLoader($class)
+ {
+ if ('Composer\Autoload\ClassLoader' === $class) {
+ require __DIR__ . '/ClassLoader.php';
+ }
+ }
+
+ /**
+ * @return \Composer\Autoload\ClassLoader
+ */
+ public static function getLoader()
+ {
+ if (null !== self::$loader) {
+ return self::$loader;
+ }
+
+ require __DIR__ . '/platform_check.php';
+
+ spl_autoload_register(array('ComposerAutoloaderInit50ddf2d71e933dcf3091cee659a80047', 'loadClassLoader'), true, true);
+ self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(__DIR__));
+ spl_autoload_unregister(array('ComposerAutoloaderInit50ddf2d71e933dcf3091cee659a80047', 'loadClassLoader'));
+
+ require __DIR__ . '/autoload_static.php';
+ call_user_func(\Composer\Autoload\ComposerStaticInit50ddf2d71e933dcf3091cee659a80047::getInitializer($loader));
+
+ $loader->register(true);
+
+ return $loader;
+ }
+}
diff --git a/vendor/composer/autoload_static.php b/vendor/composer/autoload_static.php
new file mode 100644
index 0000000..1a40e6c
--- /dev/null
+++ b/vendor/composer/autoload_static.php
@@ -0,0 +1,36 @@
+<?php
+
+// autoload_static.php @generated by Composer
+
+namespace Composer\Autoload;
+
+class ComposerStaticInit50ddf2d71e933dcf3091cee659a80047
+{
+ public static $prefixLengthsPsr4 = array (
+ 'M' =>
+ array (
+ 'MaxMind\\Db\\' => 11,
+ ),
+ );
+
+ public static $prefixDirsPsr4 = array (
+ 'MaxMind\\Db\\' =>
+ array (
+ 0 => __DIR__ . '/..' . '/maxmind-db/reader/src/MaxMind/Db',
+ ),
+ );
+
+ public static $classMap = array (
+ 'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php',
+ );
+
+ public static function getInitializer(ClassLoader $loader)
+ {
+ return \Closure::bind(function () use ($loader) {
+ $loader->prefixLengthsPsr4 = ComposerStaticInit50ddf2d71e933dcf3091cee659a80047::$prefixLengthsPsr4;
+ $loader->prefixDirsPsr4 = ComposerStaticInit50ddf2d71e933dcf3091cee659a80047::$prefixDirsPsr4;
+ $loader->classMap = ComposerStaticInit50ddf2d71e933dcf3091cee659a80047::$classMap;
+
+ }, null, ClassLoader::class);
+ }
+}
diff --git a/vendor/composer/installed.json b/vendor/composer/installed.json
new file mode 100644
index 0000000..55ed3cc
--- /dev/null
+++ b/vendor/composer/installed.json
@@ -0,0 +1,74 @@
+{
+ "packages": [
+ {
+ "name": "maxmind-db/reader",
+ "version": "v1.11.0",
+ "version_normalized": "1.11.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/maxmind/MaxMind-DB-Reader-php.git",
+ "reference": "b1f3c0699525336d09cc5161a2861268d9f2ae5b"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/maxmind/MaxMind-DB-Reader-php/zipball/b1f3c0699525336d09cc5161a2861268d9f2ae5b",
+ "reference": "b1f3c0699525336d09cc5161a2861268d9f2ae5b",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.2"
+ },
+ "conflict": {
+ "ext-maxminddb": "<1.10.1,>=2.0.0"
+ },
+ "require-dev": {
+ "friendsofphp/php-cs-fixer": "3.*",
+ "php-coveralls/php-coveralls": "^2.1",
+ "phpstan/phpstan": "*",
+ "phpunit/phpcov": ">=6.0.0",
+ "phpunit/phpunit": ">=8.0.0,<10.0.0",
+ "squizlabs/php_codesniffer": "3.*"
+ },
+ "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"
+ },
+ "time": "2021-10-18T15:23:10+00:00",
+ "type": "library",
+ "installation-source": "dist",
+ "autoload": {
+ "psr-4": {
+ "MaxMind\\Db\\": "src/MaxMind/Db"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "Apache-2.0"
+ ],
+ "authors": [
+ {
+ "name": "Gregory J. Oschwald",
+ "email": "goschwald@maxmind.com",
+ "homepage": "https://www.maxmind.com/"
+ }
+ ],
+ "description": "MaxMind DB Reader API",
+ "homepage": "https://github.com/maxmind/MaxMind-DB-Reader-php",
+ "keywords": [
+ "database",
+ "geoip",
+ "geoip2",
+ "geolocation",
+ "maxmind"
+ ],
+ "support": {
+ "issues": "https://github.com/maxmind/MaxMind-DB-Reader-php/issues",
+ "source": "https://github.com/maxmind/MaxMind-DB-Reader-php/tree/v1.11.0"
+ },
+ "install-path": "../maxmind-db/reader"
+ }
+ ],
+ "dev": true,
+ "dev-package-names": []
+}
diff --git a/vendor/composer/installed.php b/vendor/composer/installed.php
new file mode 100644
index 0000000..75611cf
--- /dev/null
+++ b/vendor/composer/installed.php
@@ -0,0 +1,32 @@
+<?php return array(
+ 'root' => array(
+ 'name' => '__root__',
+ 'pretty_version' => 'dev-main',
+ 'version' => 'dev-main',
+ 'reference' => '58e51ba50949c76f946f90cf31e11c3ea5090388',
+ 'type' => 'library',
+ 'install_path' => __DIR__ . '/../../',
+ 'aliases' => array(),
+ 'dev' => true,
+ ),
+ 'versions' => array(
+ '__root__' => array(
+ 'pretty_version' => 'dev-main',
+ 'version' => 'dev-main',
+ 'reference' => '58e51ba50949c76f946f90cf31e11c3ea5090388',
+ 'type' => 'library',
+ 'install_path' => __DIR__ . '/../../',
+ 'aliases' => array(),
+ 'dev_requirement' => false,
+ ),
+ 'maxmind-db/reader' => array(
+ 'pretty_version' => 'v1.11.0',
+ 'version' => '1.11.0.0',
+ 'reference' => 'b1f3c0699525336d09cc5161a2861268d9f2ae5b',
+ 'type' => 'library',
+ 'install_path' => __DIR__ . '/../maxmind-db/reader',
+ 'aliases' => array(),
+ 'dev_requirement' => false,
+ ),
+ ),
+);
diff --git a/vendor/composer/platform_check.php b/vendor/composer/platform_check.php
new file mode 100644
index 0000000..589e9e7
--- /dev/null
+++ b/vendor/composer/platform_check.php
@@ -0,0 +1,26 @@
+<?php
+
+// platform_check.php @generated by Composer
+
+$issues = array();
+
+if (!(PHP_VERSION_ID >= 70200)) {
+ $issues[] = 'Your Composer dependencies require a PHP version ">= 7.2.0". You are running ' . PHP_VERSION . '.';
+}
+
+if ($issues) {
+ if (!headers_sent()) {
+ header('HTTP/1.1 500 Internal Server Error');
+ }
+ if (!ini_get('display_errors')) {
+ if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') {
+ fwrite(STDERR, 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . implode(PHP_EOL, $issues) . PHP_EOL.PHP_EOL);
+ } elseif (!headers_sent()) {
+ echo 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . str_replace('You are running '.PHP_VERSION.'.', '', implode(PHP_EOL, $issues)) . PHP_EOL.PHP_EOL;
+ }
+ }
+ trigger_error(
+ 'Composer detected issues in your platform: ' . implode(' ', $issues),
+ E_USER_ERROR
+ );
+}
diff --git a/vendor/maxmind-db/reader/CHANGELOG.md b/vendor/maxmind-db/reader/CHANGELOG.md
new file mode 100644
index 0000000..4c89f0c
--- /dev/null
+++ b/vendor/maxmind-db/reader/CHANGELOG.md
@@ -0,0 +1,230 @@
+CHANGELOG
+=========
+
+1.11.0
+-------------------
+
+* Replace runtime define of a constant to facilitate opcache preloading.
+ Reported by vedadkajtaz. GitHub #134.
+* Resolve minor issue found by the Clang static analyzer in the C
+ extension.
+
+1.10.1 (2021-04-14)
+-------------------
+
+* Fix a `TypeError` exception in the pure PHP reader when using large
+ databases on 32-bit PHP builds with the `bcmath` extension. Reported
+ by dodo1708. GitHub #124.
+
+1.10.0 (2021-02-09)
+-------------------
+
+* When using the pure PHP reader, unsigned integers up to PHP_MAX_INT
+ will now be integers in PHP rather than strings. Previously integers
+ greater than 2^24 on 32-bit platforms and 2^56 on 64-bit platforms
+ would be strings due to the use of `gmp` or `bcmath` to decode them.
+ Reported by Alejandro Celaya. GitHub #119.
+
+1.9.0 (2021-01-07)
+------------------
+
+* The `maxminddb` extension is now buildable on Windows. Pull request
+ by Jan Ehrhardt. GitHub #115.
+
+1.8.0 (2020-10-01)
+------------------
+
+* Fixes for PHP 8.0. Pull Request by Remi Collet. GitHub #108.
+
+1.7.0 (2020-08-07)
+------------------
+
+* IMPORTANT: PHP 7.2 or greater is now required.
+* The extension no longer depends on the pure PHP classes in
+ `maxmind-db/reader`. You can use it independently.
+* Type hints have been added to both the pure PHP implementation
+ and the extension.
+* The `metadata` method on the reader now returns a new copy of the
+ metadata object rather than the actual object used by the reader.
+* Work around PHP `is_readable()` bug. Reported by Ben Roberts. GitHub
+ #92.
+* This is the first release of the extension as a PECL package.
+ GitHub #34.
+
+1.6.0 (2019-12-19)
+------------------
+
+* 1.5.0 and 1.5.1 contained a possible memory corruptions when using
+ `getWithPrefixLen`. This has been fixed. Reported by proton-ab.
+ GitHub #96.
+* The `composer.json` file now conflicts with all versions of the
+ `maxminddb` C extension less than the Composer version. This is to
+ reduce the chance of having an older, conflicting version of the
+ extension installed. You will need to upgrade the extension before
+ running `composer update`. Pull request by Benoît Burnichon. GitHub
+ #97.
+
+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/vendor/maxmind-db/reader/LICENSE b/vendor/maxmind-db/reader/LICENSE
new file mode 100644
index 0000000..d645695
--- /dev/null
+++ b/vendor/maxmind-db/reader/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/vendor/maxmind-db/reader/README.md b/vendor/maxmind-db/reader/README.md
new file mode 100644
index 0000000..49fa280
--- /dev/null
+++ b/vendor/maxmind-db/reader/README.md
@@ -0,0 +1,185 @@
+# 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
+<?php
+require_once 'vendor/autoload.php';
+
+use MaxMind\Db\Reader;
+
+$ipAddress = '24.24.24.24';
+$databaseFile = 'GeoIP2-City.mmdb';
+
+$reader = new Reader($databaseFile);
+
+// get returns just the record for the IP address
+print_r($reader->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/main/README.md#installing-from-a-tarball).
+After successfully installing libmaxmindb, you may install the extension
+from [pecl](https://pecl.php.net/package/maxminddb):
+
+```
+pecl install maxminddb
+```
+
+Alternatively, you may install it from the source. To do so, 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 7.2 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-2020 by MaxMind, Inc.
+
+This is free software, licensed under the Apache License, Version 2.0.
diff --git a/vendor/maxmind-db/reader/autoload.php b/vendor/maxmind-db/reader/autoload.php
new file mode 100644
index 0000000..a1119e7
--- /dev/null
+++ b/vendor/maxmind-db/reader/autoload.php
@@ -0,0 +1,47 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * PSR-4 autoloader implementation for the MaxMind\DB namespace.
+ * First we define the 'mmdb_autoload' function, and then we register
+ * it with 'spl_autoload_register' so that PHP knows to use it.
+ *
+ * @param mixed $class
+ */
+
+/**
+ * Automatically include the file that defines <code>class</code>.
+ *
+ * @param string $class
+ * the name of the class to load
+ */
+function mmdb_autoload($class): void
+{
+ /*
+ * 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/vendor/maxmind-db/reader/composer.json b/vendor/maxmind-db/reader/composer.json
new file mode 100644
index 0000000..26d4873
--- /dev/null
+++ b/vendor/maxmind-db/reader/composer.json
@@ -0,0 +1,44 @@
+{
+ "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": ">=7.2"
+ },
+ "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"
+ },
+ "conflict": {
+ "ext-maxminddb": "<1.10.1,>=2.0.0"
+ },
+ "require-dev": {
+ "friendsofphp/php-cs-fixer": "3.*",
+ "phpunit/phpunit": ">=8.0.0,<10.0.0",
+ "php-coveralls/php-coveralls": "^2.1",
+ "phpunit/phpcov": ">=6.0.0",
+ "squizlabs/php_codesniffer": "3.*",
+ "phpstan/phpstan": "*"
+ },
+ "autoload": {
+ "psr-4": {
+ "MaxMind\\Db\\": "src/MaxMind/Db"
+ }
+ },
+ "autoload-dev": {
+ "psr-4": {
+ "MaxMind\\Db\\Test\\Reader\\": "tests/MaxMind/Db/Test/Reader"
+ }
+ }
+}
diff --git a/vendor/maxmind-db/reader/ext/config.m4 b/vendor/maxmind-db/reader/ext/config.m4
new file mode 100644
index 0000000..675e00c
--- /dev/null
+++ b/vendor/maxmind-db/reader/ext/config.m4
@@ -0,0 +1,40 @@
+PHP_ARG_WITH(maxminddb,
+ [Whether to enable the MaxMind DB Reader extension],
+ [ --with-maxminddb Enable MaxMind DB Reader extension support])
+
+PHP_ARG_ENABLE(maxminddb-debug, for MaxMind DB debug support,
+ [ --enable-maxminddb-debug Enable enable MaxMind DB deubg support], no, no)
+
+if test $PHP_MAXMINDDB != "no"; then
+
+ AC_PATH_PROG(PKG_CONFIG, pkg-config, no)
+
+ AC_MSG_CHECKING(for libmaxminddb)
+ if test -x "$PKG_CONFIG" && $PKG_CONFIG --exists libmaxminddb; then
+ dnl retrieve build options from pkg-config
+ if $PKG_CONFIG libmaxminddb --atleast-version 1.0.0; then
+ LIBMAXMINDDB_INC=`$PKG_CONFIG libmaxminddb --cflags`
+ LIBMAXMINDDB_LIB=`$PKG_CONFIG libmaxminddb --libs`
+ LIBMAXMINDDB_VER=`$PKG_CONFIG libmaxminddb --modversion`
+ AC_MSG_RESULT(found version $LIBMAXMINDDB_VER)
+ else
+ AC_MSG_ERROR(system libmaxminddb must be upgraded to version >= 1.0.0)
+ fi
+ PHP_EVAL_LIBLINE($LIBMAXMINDDB_LIB, MAXMINDDB_SHARED_LIBADD)
+ PHP_EVAL_INCLINE($LIBMAXMINDDB_INC)
+ else
+ AC_MSG_RESULT(pkg-config information missing)
+ AC_MSG_WARN(will use libmaxmxinddb from compiler default path)
+
+ PHP_CHECK_LIBRARY(maxminddb, MMDB_open)
+ PHP_ADD_LIBRARY(maxminddb, 1, MAXMINDDB_SHARED_LIBADD)
+ fi
+
+ if test $PHP_MAXMINDDB_DEBUG != "no"; then
+ CFLAGS="$CFLAGS -Wall -Wextra -Wno-unused-parameter -Wno-missing-field-initializers -Werror"
+ fi
+
+ PHP_SUBST(MAXMINDDB_SHARED_LIBADD)
+
+ PHP_NEW_EXTENSION(maxminddb, maxminddb.c, $ext_shared)
+fi
diff --git a/vendor/maxmind-db/reader/ext/config.w32 b/vendor/maxmind-db/reader/ext/config.w32
new file mode 100644
index 0000000..4eb18f8
--- /dev/null
+++ b/vendor/maxmind-db/reader/ext/config.w32
@@ -0,0 +1,10 @@
+ARG_WITH("maxminddb", "Enable MaxMind DB Reader extension support", "no");
+
+if (PHP_MAXMINDDB == "yes") {
+ if (CHECK_HEADER_ADD_INCLUDE("maxminddb.h", "CFLAGS_MAXMINDDB", PHP_MAXMINDDB + ";" + PHP_PHP_BUILD + "\\include\\maxminddb") &&
+ CHECK_LIB("libmaxminddb.lib", "maxminddb", PHP_MAXMINDDB)) {
+ EXTENSION("maxminddb", "maxminddb.c");
+ } else {
+ WARNING('Could not find maxminddb.h or libmaxminddb.lib; skipping');
+ }
+}
diff --git a/vendor/maxmind-db/reader/ext/maxminddb.c b/vendor/maxmind-db/reader/ext/maxminddb.c
new file mode 100644
index 0000000..b00b2fa
--- /dev/null
+++ b/vendor/maxmind-db/reader/ext/maxminddb.c
@@ -0,0 +1,811 @@
+/* MaxMind, Inc., licenses this file to you 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.
+ */
+
+#include "php_maxminddb.h"
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <php.h>
+#include <zend.h>
+
+#include "Zend/zend_exceptions.h"
+#include "Zend/zend_types.h"
+#include "ext/spl/spl_exceptions.h"
+#include "ext/standard/info.h"
+#include <maxminddb.h>
+
+#ifdef ZTS
+#include <TSRM.h>
+#endif
+
+#define __STDC_FORMAT_MACROS
+#include <inttypes.h>
+
+#define PHP_MAXMINDDB_NS ZEND_NS_NAME("MaxMind", "Db")
+#define PHP_MAXMINDDB_READER_NS ZEND_NS_NAME(PHP_MAXMINDDB_NS, "Reader")
+#define PHP_MAXMINDDB_METADATA_NS \
+ ZEND_NS_NAME(PHP_MAXMINDDB_READER_NS, "Metadata")
+#define PHP_MAXMINDDB_READER_EX_NS \
+ ZEND_NS_NAME(PHP_MAXMINDDB_READER_NS, "InvalidDatabaseException")
+
+#define Z_MAXMINDDB_P(zv) php_maxminddb_fetch_object(Z_OBJ_P(zv))
+typedef size_t strsize_t;
+typedef zend_object free_obj_t;
+
+/* For PHP 8 compatibility */
+#if PHP_VERSION_ID < 80000
+
+#define PROP_OBJ(zv) (zv)
+
+#else
+
+#define PROP_OBJ(zv) Z_OBJ_P(zv)
+
+#define TSRMLS_C
+#define TSRMLS_CC
+#define TSRMLS_DC
+
+/* End PHP 8 compatibility */
+#endif
+
+#ifndef ZEND_ACC_CTOR
+#define ZEND_ACC_CTOR 0
+#endif
+
+/* IS_MIXED was added in 2020 */
+#ifndef IS_MIXED
+#define IS_MIXED IS_UNDEF
+#endif
+
+/* ZEND_THIS was added in 7.4 */
+#ifndef ZEND_THIS
+#define ZEND_THIS (&EX(This))
+#endif
+
+typedef struct _maxminddb_obj {
+ MMDB_s *mmdb;
+ zend_object std;
+} maxminddb_obj;
+
+PHP_FUNCTION(maxminddb);
+
+static int
+get_record(INTERNAL_FUNCTION_PARAMETERS, zval *record, int *prefix_len);
+static const MMDB_entry_data_list_s *
+handle_entry_data_list(const MMDB_entry_data_list_s *entry_data_list,
+ zval *z_value TSRMLS_DC);
+static const MMDB_entry_data_list_s *
+handle_array(const MMDB_entry_data_list_s *entry_data_list,
+ zval *z_value TSRMLS_DC);
+static const MMDB_entry_data_list_s *
+handle_map(const MMDB_entry_data_list_s *entry_data_list,
+ zval *z_value TSRMLS_DC);
+static void handle_uint128(const MMDB_entry_data_list_s *entry_data_list,
+ zval *z_value TSRMLS_DC);
+static void handle_uint64(const MMDB_entry_data_list_s *entry_data_list,
+ zval *z_value TSRMLS_DC);
+static void handle_uint32(const MMDB_entry_data_list_s *entry_data_list,
+ zval *z_value TSRMLS_DC);
+
+#define CHECK_ALLOCATED(val) \
+ if (!val) { \
+ zend_error(E_ERROR, "Out of memory"); \
+ return; \
+ }
+
+static zend_object_handlers maxminddb_obj_handlers;
+static zend_class_entry *maxminddb_ce, *maxminddb_exception_ce, *metadata_ce;
+
+static inline maxminddb_obj *
+php_maxminddb_fetch_object(zend_object *obj TSRMLS_DC) {
+ return (maxminddb_obj *)((char *)(obj)-XtOffsetOf(maxminddb_obj, std));
+}
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_maxminddbreader_construct, 0, 0, 1)
+ZEND_ARG_TYPE_INFO(0, db_file, IS_STRING, 0)
+ZEND_END_ARG_INFO()
+
+PHP_METHOD(MaxMind_Db_Reader, __construct) {
+ char *db_file = NULL;
+ strsize_t name_len;
+ zval *_this_zval = NULL;
+
+ if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
+ getThis(),
+ "Os",
+ &_this_zval,
+ maxminddb_ce,
+ &db_file,
+ &name_len) == FAILURE) {
+ return;
+ }
+
+ if (0 != php_check_open_basedir(db_file TSRMLS_CC) ||
+ 0 != access(db_file, R_OK)) {
+ zend_throw_exception_ex(
+ spl_ce_InvalidArgumentException,
+ 0 TSRMLS_CC,
+ "The file \"%s\" does not exist or is not readable.",
+ db_file);
+ return;
+ }
+
+ MMDB_s *mmdb = (MMDB_s *)ecalloc(1, sizeof(MMDB_s));
+ uint16_t status = MMDB_open(db_file, MMDB_MODE_MMAP, mmdb);
+
+ if (MMDB_SUCCESS != status) {
+ zend_throw_exception_ex(
+ maxminddb_exception_ce,
+ 0 TSRMLS_CC,
+ "Error opening database file (%s). Is this a valid "
+ "MaxMind DB file?",
+ db_file);
+ efree(mmdb);
+ return;
+ }
+
+ maxminddb_obj *mmdb_obj = Z_MAXMINDDB_P(ZEND_THIS);
+ mmdb_obj->mmdb = mmdb;
+}
+
+ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(
+ arginfo_maxminddbreader_get, 0, 1, IS_MIXED, 1)
+ZEND_ARG_TYPE_INFO(0, ip_address, IS_STRING, 0)
+ZEND_END_ARG_INFO()
+
+PHP_METHOD(MaxMind_Db_Reader, get) {
+ int prefix_len = 0;
+ get_record(INTERNAL_FUNCTION_PARAM_PASSTHRU, return_value, &prefix_len);
+}
+
+ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(
+ arginfo_maxminddbreader_getWithPrefixLen, 0, 1, IS_ARRAY, 1)
+ZEND_ARG_TYPE_INFO(0, ip_address, IS_STRING, 0)
+ZEND_END_ARG_INFO()
+
+PHP_METHOD(MaxMind_Db_Reader, getWithPrefixLen) {
+ zval record, z_prefix_len;
+
+ int prefix_len = 0;
+ if (get_record(INTERNAL_FUNCTION_PARAM_PASSTHRU, &record, &prefix_len) ==
+ FAILURE) {
+ return;
+ }
+
+ array_init(return_value);
+ add_next_index_zval(return_value, &record);
+
+ ZVAL_LONG(&z_prefix_len, prefix_len);
+ add_next_index_zval(return_value, &z_prefix_len);
+}
+
+static int
+get_record(INTERNAL_FUNCTION_PARAMETERS, zval *record, int *prefix_len) {
+ char *ip_address = NULL;
+ strsize_t name_len;
+ zval *this_zval = NULL;
+
+ if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
+ getThis(),
+ "Os",
+ &this_zval,
+ maxminddb_ce,
+ &ip_address,
+ &name_len) == FAILURE) {
+ return FAILURE;
+ }
+
+ const maxminddb_obj *mmdb_obj = (maxminddb_obj *)Z_MAXMINDDB_P(ZEND_THIS);
+
+ MMDB_s *mmdb = mmdb_obj->mmdb;
+
+ if (NULL == mmdb) {
+ zend_throw_exception_ex(spl_ce_BadMethodCallException,
+ 0 TSRMLS_CC,
+ "Attempt to read from a closed MaxMind DB.");
+ return FAILURE;
+ }
+
+ struct addrinfo hints = {
+ .ai_family = AF_UNSPEC,
+ .ai_flags = AI_NUMERICHOST,
+ /* We set ai_socktype so that we only get one result back */
+ .ai_socktype = SOCK_STREAM};
+
+ struct addrinfo *addresses = NULL;
+ int gai_status = getaddrinfo(ip_address, NULL, &hints, &addresses);
+ if (gai_status) {
+ zend_throw_exception_ex(spl_ce_InvalidArgumentException,
+ 0 TSRMLS_CC,
+ "The value \"%s\" is not a valid IP address.",
+ ip_address);
+ return FAILURE;
+ }
+ if (!addresses || !addresses->ai_addr) {
+ zend_throw_exception_ex(
+ spl_ce_InvalidArgumentException,
+ 0 TSRMLS_CC,
+ "getaddrinfo was successful but failed to set the addrinfo");
+ return FAILURE;
+ }
+
+ int sa_family = addresses->ai_addr->sa_family;
+
+ int mmdb_error = MMDB_SUCCESS;
+ MMDB_lookup_result_s result =
+ MMDB_lookup_sockaddr(mmdb, addresses->ai_addr, &mmdb_error);
+
+ freeaddrinfo(addresses);
+
+ if (MMDB_SUCCESS != mmdb_error) {
+ zend_class_entry *ex;
+ if (MMDB_IPV6_LOOKUP_IN_IPV4_DATABASE_ERROR == mmdb_error) {
+ ex = spl_ce_InvalidArgumentException;
+ } else {
+ ex = maxminddb_exception_ce;
+ }
+ zend_throw_exception_ex(ex,
+ 0 TSRMLS_CC,
+ "Error looking up %s. %s",
+ ip_address,
+ MMDB_strerror(mmdb_error));
+ return FAILURE;
+ }
+
+ *prefix_len = result.netmask;
+
+ if (sa_family == AF_INET && mmdb->metadata.ip_version == 6) {
+ /* We return the prefix length given the IPv4 address. If there is
+ no IPv4 subtree, we return a prefix length of 0. */
+ *prefix_len = *prefix_len >= 96 ? *prefix_len - 96 : 0;
+ }
+
+ if (!result.found_entry) {
+ ZVAL_NULL(record);
+ return SUCCESS;
+ }
+
+ MMDB_entry_data_list_s *entry_data_list = NULL;
+ int status = MMDB_get_entry_data_list(&result.entry, &entry_data_list);
+
+ if (MMDB_SUCCESS != status) {
+ zend_throw_exception_ex(maxminddb_exception_ce,
+ 0 TSRMLS_CC,
+ "Error while looking up data for %s. %s",
+ ip_address,
+ MMDB_strerror(status));
+ MMDB_free_entry_data_list(entry_data_list);
+ return FAILURE;
+ } else if (NULL == entry_data_list) {
+ zend_throw_exception_ex(
+ maxminddb_exception_ce,
+ 0 TSRMLS_CC,
+ "Error while looking up data for %s. Your database may "
+ "be corrupt or you have found a bug in libmaxminddb.",
+ ip_address);
+ return FAILURE;
+ }
+
+ const MMDB_entry_data_list_s *rv =
+ handle_entry_data_list(entry_data_list, record TSRMLS_CC);
+ if (rv == NULL) {
+ /* We should have already thrown the exception in handle_entry_data_list
+ */
+ return FAILURE;
+ }
+ MMDB_free_entry_data_list(entry_data_list);
+ return SUCCESS;
+}
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_maxminddbreader_void, 0, 0, 0)
+ZEND_END_ARG_INFO()
+
+PHP_METHOD(MaxMind_Db_Reader, metadata) {
+ zval *this_zval = NULL;
+
+ if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
+ getThis(),
+ "O",
+ &this_zval,
+ maxminddb_ce) == FAILURE) {
+ return;
+ }
+
+ const maxminddb_obj *const mmdb_obj =
+ (maxminddb_obj *)Z_MAXMINDDB_P(this_zval);
+
+ if (NULL == mmdb_obj->mmdb) {
+ zend_throw_exception_ex(spl_ce_BadMethodCallException,
+ 0 TSRMLS_CC,
+ "Attempt to read from a closed MaxMind DB.");
+ return;
+ }
+
+ object_init_ex(return_value, metadata_ce);
+
+ MMDB_entry_data_list_s *entry_data_list;
+ MMDB_get_metadata_as_entry_data_list(mmdb_obj->mmdb, &entry_data_list);
+
+ zval metadata_array;
+ const MMDB_entry_data_list_s *rv =
+ handle_entry_data_list(entry_data_list, &metadata_array TSRMLS_CC);
+ if (rv == NULL) {
+ return;
+ }
+ MMDB_free_entry_data_list(entry_data_list);
+ zend_call_method_with_1_params(PROP_OBJ(return_value),
+ metadata_ce,
+ &metadata_ce->constructor,
+ ZEND_CONSTRUCTOR_FUNC_NAME,
+ NULL,
+ &metadata_array);
+ zval_ptr_dtor(&metadata_array);
+}
+
+PHP_METHOD(MaxMind_Db_Reader, close) {
+ zval *this_zval = NULL;
+
+ if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
+ getThis(),
+ "O",
+ &this_zval,
+ maxminddb_ce) == FAILURE) {
+ return;
+ }
+
+ maxminddb_obj *mmdb_obj = (maxminddb_obj *)Z_MAXMINDDB_P(this_zval);
+
+ if (NULL == mmdb_obj->mmdb) {
+ zend_throw_exception_ex(spl_ce_BadMethodCallException,
+ 0 TSRMLS_CC,
+ "Attempt to close a closed MaxMind DB.");
+ return;
+ }
+ MMDB_close(mmdb_obj->mmdb);
+ efree(mmdb_obj->mmdb);
+ mmdb_obj->mmdb = NULL;
+}
+
+static const MMDB_entry_data_list_s *
+handle_entry_data_list(const MMDB_entry_data_list_s *entry_data_list,
+ zval *z_value TSRMLS_DC) {
+ switch (entry_data_list->entry_data.type) {
+ case MMDB_DATA_TYPE_MAP:
+ return handle_map(entry_data_list, z_value TSRMLS_CC);
+ case MMDB_DATA_TYPE_ARRAY:
+ return handle_array(entry_data_list, z_value TSRMLS_CC);
+ case MMDB_DATA_TYPE_UTF8_STRING:
+ ZVAL_STRINGL(z_value,
+ (char *)entry_data_list->entry_data.utf8_string,
+ entry_data_list->entry_data.data_size);
+ break;
+ case MMDB_DATA_TYPE_BYTES:
+ ZVAL_STRINGL(z_value,
+ (char *)entry_data_list->entry_data.bytes,
+ entry_data_list->entry_data.data_size);
+ break;
+ case MMDB_DATA_TYPE_DOUBLE:
+ ZVAL_DOUBLE(z_value, entry_data_list->entry_data.double_value);
+ break;
+ case MMDB_DATA_TYPE_FLOAT:
+ ZVAL_DOUBLE(z_value, entry_data_list->entry_data.float_value);
+ break;
+ case MMDB_DATA_TYPE_UINT16:
+ ZVAL_LONG(z_value, entry_data_list->entry_data.uint16);
+ break;
+ case MMDB_DATA_TYPE_UINT32:
+ handle_uint32(entry_data_list, z_value TSRMLS_CC);
+ break;
+ case MMDB_DATA_TYPE_BOOLEAN:
+ ZVAL_BOOL(z_value, entry_data_list->entry_data.boolean);
+ break;
+ case MMDB_DATA_TYPE_UINT64:
+ handle_uint64(entry_data_list, z_value TSRMLS_CC);
+ break;
+ case MMDB_DATA_TYPE_UINT128:
+ handle_uint128(entry_data_list, z_value TSRMLS_CC);
+ break;
+ case MMDB_DATA_TYPE_INT32:
+ ZVAL_LONG(z_value, entry_data_list->entry_data.int32);
+ break;
+ default:
+ zend_throw_exception_ex(maxminddb_exception_ce,
+ 0 TSRMLS_CC,
+ "Invalid data type arguments: %d",
+ entry_data_list->entry_data.type);
+ return NULL;
+ }
+ return entry_data_list;
+}
+
+static const MMDB_entry_data_list_s *
+handle_map(const MMDB_entry_data_list_s *entry_data_list,
+ zval *z_value TSRMLS_DC) {
+ array_init(z_value);
+ const uint32_t map_size = entry_data_list->entry_data.data_size;
+
+ uint32_t i;
+ for (i = 0; i < map_size && entry_data_list; i++) {
+ entry_data_list = entry_data_list->next;
+
+ char *key = estrndup((char *)entry_data_list->entry_data.utf8_string,
+ entry_data_list->entry_data.data_size);
+ if (NULL == key) {
+ zend_throw_exception_ex(maxminddb_exception_ce,
+ 0 TSRMLS_CC,
+ "Invalid data type arguments");
+ return NULL;
+ }
+
+ entry_data_list = entry_data_list->next;
+ zval new_value;
+ entry_data_list =
+ handle_entry_data_list(entry_data_list, &new_value TSRMLS_CC);
+ if (entry_data_list != NULL) {
+ add_assoc_zval(z_value, key, &new_value);
+ }
+ efree(key);
+ }
+ return entry_data_list;
+}
+
+static const MMDB_entry_data_list_s *
+handle_array(const MMDB_entry_data_list_s *entry_data_list,
+ zval *z_value TSRMLS_DC) {
+ const uint32_t size = entry_data_list->entry_data.data_size;
+
+ array_init(z_value);
+
+ uint32_t i;
+ for (i = 0; i < size && entry_data_list; i++) {
+ entry_data_list = entry_data_list->next;
+ zval new_value;
+ entry_data_list =
+ handle_entry_data_list(entry_data_list, &new_value TSRMLS_CC);
+ if (entry_data_list != NULL) {
+ add_next_index_zval(z_value, &new_value);
+ }
+ }
+ return entry_data_list;
+}
+
+static void handle_uint128(const MMDB_entry_data_list_s *entry_data_list,
+ zval *z_value TSRMLS_DC) {
+ uint64_t high = 0;
+ uint64_t low = 0;
+#if MMDB_UINT128_IS_BYTE_ARRAY
+ int i;
+ for (i = 0; i < 8; i++) {
+ high = (high << 8) | entry_data_list->entry_data.uint128[i];
+ }
+
+ for (i = 8; i < 16; i++) {
+ low = (low << 8) | entry_data_list->entry_data.uint128[i];
+ }
+#else
+ high = entry_data_list->entry_data.uint128 >> 64;
+ low = (uint64_t)entry_data_list->entry_data.uint128;
+#endif
+
+ char *num_str;
+ spprintf(&num_str, 0, "0x%016" PRIX64 "%016" PRIX64, high, low);
+ CHECK_ALLOCATED(num_str);
+
+ ZVAL_STRING(z_value, num_str);
+ efree(num_str);
+}
+
+static void handle_uint32(const MMDB_entry_data_list_s *entry_data_list,
+ zval *z_value TSRMLS_DC) {
+ uint32_t val = entry_data_list->entry_data.uint32;
+
+#if LONG_MAX >= UINT32_MAX
+ ZVAL_LONG(z_value, val);
+ return;
+#else
+ if (val <= LONG_MAX) {
+ ZVAL_LONG(z_value, val);
+ return;
+ }
+
+ char *int_str;
+ spprintf(&int_str, 0, "%" PRIu32, val);
+ CHECK_ALLOCATED(int_str);
+
+ ZVAL_STRING(z_value, int_str);
+ efree(int_str);
+#endif
+}
+
+static void handle_uint64(const MMDB_entry_data_list_s *entry_data_list,
+ zval *z_value TSRMLS_DC) {
+ uint64_t val = entry_data_list->entry_data.uint64;
+
+#if LONG_MAX >= UINT64_MAX
+ ZVAL_LONG(z_value, val);
+ return;
+#else
+ if (val <= LONG_MAX) {
+ ZVAL_LONG(z_value, val);
+ return;
+ }
+
+ char *int_str;
+ spprintf(&int_str, 0, "%" PRIu64, val);
+ CHECK_ALLOCATED(int_str);
+
+ ZVAL_STRING(z_value, int_str);
+ efree(int_str);
+#endif
+}
+
+static void maxminddb_free_storage(free_obj_t *object TSRMLS_DC) {
+ maxminddb_obj *obj =
+ php_maxminddb_fetch_object((zend_object *)object TSRMLS_CC);
+ if (obj->mmdb != NULL) {
+ MMDB_close(obj->mmdb);
+ efree(obj->mmdb);
+ }
+
+ zend_object_std_dtor(&obj->std TSRMLS_CC);
+}
+
+static zend_object *maxminddb_create_handler(zend_class_entry *type TSRMLS_DC) {
+ maxminddb_obj *obj = (maxminddb_obj *)ecalloc(1, sizeof(maxminddb_obj));
+ zend_object_std_init(&obj->std, type TSRMLS_CC);
+ object_properties_init(&(obj->std), type);
+
+ obj->std.handlers = &maxminddb_obj_handlers;
+
+ return &obj->std;
+}
+
+/* clang-format off */
+static zend_function_entry maxminddb_methods[] = {
+ PHP_ME(MaxMind_Db_Reader, __construct, arginfo_maxminddbreader_construct,
+ ZEND_ACC_PUBLIC | ZEND_ACC_CTOR)
+ PHP_ME(MaxMind_Db_Reader, close, arginfo_maxminddbreader_void, ZEND_ACC_PUBLIC)
+ PHP_ME(MaxMind_Db_Reader, get, arginfo_maxminddbreader_get, ZEND_ACC_PUBLIC)
+ PHP_ME(MaxMind_Db_Reader, getWithPrefixLen, arginfo_maxminddbreader_getWithPrefixLen, ZEND_ACC_PUBLIC)
+ PHP_ME(MaxMind_Db_Reader, metadata, arginfo_maxminddbreader_void, ZEND_ACC_PUBLIC)
+ { NULL, NULL, NULL }
+};
+/* clang-format on */
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_metadata_construct, 0, 0, 1)
+ZEND_ARG_TYPE_INFO(0, metadata, IS_ARRAY, 0)
+ZEND_END_ARG_INFO()
+
+PHP_METHOD(MaxMind_Db_Reader_Metadata, __construct) {
+ zval *object = NULL;
+ zval *metadata_array = NULL;
+ zend_long node_count = 0;
+ zend_long record_size = 0;
+
+ if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
+ getThis(),
+ "Oa",
+ &object,
+ metadata_ce,
+ &metadata_array) == FAILURE) {
+ return;
+ }
+
+ zval *tmp = NULL;
+ if ((tmp = zend_hash_str_find(HASH_OF(metadata_array),
+ "binary_format_major_version",
+ sizeof("binary_format_major_version") - 1))) {
+ zend_update_property(metadata_ce,
+ PROP_OBJ(object),
+ "binaryFormatMajorVersion",
+ sizeof("binaryFormatMajorVersion") - 1,
+ tmp);
+ }
+
+ if ((tmp = zend_hash_str_find(HASH_OF(metadata_array),
+ "binary_format_minor_version",
+ sizeof("binary_format_minor_version") - 1))) {
+ zend_update_property(metadata_ce,
+ PROP_OBJ(object),
+ "binaryFormatMinorVersion",
+ sizeof("binaryFormatMinorVersion") - 1,
+ tmp);
+ }
+
+ if ((tmp = zend_hash_str_find(HASH_OF(metadata_array),
+ "build_epoch",
+ sizeof("build_epoch") - 1))) {
+ zend_update_property(metadata_ce,
+ PROP_OBJ(object),
+ "buildEpoch",
+ sizeof("buildEpoch") - 1,
+ tmp);
+ }
+
+ if ((tmp = zend_hash_str_find(HASH_OF(metadata_array),
+ "database_type",
+ sizeof("database_type") - 1))) {
+ zend_update_property(metadata_ce,
+ PROP_OBJ(object),
+ "databaseType",
+ sizeof("databaseType") - 1,
+ tmp);
+ }
+
+ if ((tmp = zend_hash_str_find(HASH_OF(metadata_array),
+ "description",
+ sizeof("description") - 1))) {
+ zend_update_property(metadata_ce,
+ PROP_OBJ(object),
+ "description",
+ sizeof("description") - 1,
+ tmp);
+ }
+
+ if ((tmp = zend_hash_str_find(HASH_OF(metadata_array),
+ "ip_version",
+ sizeof("ip_version") - 1))) {
+ zend_update_property(metadata_ce,
+ PROP_OBJ(object),
+ "ipVersion",
+ sizeof("ipVersion") - 1,
+ tmp);
+ }
+
+ if ((tmp = zend_hash_str_find(
+ HASH_OF(metadata_array), "languages", sizeof("languages") - 1))) {
+ zend_update_property(metadata_ce,
+ PROP_OBJ(object),
+ "languages",
+ sizeof("languages") - 1,
+ tmp);
+ }
+
+ if ((tmp = zend_hash_str_find(HASH_OF(metadata_array),
+ "record_size",
+ sizeof("record_size") - 1))) {
+ zend_update_property(metadata_ce,
+ PROP_OBJ(object),
+ "recordSize",
+ sizeof("recordSize") - 1,
+ tmp);
+ if (Z_TYPE_P(tmp) == IS_LONG) {
+ record_size = Z_LVAL_P(tmp);
+ }
+ }
+
+ if (record_size != 0) {
+ zend_update_property_long(metadata_ce,
+ PROP_OBJ(object),
+ "nodeByteSize",
+ sizeof("nodeByteSize") - 1,
+ record_size / 4);
+ }
+
+ if ((tmp = zend_hash_str_find(HASH_OF(metadata_array),
+ "node_count",
+ sizeof("node_count") - 1))) {
+ zend_update_property(metadata_ce,
+ PROP_OBJ(object),
+ "nodeCount",
+ sizeof("nodeCount") - 1,
+ tmp);
+ if (Z_TYPE_P(tmp) == IS_LONG) {
+ node_count = Z_LVAL_P(tmp);
+ }
+ }
+
+ if (record_size != 0) {
+ zend_update_property_long(metadata_ce,
+ PROP_OBJ(object),
+ "searchTreeSize",
+ sizeof("searchTreeSize") - 1,
+ record_size * node_count / 4);
+ }
+}
+
+// clang-format off
+static zend_function_entry metadata_methods[] = {
+ PHP_ME(MaxMind_Db_Reader_Metadata, __construct, arginfo_metadata_construct, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR)
+ {NULL, NULL, NULL}
+};
+// clang-format on
+
+PHP_MINIT_FUNCTION(maxminddb) {
+ zend_class_entry ce;
+
+ INIT_CLASS_ENTRY(ce, PHP_MAXMINDDB_READER_EX_NS, NULL);
+ maxminddb_exception_ce =
+ zend_register_internal_class_ex(&ce, zend_ce_exception);
+
+ INIT_CLASS_ENTRY(ce, PHP_MAXMINDDB_READER_NS, maxminddb_methods);
+ maxminddb_ce = zend_register_internal_class(&ce TSRMLS_CC);
+ maxminddb_ce->create_object = maxminddb_create_handler;
+
+ INIT_CLASS_ENTRY(ce, PHP_MAXMINDDB_METADATA_NS, metadata_methods);
+ metadata_ce = zend_register_internal_class(&ce TSRMLS_CC);
+ zend_declare_property_null(metadata_ce,
+ "binaryFormatMajorVersion",
+ sizeof("binaryFormatMajorVersion") - 1,
+ ZEND_ACC_PUBLIC);
+ zend_declare_property_null(metadata_ce,
+ "binaryFormatMinorVersion",
+ sizeof("binaryFormatMinorVersion") - 1,
+ ZEND_ACC_PUBLIC);
+ zend_declare_property_null(
+ metadata_ce, "buildEpoch", sizeof("buildEpoch") - 1, ZEND_ACC_PUBLIC);
+ zend_declare_property_null(metadata_ce,
+ "databaseType",
+ sizeof("databaseType") - 1,
+ ZEND_ACC_PUBLIC);
+ zend_declare_property_null(
+ metadata_ce, "description", sizeof("description") - 1, ZEND_ACC_PUBLIC);
+ zend_declare_property_null(
+ metadata_ce, "ipVersion", sizeof("ipVersion") - 1, ZEND_ACC_PUBLIC);
+ zend_declare_property_null(
+ metadata_ce, "languages", sizeof("languages") - 1, ZEND_ACC_PUBLIC);
+ zend_declare_property_null(metadata_ce,
+ "nodeByteSize",
+ sizeof("nodeByteSize") - 1,
+ ZEND_ACC_PUBLIC);
+ zend_declare_property_null(
+ metadata_ce, "nodeCount", sizeof("nodeCount") - 1, ZEND_ACC_PUBLIC);
+ zend_declare_property_null(
+ metadata_ce, "recordSize", sizeof("recordSize") - 1, ZEND_ACC_PUBLIC);
+ zend_declare_property_null(metadata_ce,
+ "searchTreeSize",
+ sizeof("searchTreeSize") - 1,
+ ZEND_ACC_PUBLIC);
+
+ memcpy(&maxminddb_obj_handlers,
+ zend_get_std_object_handlers(),
+ sizeof(zend_object_handlers));
+ maxminddb_obj_handlers.clone_obj = NULL;
+ maxminddb_obj_handlers.offset = XtOffsetOf(maxminddb_obj, std);
+ maxminddb_obj_handlers.free_obj = maxminddb_free_storage;
+ zend_declare_class_constant_string(maxminddb_ce,
+ "MMDB_LIB_VERSION",
+ sizeof("MMDB_LIB_VERSION") - 1,
+ MMDB_lib_version() TSRMLS_CC);
+
+ return SUCCESS;
+}
+
+static PHP_MINFO_FUNCTION(maxminddb) {
+ php_info_print_table_start();
+
+ php_info_print_table_row(2, "MaxMind DB Reader", "enabled");
+ php_info_print_table_row(
+ 2, "maxminddb extension version", PHP_MAXMINDDB_VERSION);
+ php_info_print_table_row(
+ 2, "libmaxminddb library version", MMDB_lib_version());
+
+ php_info_print_table_end();
+}
+
+zend_module_entry maxminddb_module_entry = {STANDARD_MODULE_HEADER,
+ PHP_MAXMINDDB_EXTNAME,
+ NULL,
+ PHP_MINIT(maxminddb),
+ NULL,
+ NULL,
+ NULL,
+ PHP_MINFO(maxminddb),
+ PHP_MAXMINDDB_VERSION,
+ STANDARD_MODULE_PROPERTIES};
+
+#ifdef COMPILE_DL_MAXMINDDB
+ZEND_GET_MODULE(maxminddb)
+#endif
diff --git a/vendor/maxmind-db/reader/ext/php_maxminddb.h b/vendor/maxmind-db/reader/ext/php_maxminddb.h
new file mode 100644
index 0000000..cba9ed5
--- /dev/null
+++ b/vendor/maxmind-db/reader/ext/php_maxminddb.h
@@ -0,0 +1,24 @@
+/* MaxMind, Inc., licenses this file to you 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.
+ */
+
+#include <zend_interfaces.h>
+
+#ifndef PHP_MAXMINDDB_H
+#define PHP_MAXMINDDB_H 1
+#define PHP_MAXMINDDB_VERSION "1.10.1"
+#define PHP_MAXMINDDB_EXTNAME "maxminddb"
+
+extern zend_module_entry maxminddb_module_entry;
+#define phpext_maxminddb_ptr &maxminddb_module_entry
+
+#endif
diff --git a/vendor/maxmind-db/reader/ext/tests/001-load.phpt b/vendor/maxmind-db/reader/ext/tests/001-load.phpt
new file mode 100644
index 0000000..09810ee
--- /dev/null
+++ b/vendor/maxmind-db/reader/ext/tests/001-load.phpt
@@ -0,0 +1,12 @@
+--TEST--
+Check for maxminddb presence
+--SKIPIF--
+<?php if (!extension_loaded('maxminddb')) {
+ echo 'skip';
+} ?>
+--FILE--
+<?php
+echo 'maxminddb extension is available';
+?>
+--EXPECT--
+maxminddb extension is available
diff --git a/vendor/maxmind-db/reader/ext/tests/002-final.phpt b/vendor/maxmind-db/reader/ext/tests/002-final.phpt
new file mode 100644
index 0000000..d91b7d0
--- /dev/null
+++ b/vendor/maxmind-db/reader/ext/tests/002-final.phpt
@@ -0,0 +1,13 @@
+--TEST--
+Check that Reader class is not final
+--SKIPIF--
+<?php if (!extension_loaded('maxminddb')) {
+ echo 'skip';
+} ?>
+--FILE--
+<?php
+$reflectionClass = new \ReflectionClass('MaxMind\Db\Reader');
+var_dump($reflectionClass->isFinal());
+?>
+--EXPECT--
+bool(false)
diff --git a/vendor/maxmind-db/reader/ext/tests/003-open-basedir.phpt b/vendor/maxmind-db/reader/ext/tests/003-open-basedir.phpt
new file mode 100644
index 0000000..26e9781
--- /dev/null
+++ b/vendor/maxmind-db/reader/ext/tests/003-open-basedir.phpt
@@ -0,0 +1,12 @@
+--TEST--
+openbase_dir is followed
+--INI--
+open_basedir=/--dne--
+--FILE--
+<?php
+use MaxMind\Db\Reader;
+
+$reader = new Reader('/usr/local/share/GeoIP/GeoIP2-City.mmdb');
+?>
+--EXPECTREGEX--
+.*open_basedir restriction in effect.*
diff --git a/vendor/maxmind-db/reader/package.xml b/vendor/maxmind-db/reader/package.xml
new file mode 100644
index 0000000..b687468
--- /dev/null
+++ b/vendor/maxmind-db/reader/package.xml
@@ -0,0 +1,63 @@
+<?xml version="1.0"?>
+<package version="2.0" xmlns="http://pear.php.net/dtd/package-2.0"
+ xmlns:tasks="http://pear.php.net/dtd/tasks-1.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://pear.php.net/dtd/tasks-1.0 http://pear.php.net/dtd/tasks-1.0.xsd http://pear.php.net/dtd/package-2.0 http://pear.php.net/dtd/package-2.0.xsd">
+
+ <name>maxminddb</name>
+ <channel>pecl.php.net</channel>
+ <summary>Reader for the MaxMind DB file format</summary>
+ <description>This is the PHP extension for reading MaxMind DB files. MaxMind DB is a binary file format that stores data indexed by IP address subnets (IPv4 or IPv6).</description>
+ <lead>
+ <name>Greg Oschwald</name>
+ <user>oschwald</user>
+ <email>goschwald@maxmind.com</email>
+ <active>yes</active>
+ </lead>
+ <date>2021-04-14</date>
+ <version>
+ <release>1.10.1</release>
+ <api>1.10.1</api>
+ </version>
+ <stability>
+ <release>stable</release>
+ <api>stable</api>
+ </stability>
+ <license uri="https://github.com/maxmind/MaxMind-DB-Reader-php/blob/main/LICENSE">Apache License 2.0</license>
+ <notes>* Fix a `TypeError` exception in the pure PHP reader when using large
+ databases on 32-bit PHP builds with the `bcmath` extension. Reported
+ by dodo1708. GitHub #124.</notes>
+ <contents>
+ <dir name="/">
+ <file role="doc" name="LICENSE"/>
+ <file role="doc" name="CHANGELOG.md"/>
+ <file role="doc" name="README.md"/>
+
+ <dir name="ext">
+ <file role="src" name="config.m4"/>
+ <file role="src" name="config.w32"/>
+
+ <file role="src" name="maxminddb.c"/>
+ <file role="src" name="php_maxminddb.h"/>
+
+ <dir name="tests">
+ <file role="test" name="001-load.phpt"/>
+ <file role="test" name="002-final.phpt"/>
+ <file role="test" name="003-open-basedir.phpt"/>
+ </dir>
+ </dir>
+ </dir>
+ </contents>
+ <dependencies>
+ <required>
+ <php>
+ <min>7.2.0</min>
+ </php>
+ <pearinstaller>
+ <min>1.10.0</min>
+ </pearinstaller>
+ </required>
+ </dependencies>
+ <providesextension>maxminddb</providesextension>
+ <extsrcrelease />
+</package>
diff --git a/vendor/maxmind-db/reader/src/MaxMind/Db/Reader.php b/vendor/maxmind-db/reader/src/MaxMind/Db/Reader.php
new file mode 100644
index 0000000..4dfaef4
--- /dev/null
+++ b/vendor/maxmind-db/reader/src/MaxMind/Db/Reader.php
@@ -0,0 +1,373 @@
+<?php
+
+declare(strict_types=1);
+
+namespace MaxMind\Db;
+
+use ArgumentCountError;
+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.
+ */
+class Reader
+{
+ /**
+ * @var int
+ */
+ private static $DATA_SECTION_SEPARATOR_SIZE = 16;
+ /**
+ * @var string
+ */
+ private static $METADATA_START_MARKER = "\xAB\xCD\xEFMaxMind.com";
+ /**
+ * @var int
+ */
+ private static $METADATA_START_MARKER_LENGTH = 14;
+ /**
+ * @var int
+ */
+ private static $METADATA_MAX_SIZE = 131072; // 128 * 1024 = 128KiB
+
+ /**
+ * @var Decoder
+ */
+ private $decoder;
+ /**
+ * @var resource
+ */
+ private $fileHandle;
+ /**
+ * @var int
+ */
+ private $fileSize;
+ /**
+ * @var int
+ */
+ private $ipV4Start;
+ /**
+ * @var Metadata
+ */
+ 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 InvalidDatabaseException
+ * if the database is invalid or there is an error reading
+ * from it
+ */
+ public function __construct(string $database)
+ {
+ if (\func_num_args() !== 1) {
+ throw new ArgumentCountError(
+ sprintf('%s() expects exactly 1 parameter, %d given', __METHOD__, \func_num_args())
+ );
+ }
+
+ $fileHandle = @fopen($database, 'rb');
+ if ($fileHandle === false) {
+ throw new InvalidArgumentException(
+ "The file \"$database\" does not exist or is not readable."
+ );
+ }
+ $this->fileHandle = $fileHandle;
+
+ $fileSize = @filesize($database);
+ if ($fileSize === false) {
+ throw new UnexpectedValueException(
+ "Error determining the size of \"$database\"."
+ );
+ }
+ $this->fileSize = $fileSize;
+
+ $start = $this->findMetadataStart($database);
+ $metadataDecoder = new Decoder($this->fileHandle, $start);
+ [$metadataArray] = $metadataDecoder->decode($start);
+ $this->metadata = new Metadata($metadataArray);
+ $this->decoder = new Decoder(
+ $this->fileHandle,
+ $this->metadata->searchTreeSize + self::$DATA_SECTION_SEPARATOR_SIZE
+ );
+ $this->ipV4Start = $this->ipV4StartNode();
+ }
+
+ /**
+ * 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 InvalidDatabaseException
+ * if the database is invalid or there is an error reading
+ * from it
+ *
+ * @return mixed the record for the IP address
+ */
+ public function get(string $ipAddress)
+ {
+ if (\func_num_args() !== 1) {
+ throw new ArgumentCountError(
+ sprintf('%s() expects exactly 1 parameter, %d given', __METHOD__, \func_num_args())
+ );
+ }
+ [$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(string $ipAddress): array
+ {
+ if (\func_num_args() !== 1) {
+ throw new ArgumentCountError(
+ sprintf('%s() expects exactly 1 parameter, %d given', __METHOD__, \func_num_args())
+ );
+ }
+
+ if (!\is_resource($this->fileHandle)) {
+ throw new BadMethodCallException(
+ 'Attempt to read from a closed MaxMind DB.'
+ );
+ }
+
+ [$pointer, $prefixLen] = $this->findAddressInTree($ipAddress);
+ if ($pointer === 0) {
+ return [null, $prefixLen];
+ }
+
+ return [$this->resolveDataPointer($pointer), $prefixLen];
+ }
+
+ private function findAddressInTree(string $ipAddress): array
+ {
+ $packedAddr = @inet_pton($ipAddress);
+ if ($packedAddr === false) {
+ throw new InvalidArgumentException(
+ "The value \"$ipAddress\" is not a valid IP address."
+ );
+ }
+
+ $rawAddress = unpack('C*', $packedAddr);
+
+ $bitCount = \count($rawAddress) * 8;
+
+ // The first node of the tree is always node 0, at the beginning of the
+ // value
+ $node = 0;
+
+ $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;
+ }
+ } 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 === $nodeCount) {
+ // Record is empty
+ return [0, $i];
+ }
+ if ($node > $nodeCount) {
+ // Record is a data pointer
+ return [$node, $i];
+ }
+
+ throw new InvalidDatabaseException(
+ 'Invalid or corrupt database. Maximum search depth reached without finding a leaf node'
+ );
+ }
+
+ private function ipV4StartNode(): int
+ {
+ // If we have an IPv4 database, the start node is the first node
+ if ($this->metadata->ipVersion === 4) {
+ return 0;
+ }
+
+ $node = 0;
+
+ for ($i = 0; $i < 96 && $node < $this->metadata->nodeCount; ++$i) {
+ $node = $this->readNode($node, 0);
+ }
+
+ return $node;
+ }
+
+ private function readNode(int $nodeNumber, int $index): int
+ {
+ $baseOffset = $nodeNumber * $this->metadata->nodeByteSize;
+
+ switch ($this->metadata->recordSize) {
+ case 24:
+ $bytes = Util::read($this->fileHandle, $baseOffset + $index * 3, 3);
+ [, $node] = unpack('N', "\x00" . $bytes);
+
+ return $node;
+
+ case 28:
+ $bytes = Util::read($this->fileHandle, $baseOffset + 3 * $index, 4);
+ if ($index === 0) {
+ $middle = (0xF0 & \ord($bytes[3])) >> 4;
+ } else {
+ $middle = 0x0F & \ord($bytes[0]);
+ }
+ [, $node] = unpack('N', \chr($middle) . substr($bytes, $index, 3));
+
+ return $node;
+
+ case 32:
+ $bytes = Util::read($this->fileHandle, $baseOffset + $index * 4, 4);
+ [, $node] = unpack('N', $bytes);
+
+ return $node;
+
+ default:
+ throw new InvalidDatabaseException(
+ 'Unknown record size: '
+ . $this->metadata->recordSize
+ );
+ }
+ }
+
+ /**
+ * @return mixed
+ */
+ private function resolveDataPointer(int $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"
+ );
+ }
+
+ [$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(string $filename): int
+ {
+ $handle = $this->fileHandle;
+ $fstat = fstat($handle);
+ $fileSize = $fstat['size'];
+ $marker = self::$METADATA_START_MARKER;
+ $markerLength = self::$METADATA_START_MARKER_LENGTH;
+
+ $minStart = $fileSize - min(self::$METADATA_MAX_SIZE, $fileSize);
+
+ for ($offset = $fileSize - $markerLength; $offset >= $minStart; --$offset) {
+ if (fseek($handle, $offset) !== 0) {
+ break;
+ }
+
+ $value = fread($handle, $markerLength);
+ if ($value === $marker) {
+ return $offset + $markerLength;
+ }
+ }
+
+ 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(): Metadata
+ {
+ if (\func_num_args()) {
+ throw new ArgumentCountError(
+ sprintf('%s() expects exactly 0 parameters, %d given', __METHOD__, \func_num_args())
+ );
+ }
+
+ // 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 clone $this->metadata;
+ }
+
+ /**
+ * Closes the MaxMind DB and returns resources to the system.
+ *
+ * @throws Exception
+ * if an I/O error occurs
+ */
+ public function close(): void
+ {
+ if (\func_num_args()) {
+ throw new ArgumentCountError(
+ sprintf('%s() expects exactly 0 parameters, %d given', __METHOD__, \func_num_args())
+ );
+ }
+
+ if (!\is_resource($this->fileHandle)) {
+ throw new BadMethodCallException(
+ 'Attempt to close a closed MaxMind DB.'
+ );
+ }
+ fclose($this->fileHandle);
+ }
+}
diff --git a/vendor/maxmind-db/reader/src/MaxMind/Db/Reader/Decoder.php b/vendor/maxmind-db/reader/src/MaxMind/Db/Reader/Decoder.php
new file mode 100644
index 0000000..babaed8
--- /dev/null
+++ b/vendor/maxmind-db/reader/src/MaxMind/Db/Reader/Decoder.php
@@ -0,0 +1,374 @@
+<?php
+
+declare(strict_types=1);
+
+namespace MaxMind\Db\Reader;
+
+// @codingStandardsIgnoreLine
+use RuntimeException;
+
+class Decoder
+{
+ /**
+ * @var resource
+ */
+ private $fileStream;
+ /**
+ * @var int
+ */
+ private $pointerBase;
+ /**
+ * @var float
+ */
+ private $pointerBaseByteSize;
+ /**
+ * This is only used for unit testing.
+ *
+ * @var bool
+ */
+ private $pointerTestHack;
+ /**
+ * @var bool
+ */
+ private $switchByteOrder;
+
+ private const _EXTENDED = 0;
+ private const _POINTER = 1;
+ private const _UTF8_STRING = 2;
+ private const _DOUBLE = 3;
+ private const _BYTES = 4;
+ private const _UINT16 = 5;
+ private const _UINT32 = 6;
+ private const _MAP = 7;
+ private const _INT32 = 8;
+ private const _UINT64 = 9;
+ private const _UINT128 = 10;
+ private const _ARRAY = 11;
+ private const _CONTAINER = 12;
+ private const _END_MARKER = 13;
+ private const _BOOLEAN = 14;
+ private const _FLOAT = 15;
+
+ /**
+ * @param resource $fileStream
+ */
+ public function __construct(
+ $fileStream,
+ int $pointerBase = 0,
+ bool $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(int $offset): array
+ {
+ $ctrlByte = \ord(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) {
+ [$pointer, $offset] = $this->decodePointer($ctrlByte, $offset);
+
+ // for unit testing
+ if ($this->pointerTestHack) {
+ return [$pointer];
+ }
+
+ [$result] = $this->decode($pointer);
+
+ return [$result, $offset];
+ }
+
+ if ($type === self::_EXTENDED) {
+ $nextByte = \ord(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;
+ }
+
+ [$size, $offset] = $this->sizeFromCtrlByte($ctrlByte, $offset);
+
+ return $this->decodeByType($type, $offset, $size);
+ }
+
+ private function decodeByType(int $type, int $offset, int $size): array
+ {
+ 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(int $expected, int $actual): void
+ {
+ 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(int $size, int $offset): array
+ {
+ $array = [];
+
+ for ($i = 0; $i < $size; ++$i) {
+ [$value, $offset] = $this->decode($offset);
+ $array[] = $value;
+ }
+
+ return [$array, $offset];
+ }
+
+ private function decodeBoolean(int $size): bool
+ {
+ return $size !== 0;
+ }
+
+ private function decodeDouble(string $bytes): float
+ {
+ // This assumes IEEE 754 doubles, but most (all?) modern platforms
+ // use them.
+ [, $double] = unpack('E', $bytes);
+
+ return $double;
+ }
+
+ private function decodeFloat(string $bytes): float
+ {
+ // This assumes IEEE 754 floats, but most (all?) modern platforms
+ // use them.
+ [, $float] = unpack('G', $bytes);
+
+ return $float;
+ }
+
+ private function decodeInt32(string $bytes, int $size): int
+ {
+ 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)"
+ );
+ }
+
+ [, $int] = unpack('l', $this->maybeSwitchByteOrder($bytes));
+
+ return $int;
+ }
+
+ private function decodeMap(int $size, int $offset): array
+ {
+ $map = [];
+
+ for ($i = 0; $i < $size; ++$i) {
+ [$key, $offset] = $this->decode($offset);
+ [$value, $offset] = $this->decode($offset);
+ $map[$key] = $value;
+ }
+
+ return [$map, $offset];
+ }
+
+ private function decodePointer(int $ctrlByte, int $offset): array
+ {
+ $pointerSize = (($ctrlByte >> 3) & 0x3) + 1;
+
+ $buffer = Util::read($this->fileStream, $offset, $pointerSize);
+ $offset = $offset + $pointerSize;
+
+ switch ($pointerSize) {
+ case 1:
+ $packed = \chr($ctrlByte & 0x7) . $buffer;
+ [, $pointer] = unpack('n', $packed);
+ $pointer += $this->pointerBase;
+
+ break;
+
+ case 2:
+ $packed = "\x00" . \chr($ctrlByte & 0x7) . $buffer;
+ [, $pointer] = unpack('N', $packed);
+ $pointer += $this->pointerBase + 2048;
+
+ break;
+
+ case 3:
+ $packed = \chr($ctrlByte & 0x7) . $buffer;
+
+ // It is safe to use 'N' here, even on 32 bit machines as the
+ // first bit is 0.
+ [, $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);
+
+ $pointerBase = $this->pointerBase;
+
+ if (\PHP_INT_MAX - $pointerBase >= $pointerOffset) {
+ $pointer = $pointerOffset + $pointerBase;
+ } else {
+ throw new RuntimeException(
+ 'The database offset is too large to be represented on your platform.'
+ );
+ }
+
+ break;
+
+ default:
+ throw new InvalidDatabaseException(
+ 'Unexpected pointer size ' . $pointerSize
+ );
+ }
+
+ return [$pointer, $offset];
+ }
+
+ // @phpstan-ignore-next-line
+ private function decodeUint(string $bytes, int $byteLength)
+ {
+ if ($byteLength === 0) {
+ return 0;
+ }
+
+ $integer = 0;
+
+ // PHP integers are signed. PHP_INT_SIZE - 1 is the number of
+ // complete bytes that can be converted to an integer. However,
+ // we can convert another byte if the leading bit is zero.
+ $useRealInts = $byteLength <= \PHP_INT_SIZE - 1
+ || ($byteLength === \PHP_INT_SIZE && (\ord($bytes[0]) & 0x80) === 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 ($useRealInts) {
+ $integer = ($integer << 8) + $part;
+ } elseif (\extension_loaded('gmp')) {
+ $integer = gmp_strval(gmp_add(gmp_mul((string) $integer, '256'), $part));
+ } elseif (\extension_loaded('bcmath')) {
+ $integer = bcadd(bcmul((string) $integer, '256'), (string) $part);
+ } else {
+ throw new RuntimeException(
+ 'The gmp or bcmath extension must be installed to read this database.'
+ );
+ }
+ }
+
+ return $integer;
+ }
+
+ private function sizeFromCtrlByte(int $ctrlByte, int $offset): array
+ {
+ $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) {
+ [, $adjust] = unpack('n', $bytes);
+ $size = 285 + $adjust;
+ } else {
+ [, $adjust] = unpack('N', "\x00" . $bytes);
+ $size = $adjust + 65821;
+ }
+
+ return [$size, $offset + $bytesToRead];
+ }
+
+ private function maybeSwitchByteOrder(string $bytes): string
+ {
+ return $this->switchByteOrder ? strrev($bytes) : $bytes;
+ }
+
+ private function isPlatformLittleEndian(): bool
+ {
+ $testint = 0x00FF;
+ $packed = pack('S', $testint);
+
+ return $testint === current(unpack('v', $packed));
+ }
+}
diff --git a/vendor/maxmind-db/reader/src/MaxMind/Db/Reader/InvalidDatabaseException.php b/vendor/maxmind-db/reader/src/MaxMind/Db/Reader/InvalidDatabaseException.php
new file mode 100644
index 0000000..5323107
--- /dev/null
+++ b/vendor/maxmind-db/reader/src/MaxMind/Db/Reader/InvalidDatabaseException.php
@@ -0,0 +1,14 @@
+<?php
+
+declare(strict_types=1);
+
+namespace MaxMind\Db\Reader;
+
+use Exception;
+
+/**
+ * This class should be thrown when unexpected data is found in the database.
+ */
+class InvalidDatabaseException extends Exception
+{
+}
diff --git a/vendor/maxmind-db/reader/src/MaxMind/Db/Reader/Metadata.php b/vendor/maxmind-db/reader/src/MaxMind/Db/Reader/Metadata.php
new file mode 100644
index 0000000..873064b
--- /dev/null
+++ b/vendor/maxmind-db/reader/src/MaxMind/Db/Reader/Metadata.php
@@ -0,0 +1,112 @@
+<?php
+
+declare(strict_types=1);
+
+namespace MaxMind\Db\Reader;
+
+use ArgumentCountError;
+
+/**
+ * This class provides the metadata for the MaxMind DB file.
+ */
+class Metadata
+{
+ /**
+ * This is an unsigned 16-bit integer indicating the major version number
+ * for the database's binary format.
+ *
+ * @var int
+ */
+ public $binaryFormatMajorVersion;
+ /**
+ * This is an unsigned 16-bit integer indicating the minor version number
+ * for the database's binary format.
+ *
+ * @var int
+ */
+ public $binaryFormatMinorVersion;
+ /**
+ * This is an unsigned 64-bit integer that contains the database build
+ * timestamp as a Unix epoch value.
+ *
+ * @var int
+ */
+ public $buildEpoch;
+ /**
+ * 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.
+ *
+ * @var string
+ */
+ public $databaseType;
+ /**
+ * 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.
+ *
+ * @var array
+ */
+ public $description;
+ /**
+ * This is an unsigned 16-bit integer which is always 4 or 6. It indicates
+ * whether the database contains IPv4 or IPv6 address data.
+ *
+ * @var int
+ */
+ public $ipVersion;
+ /**
+ * 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.
+ *
+ * @var array
+ */
+ public $languages;
+ /**
+ * @var int
+ */
+ public $nodeByteSize;
+ /**
+ * This is an unsigned 32-bit integer indicating the number of nodes in
+ * the search tree.
+ *
+ * @var int
+ */
+ public $nodeCount;
+ /**
+ * 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.
+ *
+ * @var int
+ */
+ public $recordSize;
+ /**
+ * @var int
+ */
+ public $searchTreeSize;
+
+ public function __construct(array $metadata)
+ {
+ if (\func_num_args() !== 1) {
+ throw new ArgumentCountError(
+ sprintf('%s() expects exactly 1 parameter, %d given', __METHOD__, \func_num_args())
+ );
+ }
+
+ $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;
+ }
+}
diff --git a/vendor/maxmind-db/reader/src/MaxMind/Db/Reader/Util.php b/vendor/maxmind-db/reader/src/MaxMind/Db/Reader/Util.php
new file mode 100644
index 0000000..89db715
--- /dev/null
+++ b/vendor/maxmind-db/reader/src/MaxMind/Db/Reader/Util.php
@@ -0,0 +1,32 @@
+<?php
+
+declare(strict_types=1);
+
+namespace MaxMind\Db\Reader;
+
+class Util
+{
+ /**
+ * @param resource $stream
+ */
+ public static function read($stream, int $offset, int $numberOfBytes): string
+ {
+ 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 ($value !== false && ftell($stream) - $offset === $numberOfBytes) {
+ return $value;
+ }
+ }
+
+ throw new InvalidDatabaseException(
+ 'The MaxMind DB file contains bad data'
+ );
+ }
+}