
commit
2ccad3b139
33 changed files with 4417 additions and 0 deletions
@ -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 |
@ -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. |
@ -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. |
@ -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'); |
@ -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" |
|||
} |
|||
} |
|||
} |
@ -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 |
@ -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'); |
|||
} |
|||
} |
@ -0,0 +1,806 @@ |
|||
/* 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 |
|||
|
|||
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(getThis()); |
|||
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(getThis()); |
|||
|
|||
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 |
@ -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 |
@ -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 |
@ -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) |
@ -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.* |
@ -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> |
@ -0,0 +1,7 @@ |
|||
parameters: |
|||
level: 6 |
|||
paths: |
|||
- src |
|||
- tests |
|||
checkMissingIterableValueType: false |
|||
|
@ -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; |
|||
|
|||