summaryrefslogtreecommitdiffstats
path: root/vendor/maxmind-db/reader
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/maxmind-db/reader')
-rw-r--r--vendor/maxmind-db/reader/CHANGELOG.md222
-rw-r--r--vendor/maxmind-db/reader/LICENSE202
-rw-r--r--vendor/maxmind-db/reader/README.md178
-rw-r--r--vendor/maxmind-db/reader/autoload.php45
-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/maxminddb.c704
-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.php327
-rw-r--r--vendor/maxmind-db/reader/src/MaxMind/Db/Reader/Decoder.php381
-rw-r--r--vendor/maxmind-db/reader/src/MaxMind/Db/Reader/InvalidDatabaseException.php12
-rw-r--r--vendor/maxmind-db/reader/src/MaxMind/Db/Reader/Metadata.php88
-rw-r--r--vendor/maxmind-db/reader/src/MaxMind/Db/Reader/Util.php26
17 files changed, 2393 insertions, 0 deletions
diff --git a/vendor/maxmind-db/reader/CHANGELOG.md b/vendor/maxmind-db/reader/CHANGELOG.md
new file mode 100644
index 0000000..d413e4f
--- /dev/null
+++ b/vendor/maxmind-db/reader/CHANGELOG.md
@@ -0,0 +1,222 @@
+CHANGELOG
+=========
+
+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..5b3f21e
--- /dev/null
+++ b/vendor/maxmind-db/reader/README.md
@@ -0,0 +1,178 @@
+# MaxMind DB Reader PHP API #
+
+## Description ##
+
+This is the PHP API for reading MaxMind DB files. MaxMind DB is a binary file
+format that stores data indexed by IP address subnets (IPv4 or IPv6).
+
+## Installation (Composer) ##
+
+We recommend installing this package with [Composer](https://getcomposer.org/).
+
+### Download Composer ###
+
+To download Composer, run in the root directory of your project:
+
+```bash
+curl -sS https://getcomposer.org/installer | php
+```
+
+You should now have the file `composer.phar` in your project directory.
+
+### Install Dependencies ###
+
+Run in your project root:
+
+```
+php composer.phar require maxmind-db/reader:~1.0
+```
+
+You should now have the files `composer.json` and `composer.lock` as well as
+the directory `vendor` in your project directory. If you use a version control
+system, `composer.json` should be added to it.
+
+### Require Autoloader ###
+
+After installing the dependencies, you need to require the Composer autoloader
+from your code:
+
+```php
+require 'vendor/autoload.php';
+```
+
+## Installation (Standalone) ##
+
+If you don't want to use Composer for some reason, a custom
+`autoload.php` is provided for you in the project root. To use the
+library, simply include that file,
+
+```php
+require('/path/to/MaxMind-DB-Reader-php/autoload.php');
+```
+
+and then instantiate the reader class normally:
+
+```php
+use MaxMind\Db\Reader;
+$reader = new Reader('example.mmdb');
+```
+
+## Installation (RPM)
+
+RPMs are available in the [official Fedora repository](https://apps.fedoraproject.org/packages/php-maxminddb).
+
+To install on Fedora, run:
+
+```bash
+dnf install php-maxminddb
+```
+
+To install on CentOS or RHEL 7, first [enable the EPEL repository](https://fedoraproject.org/wiki/EPEL)
+and then run:
+
+```bash
+yum install php-maxminddb
+```
+
+Please note that these packages are *not* maintained by MaxMind.
+
+## Usage ##
+
+## Example ##
+
+```php
+<?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/master/README.md#installing-from-a-tarball).
+After successfully installing libmaxmindb, run the following commands from the
+top-level directory of this distribution:
+
+```
+cd ext
+phpize
+./configure
+make
+make test
+sudo make install
+```
+
+You then must load your extension. The recommend method is to add the
+following to your `php.ini` file:
+
+```
+extension=maxminddb.so
+```
+
+Note: You may need to install the PHP development package on your OS such as
+php5-dev for Debian-based systems or php-devel for RedHat/Fedora-based ones.
+
+## 128-bit Integer Support ##
+
+The MaxMind DB format includes 128-bit unsigned integer as a type. Although
+no MaxMind-distributed database currently makes use of this type, both the
+pure PHP reader and the C extension support this type. The pure PHP reader
+requires gmp or bcmath to read databases with 128-bit unsigned integers.
+
+The integer is currently returned as a hexadecimal string (prefixed with "0x")
+by the C extension and a decimal string (no prefix) by the pure PHP reader.
+Any change to make the reader implementations always return either a
+hexadecimal or decimal representation of the integer will NOT be considered a
+breaking change.
+
+## Support ##
+
+Please report all issues with this code using the [GitHub issue tracker](https://github.com/maxmind/MaxMind-DB-Reader-php/issues).
+
+If you are having an issue with a MaxMind service that is not specific to the
+client API, please see [our support page](https://www.maxmind.com/en/support).
+
+## Requirements ##
+
+This library requires PHP 5.6 or greater.
+
+The GMP or BCMath extension may be required to read some databases
+using the pure PHP API.
+
+## Contributing ##
+
+Patches and pull requests are encouraged. All code should follow the PSR-1 and
+PSR-2 style guidelines. Please include unit tests whenever possible.
+
+## Versioning ##
+
+The MaxMind DB Reader PHP API uses [Semantic Versioning](https://semver.org/).
+
+## Copyright and License ##
+
+This software is Copyright (c) 2014-2019 by MaxMind, Inc.
+
+This is free software, licensed under the Apache License, Version 2.0.
diff --git a/vendor/maxmind-db/reader/autoload.php b/vendor/maxmind-db/reader/autoload.php
new file mode 100644
index 0000000..c79126f
--- /dev/null
+++ b/vendor/maxmind-db/reader/autoload.php
@@ -0,0 +1,45 @@
+<?php
+
+/**
+ * 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)
+{
+ /*
+ * 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..d4debfb
--- /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": "*",
+ "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/maxminddb.c b/vendor/maxmind-db/reader/ext/maxminddb.c
new file mode 100644
index 0000000..2714608
--- /dev/null
+++ b/vendor/maxmind-db/reader/ext/maxminddb.c
@@ -0,0 +1,704 @@
+/* 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 "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_READER_EX_NS \
+ ZEND_NS_NAME(PHP_MAXMINDDB_READER_NS, "InvalidDatabaseException")
+
+#ifdef ZEND_ENGINE_3
+#define Z_MAXMINDDB_P(zv) php_maxminddb_fetch_object(Z_OBJ_P(zv))
+#define _ZVAL_STRING ZVAL_STRING
+#define _ZVAL_STRINGL ZVAL_STRINGL
+typedef size_t strsize_t;
+typedef zend_object free_obj_t;
+#else
+#define Z_MAXMINDDB_P(zv) \
+ (maxminddb_obj *)zend_object_store_get_object(zv TSRMLS_CC)
+#define _ZVAL_STRING(a, b) ZVAL_STRING(a, b, 1)
+#define _ZVAL_STRINGL(a, b, c) ZVAL_STRINGL(a, b, c, 1)
+typedef int strsize_t;
+typedef void free_obj_t;
+#endif
+
+/* For PHP 8 compatibility */
+#ifndef TSRMLS_C
+#define TSRMLS_C
+#endif
+#ifndef TSRMLS_CC
+#define TSRMLS_CC
+#endif
+#ifndef TSRMLS_DC
+#define TSRMLS_DC
+#endif
+#ifndef ZEND_ACC_CTOR
+#define ZEND_ACC_CTOR 0
+#endif
+
+#ifdef ZEND_ENGINE_3
+typedef struct _maxminddb_obj {
+ MMDB_s *mmdb;
+ zend_object std;
+} maxminddb_obj;
+#else
+typedef struct _maxminddb_obj {
+ zend_object std;
+ MMDB_s *mmdb;
+} maxminddb_obj;
+#endif
+
+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);
+static zend_class_entry *lookup_class(const char *name TSRMLS_DC);
+
+#define CHECK_ALLOCATED(val) \
+ if (!val) { \
+ zend_error(E_ERROR, "Out of memory"); \
+ return; \
+ }
+
+#define THROW_EXCEPTION(name, ...) \
+ { \
+ zend_class_entry *exception_ce = lookup_class(name TSRMLS_CC); \
+ zend_throw_exception_ex(exception_ce, 0 TSRMLS_CC, __VA_ARGS__); \
+ }
+
+#if PHP_VERSION_ID < 50399
+#define object_properties_init(zo, class_type) \
+ { \
+ zval *tmp; \
+ zend_hash_copy((*zo).properties, \
+ &class_type->default_properties, \
+ (copy_ctor_func_t)zval_add_ref, \
+ (void *)&tmp, \
+ sizeof(zval *)); \
+ }
+#endif
+
+static zend_object_handlers maxminddb_obj_handlers;
+static zend_class_entry *maxminddb_ce;
+
+static inline maxminddb_obj *
+php_maxminddb_fetch_object(zend_object *obj TSRMLS_DC) {
+#ifdef ZEND_ENGINE_3
+ return (maxminddb_obj *)((char *)(obj)-XtOffsetOf(maxminddb_obj, std));
+#else
+ return (maxminddb_obj *)obj;
+#endif
+}
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_maxmindbreader_construct, 0, 0, 1)
+ZEND_ARG_INFO(0, db_file)
+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) {
+ THROW_EXCEPTION("InvalidArgumentException",
+ "The constructor takes exactly one argument.");
+ return;
+ }
+
+ if (0 != php_check_open_basedir(db_file TSRMLS_CC) ||
+ 0 != access(db_file, R_OK)) {
+ THROW_EXCEPTION("InvalidArgumentException",
+ "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) {
+ THROW_EXCEPTION(PHP_MAXMINDDB_READER_EX_NS,
+ "Error opening database file (%s). Is this a valid "
+ "MaxMind DB file?",
+ db_file);
+ efree(mmdb);
+ return;
+ }
+
+ maxminddb_obj *mmdb_obj = Z_MAXMINDDB_P(getThis());
+ mmdb_obj->mmdb = mmdb;
+}
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_maxmindbreader_get, 0, 0, 1)
+ZEND_ARG_INFO(0, ip_address)
+ZEND_END_ARG_INFO()
+
+PHP_METHOD(MaxMind_Db_Reader, get) {
+ int prefix_len = 0;
+ get_record(INTERNAL_FUNCTION_PARAM_PASSTHRU, return_value, &prefix_len);
+}
+
+PHP_METHOD(MaxMind_Db_Reader, getWithPrefixLen) {
+ zval *record, *z_prefix_len;
+#ifdef ZEND_ENGINE_3
+ zval _record, _z_prefix_len;
+ record = &_record;
+ z_prefix_len = &_z_prefix_len;
+#else
+ ALLOC_INIT_ZVAL(record);
+ ALLOC_INIT_ZVAL(z_prefix_len);
+#endif
+
+ int prefix_len = 0;
+ if (get_record(INTERNAL_FUNCTION_PARAM_PASSTHRU, record, &prefix_len)) {
+ 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) {
+ THROW_EXCEPTION("InvalidArgumentException",
+ "Method takes exactly one argument.");
+ return 1;
+ }
+
+ const maxminddb_obj *mmdb_obj = (maxminddb_obj *)Z_MAXMINDDB_P(getThis());
+
+ MMDB_s *mmdb = mmdb_obj->mmdb;
+
+ if (NULL == mmdb) {
+ THROW_EXCEPTION("BadMethodCallException",
+ "Attempt to read from a closed MaxMind DB.");
+ return 1;
+ }
+
+ 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) {
+ THROW_EXCEPTION("InvalidArgumentException",
+ "The value \"%s\" is not a valid IP address.",
+ ip_address);
+ return 1;
+ }
+ if (!addresses || !addresses->ai_addr) {
+ THROW_EXCEPTION(
+ "InvalidArgumentException",
+ "getaddrinfo was successful but failed to set the addrinfo");
+ return 1;
+ }
+
+ 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) {
+ char *exception_name;
+ if (MMDB_IPV6_LOOKUP_IN_IPV4_DATABASE_ERROR == mmdb_error) {
+ exception_name = "InvalidArgumentException";
+ } else {
+ exception_name = PHP_MAXMINDDB_READER_EX_NS;
+ }
+ THROW_EXCEPTION(exception_name,
+ "Error looking up %s. %s",
+ ip_address,
+ MMDB_strerror(mmdb_error));
+ return 1;
+ }
+
+ *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 0;
+ }
+
+ 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) {
+ THROW_EXCEPTION(PHP_MAXMINDDB_READER_EX_NS,
+ "Error while looking up data for %s. %s",
+ ip_address,
+ MMDB_strerror(status));
+ MMDB_free_entry_data_list(entry_data_list);
+ return 1;
+ } else if (NULL == entry_data_list) {
+ THROW_EXCEPTION(PHP_MAXMINDDB_READER_EX_NS,
+ "Error while looking up data for %s. Your database may "
+ "be corrupt or you have found a bug in libmaxminddb.",
+ ip_address);
+ return 1;
+ }
+
+ handle_entry_data_list(entry_data_list, record TSRMLS_CC);
+ MMDB_free_entry_data_list(entry_data_list);
+ return 0;
+}
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_maxmindbreader_void, 0, 0, 0)
+ZEND_END_ARG_INFO()
+
+PHP_METHOD(MaxMind_Db_Reader, metadata) {
+ if (ZEND_NUM_ARGS() != 0) {
+ THROW_EXCEPTION("InvalidArgumentException",
+ "Method takes no arguments.");
+ return;
+ }
+
+ const maxminddb_obj *const mmdb_obj =
+ (maxminddb_obj *)Z_MAXMINDDB_P(getThis());
+
+ if (NULL == mmdb_obj->mmdb) {
+ THROW_EXCEPTION("BadMethodCallException",
+ "Attempt to read from a closed MaxMind DB.");
+ return;
+ }
+
+ const char *const name = ZEND_NS_NAME(PHP_MAXMINDDB_READER_NS, "Metadata");
+ zend_class_entry *metadata_ce = lookup_class(name TSRMLS_CC);
+
+ object_init_ex(return_value, metadata_ce);
+
+#ifdef ZEND_ENGINE_3
+ zval _metadata_array;
+ zval *metadata_array = &_metadata_array;
+ ZVAL_NULL(metadata_array);
+#else
+ zval *metadata_array;
+ ALLOC_INIT_ZVAL(metadata_array);
+#endif
+
+ MMDB_entry_data_list_s *entry_data_list;
+ MMDB_get_metadata_as_entry_data_list(mmdb_obj->mmdb, &entry_data_list);
+
+ handle_entry_data_list(entry_data_list, metadata_array TSRMLS_CC);
+ MMDB_free_entry_data_list(entry_data_list);
+#if PHP_VERSION_ID >= 80000
+ zend_call_method_with_1_params(Z_OBJ_P(return_value),
+ metadata_ce,
+ &metadata_ce->constructor,
+ ZEND_CONSTRUCTOR_FUNC_NAME,
+ NULL,
+ metadata_array);
+ zval_ptr_dtor(metadata_array);
+#elif defined(ZEND_ENGINE_3)
+ zend_call_method_with_1_params(return_value,
+ metadata_ce,
+ &metadata_ce->constructor,
+ ZEND_CONSTRUCTOR_FUNC_NAME,
+ NULL,
+ metadata_array);
+ zval_ptr_dtor(metadata_array);
+#else
+ zend_call_method_with_1_params(&return_value,
+ metadata_ce,
+ &metadata_ce->constructor,
+ ZEND_CONSTRUCTOR_FUNC_NAME,
+ NULL,
+ metadata_array);
+ zval_ptr_dtor(&metadata_array);
+#endif
+}
+
+PHP_METHOD(MaxMind_Db_Reader, close) {
+ if (ZEND_NUM_ARGS() != 0) {
+ THROW_EXCEPTION("InvalidArgumentException",
+ "Method takes no arguments.");
+ return;
+ }
+
+ maxminddb_obj *mmdb_obj = (maxminddb_obj *)Z_MAXMINDDB_P(getThis());
+
+ if (NULL == mmdb_obj->mmdb) {
+ THROW_EXCEPTION("BadMethodCallException",
+ "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:
+ THROW_EXCEPTION(PHP_MAXMINDDB_READER_EX_NS,
+ "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;
+
+ uint 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) {
+ THROW_EXCEPTION(PHP_MAXMINDDB_READER_EX_NS,
+ "Invalid data type arguments");
+ return NULL;
+ }
+
+ entry_data_list = entry_data_list->next;
+#ifdef ZEND_ENGINE_3
+ zval _new_value;
+ zval *new_value = &_new_value;
+ ZVAL_NULL(new_value);
+#else
+ zval *new_value;
+ ALLOC_INIT_ZVAL(new_value);
+#endif
+ entry_data_list =
+ handle_entry_data_list(entry_data_list, new_value TSRMLS_CC);
+ 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);
+
+ uint i;
+ for (i = 0; i < size && entry_data_list; i++) {
+ entry_data_list = entry_data_list->next;
+#ifdef ZEND_ENGINE_3
+ zval _new_value;
+ zval *new_value = &_new_value;
+ ZVAL_NULL(new_value);
+#else
+ zval *new_value;
+ ALLOC_INIT_ZVAL(new_value);
+#endif
+ entry_data_list =
+ handle_entry_data_list(entry_data_list, new_value TSRMLS_CC);
+ 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 zend_class_entry *lookup_class(const char *name TSRMLS_DC) {
+#ifdef ZEND_ENGINE_3
+ zend_string *n = zend_string_init(name, strlen(name), 0);
+ zend_class_entry *ce = zend_lookup_class(n);
+ zend_string_release(n);
+ if (NULL == ce) {
+ zend_error(E_ERROR, "Class %s not found", name);
+ }
+ return ce;
+#else
+ zend_class_entry **ce;
+ if (FAILURE == zend_lookup_class(name, strlen(name), &ce TSRMLS_CC)) {
+ zend_error(E_ERROR, "Class %s not found", name);
+ }
+ return *ce;
+#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);
+#ifndef ZEND_ENGINE_3
+ efree(object);
+#endif
+}
+
+#ifdef ZEND_ENGINE_3
+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;
+}
+#else
+static zend_object_value
+maxminddb_create_handler(zend_class_entry *type TSRMLS_DC) {
+ zend_object_value retval;
+
+ 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);
+
+ retval.handle = zend_objects_store_put(
+ obj, NULL, maxminddb_free_storage, NULL TSRMLS_CC);
+ retval.handlers = &maxminddb_obj_handlers;
+
+ return retval;
+}
+#endif
+
+// clang-format off
+static zend_function_entry maxminddb_methods[] = {
+ PHP_ME(MaxMind_Db_Reader, __construct, arginfo_maxmindbreader_construct,
+ ZEND_ACC_PUBLIC | ZEND_ACC_CTOR)
+ PHP_ME(MaxMind_Db_Reader, close, arginfo_maxmindbreader_void, ZEND_ACC_PUBLIC)
+ PHP_ME(MaxMind_Db_Reader, get, arginfo_maxmindbreader_get, ZEND_ACC_PUBLIC)
+ PHP_ME(MaxMind_Db_Reader, getWithPrefixLen, arginfo_maxmindbreader_get, ZEND_ACC_PUBLIC)
+ PHP_ME(MaxMind_Db_Reader, metadata, arginfo_maxmindbreader_void, ZEND_ACC_PUBLIC)
+ { NULL, NULL, NULL }
+};
+// clang-format on
+
+PHP_MINIT_FUNCTION(maxminddb) {
+ zend_class_entry ce;
+
+ 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;
+ memcpy(&maxminddb_obj_handlers,
+ zend_get_std_object_handlers(),
+ sizeof(zend_object_handlers));
+ maxminddb_obj_handlers.clone_obj = NULL;
+#ifdef ZEND_ENGINE_3
+ maxminddb_obj_handlers.offset = XtOffsetOf(maxminddb_obj, std);
+ maxminddb_obj_handlers.free_obj = maxminddb_free_storage;
+#endif
+ 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..b219777
--- /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..2beaf37
--- /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..85457c5
--- /dev/null
+++ b/vendor/maxmind-db/reader/src/MaxMind/Db/Reader.php
@@ -0,0 +1,327 @@
+<?php
+
+namespace MaxMind\Db;
+
+use BadMethodCallException;
+use Exception;
+use InvalidArgumentException;
+use MaxMind\Db\Reader\Decoder;
+use MaxMind\Db\Reader\InvalidDatabaseException;
+use MaxMind\Db\Reader\Metadata;
+use MaxMind\Db\Reader\Util;
+use UnexpectedValueException;
+
+/**
+ * Instances of this class provide a reader for the MaxMind DB format. IP
+ * addresses can be looked up using the get method.
+ */
+class Reader
+{
+ private static $DATA_SECTION_SEPARATOR_SIZE = 16;
+ private static $METADATA_START_MARKER = "\xAB\xCD\xEFMaxMind.com";
+ private static $METADATA_START_MARKER_LENGTH = 14;
+ private static $METADATA_MAX_SIZE = 131072; // 128 * 1024 = 128KB
+
+ private $decoder;
+ private $fileHandle;
+ private $fileSize;
+ private $ipV4Start;
+ private $metadata;
+
+ /**
+ * Constructs a Reader for the MaxMind DB format. The file passed to it must
+ * be a valid MaxMind DB file such as a GeoIp2 database file.
+ *
+ * @param string $database
+ * the MaxMind DB file to use
+ *
+ * @throws InvalidArgumentException for invalid database path or unknown arguments
+ * @throws \MaxMind\Db\Reader\InvalidDatabaseException
+ * if the database is invalid or there is an error reading
+ * from it
+ */
+ public function __construct($database)
+ {
+ if (\func_num_args() !== 1) {
+ throw new InvalidArgumentException(
+ 'The constructor takes exactly one argument.'
+ );
+ }
+
+ if (!is_readable($database)) {
+ throw new InvalidArgumentException(
+ "The file \"$database\" does not exist or is not readable."
+ );
+ }
+ $this->fileHandle = @fopen($database, 'rb');
+ if ($this->fileHandle === false) {
+ throw new InvalidArgumentException(
+ "Error opening \"$database\"."
+ );
+ }
+ $this->fileSize = @filesize($database);
+ if ($this->fileSize === false) {
+ throw new UnexpectedValueException(
+ "Error determining the size of \"$database\"."
+ );
+ }
+
+ $start = $this->findMetadataStart($database);
+ $metadataDecoder = new Decoder($this->fileHandle, $start);
+ list($metadataArray) = $metadataDecoder->decode($start);
+ $this->metadata = new Metadata($metadataArray);
+ $this->decoder = new Decoder(
+ $this->fileHandle,
+ $this->metadata->searchTreeSize + self::$DATA_SECTION_SEPARATOR_SIZE
+ );
+ $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($ipAddress)
+ {
+ if (\func_num_args() !== 1) {
+ throw new InvalidArgumentException(
+ 'Method takes exactly one argument.'
+ );
+ }
+ list($record) = $this->getWithPrefixLen($ipAddress);
+
+ return $record;
+ }
+
+ /**
+ * Retrieves the record for the IP address and its associated network prefix length.
+ *
+ * @param string $ipAddress
+ * the IP address to look up
+ *
+ * @throws BadMethodCallException if this method is called on a closed database
+ * @throws InvalidArgumentException if something other than a single IP address is passed to the method
+ * @throws InvalidDatabaseException
+ * if the database is invalid or there is an error reading
+ * from it
+ *
+ * @return array an array where the first element is the record and the
+ * second the network prefix length for the record
+ */
+ public function getWithPrefixLen($ipAddress)
+ {
+ if (\func_num_args() !== 1) {
+ throw new InvalidArgumentException(
+ 'Method takes exactly one argument.'
+ );
+ }
+
+ if (!\is_resource($this->fileHandle)) {
+ throw new BadMethodCallException(
+ 'Attempt to read from a closed MaxMind DB.'
+ );
+ }
+
+ if (!filter_var($ipAddress, FILTER_VALIDATE_IP)) {
+ throw new InvalidArgumentException(
+ "The value \"$ipAddress\" is not a valid IP address."
+ );
+ }
+
+ list($pointer, $prefixLen) = $this->findAddressInTree($ipAddress);
+ if ($pointer === 0) {
+ return [null, $prefixLen];
+ }
+
+ return [$this->resolveDataPointer($pointer), $prefixLen];
+ }
+
+ private function findAddressInTree($ipAddress)
+ {
+ $rawAddress = unpack('C*', inet_pton($ipAddress));
+
+ $bitCount = \count($rawAddress) * 8;
+
+ // The first node of the tree is always node 0, at the beginning of the
+ // value
+ $node = 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];
+ } elseif ($node > $nodeCount) {
+ // Record is a data pointer
+ return [$node, $i];
+ }
+ throw new InvalidDatabaseException('Something bad happened');
+ }
+
+ private function ipV4StartNode()
+ {
+ // 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($nodeNumber, $index)
+ {
+ $baseOffset = $nodeNumber * $this->metadata->nodeByteSize;
+
+ switch ($this->metadata->recordSize) {
+ case 24:
+ $bytes = Util::read($this->fileHandle, $baseOffset + $index * 3, 3);
+ list(, $node) = unpack('N', "\x00" . $bytes);
+
+ return $node;
+ case 28:
+ $bytes = Util::read($this->fileHandle, $baseOffset + 3 * $index, 4);
+ if ($index === 0) {
+ $middle = (0xF0 & \ord($bytes[3])) >> 4;
+ } else {
+ $middle = 0x0F & \ord($bytes[0]);
+ }
+ list(, $node) = unpack('N', \chr($middle) . substr($bytes, $index, 3));
+
+ return $node;
+ case 32:
+ $bytes = Util::read($this->fileHandle, $baseOffset + $index * 4, 4);
+ list(, $node) = unpack('N', $bytes);
+
+ return $node;
+ default:
+ throw new InvalidDatabaseException(
+ 'Unknown record size: '
+ . $this->metadata->recordSize
+ );
+ }
+ }
+
+ private function resolveDataPointer($pointer)
+ {
+ $resolved = $pointer - $this->metadata->nodeCount
+ + $this->metadata->searchTreeSize;
+ if ($resolved >= $this->fileSize) {
+ throw new InvalidDatabaseException(
+ "The MaxMind DB file's search tree is corrupt"
+ );
+ }
+
+ list($data) = $this->decoder->decode($resolved);
+
+ return $data;
+ }
+
+ /*
+ * This is an extremely naive but reasonably readable implementation. There
+ * are much faster algorithms (e.g., Boyer-Moore) for this if speed is ever
+ * an issue, but I suspect it won't be.
+ */
+ private function findMetadataStart($filename)
+ {
+ $handle = $this->fileHandle;
+ $fstat = fstat($handle);
+ $fileSize = $fstat['size'];
+ $marker = self::$METADATA_START_MARKER;
+ $markerLength = self::$METADATA_START_MARKER_LENGTH;
+
+ $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()
+ {
+ if (\func_num_args()) {
+ throw new InvalidArgumentException(
+ 'Method takes no arguments.'
+ );
+ }
+
+ // Not technically required, but this makes it consistent with
+ // C extension and it allows us to change our implementation later.
+ if (!\is_resource($this->fileHandle)) {
+ throw new BadMethodCallException(
+ 'Attempt to read from a closed MaxMind DB.'
+ );
+ }
+
+ return $this->metadata;
+ }
+
+ /**
+ * Closes the MaxMind DB and returns resources to the system.
+ *
+ * @throws Exception
+ * if an I/O error occurs
+ */
+ public function close()
+ {
+ if (!\is_resource($this->fileHandle)) {
+ throw new BadMethodCallException(
+ 'Attempt to close a closed MaxMind DB.'
+ );
+ }
+ fclose($this->fileHandle);
+ }
+}
diff --git a/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..8f451b8
--- /dev/null
+++ b/vendor/maxmind-db/reader/src/MaxMind/Db/Reader/Decoder.php
@@ -0,0 +1,381 @@
+<?php
+
+declare(strict_types=1);
+
+namespace MaxMind\Db\Reader;
+
+// @codingStandardsIgnoreLine
+use RuntimeException;
+
+/*
+ * @ignore
+ *
+ * We subtract 1 from the log to protect against precision loss.
+ */
+\define(__NAMESPACE__ . '\_MM_MAX_INT_BYTES', (int) ((log(\PHP_INT_MAX, 2) - 1) / 8));
+
+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. _MM_MAX_INT_BYTES 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 <= _MM_MAX_INT_BYTES
+ || ($byteLength === _MM_MAX_INT_BYTES + 1 && (\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..543fde4
--- /dev/null
+++ b/vendor/maxmind-db/reader/src/MaxMind/Db/Reader/InvalidDatabaseException.php
@@ -0,0 +1,12 @@
+<?php
+
+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..94a5592
--- /dev/null
+++ b/vendor/maxmind-db/reader/src/MaxMind/Db/Reader/Metadata.php
@@ -0,0 +1,88 @@
+<?php
+
+namespace MaxMind\Db\Reader;
+
+/**
+ * This class provides the metadata for the MaxMind DB file.
+ *
+ * @property int $nodeCount This is an unsigned 32-bit
+ * integer indicating the number of
+ * nodes in the search tree.
+ * @property int $recordSize This is an unsigned 16-bit
+ * integer. It indicates the number
+ * of bits in a record in the search
+ * tree. Note that each node
+ * consists of two records.
+ * @property int $ipVersion This is an unsigned 16-bit
+ * integer which is always 4 or 6.
+ * It indicates whether the database
+ * contains IPv4 or IPv6 address
+ * data.
+ * @property string $databaseType This is a string that indicates
+ * the structure of each data record
+ * associated with an IP address.
+ * The actual definition of these
+ * structures is left up to the
+ * database creator.
+ * @property array $languages An array of strings, each of
+ * which is a language code. A given
+ * record may contain data items
+ * that have been localized to some
+ * or all of these languages. This
+ * may be undefined.
+ * @property int $binaryFormatMajorVersion This is an unsigned 16-bit
+ * integer indicating the major
+ * version number for the database's
+ * binary format.
+ * @property int $binaryFormatMinorVersion This is an unsigned 16-bit
+ * integer indicating the minor
+ * version number for the database's
+ * binary format.
+ * @property int $buildEpoch This is an unsigned 64-bit
+ * integer that contains the
+ * database build timestamp as a
+ * Unix epoch value.
+ * @property array $description This key will always point to a
+ * map (associative array). The keys
+ * of that map will be language
+ * codes, and the values will be a
+ * description in that language as a
+ * UTF-8 string. May be undefined
+ * for some databases.
+ */
+class Metadata
+{
+ private $binaryFormatMajorVersion;
+ private $binaryFormatMinorVersion;
+ private $buildEpoch;
+ private $databaseType;
+ private $description;
+ private $ipVersion;
+ private $languages;
+ private $nodeByteSize;
+ private $nodeCount;
+ private $recordSize;
+ private $searchTreeSize;
+
+ public function __construct($metadata)
+ {
+ $this->binaryFormatMajorVersion =
+ $metadata['binary_format_major_version'];
+ $this->binaryFormatMinorVersion =
+ $metadata['binary_format_minor_version'];
+ $this->buildEpoch = $metadata['build_epoch'];
+ $this->databaseType = $metadata['database_type'];
+ $this->languages = $metadata['languages'];
+ $this->description = $metadata['description'];
+ $this->ipVersion = $metadata['ip_version'];
+ $this->nodeCount = $metadata['node_count'];
+ $this->recordSize = $metadata['record_size'];
+ $this->nodeByteSize = $this->recordSize / 4;
+ $this->searchTreeSize = $this->nodeCount * $this->nodeByteSize;
+ }
+
+ public function __get($var)
+ {
+ return $this->$var;
+ }
+}
diff --git a/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..149a5c4
--- /dev/null
+++ b/vendor/maxmind-db/reader/src/MaxMind/Db/Reader/Util.php
@@ -0,0 +1,26 @@
+<?php
+
+namespace MaxMind\Db\Reader;
+
+class Util
+{
+ public static function read($stream, $offset, $numberOfBytes)
+ {
+ if ($numberOfBytes === 0) {
+ return '';
+ }
+ if (fseek($stream, $offset) === 0) {
+ $value = fread($stream, $numberOfBytes);
+
+ // We check that the number of bytes read is equal to the number
+ // asked for. We use ftell as getting the length of $value is
+ // much slower.
+ if (ftell($stream) - $offset === $numberOfBytes) {
+ return $value;
+ }
+ }
+ throw new InvalidDatabaseException(
+ 'The MaxMind DB file contains bad data'
+ );
+ }
+}