update v 1.0.7.5
This commit is contained in:
20
vendor/maxmind-db/reader/.coveralls-phpunit.xml.dist
vendored
Normal file
20
vendor/maxmind-db/reader/.coveralls-phpunit.xml.dist
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<phpunit bootstrap="./tests/bootstrap.php" colors="true">
|
||||
<testsuites>
|
||||
<testsuite name="MaxMind DB Test Suite">
|
||||
<directory suffix="Test.php">./tests/MaxMind/Db/Test/</directory>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
|
||||
<filter>
|
||||
<whitelist>
|
||||
<directory suffix=".php">./src/MaxMind/Db/</directory>
|
||||
</whitelist>
|
||||
</filter>
|
||||
|
||||
<logging>
|
||||
<log type="coverage-clover" target="build/logs/clover.xml"/>
|
||||
</logging>
|
||||
|
||||
</phpunit>
|
33
vendor/maxmind-db/reader/.gitignore
vendored
Normal file
33
vendor/maxmind-db/reader/.gitignore
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
*~
|
||||
*.la
|
||||
*.lo
|
||||
*.o
|
||||
*.old
|
||||
*.sublime-*
|
||||
*.sw?
|
||||
.deps
|
||||
.gh-pages
|
||||
/.idea
|
||||
.libs/
|
||||
_site
|
||||
ac*.m4
|
||||
autom4te.cache/
|
||||
build/
|
||||
composer.lock
|
||||
composer.phar
|
||||
config.[^mw]*
|
||||
configure*
|
||||
core
|
||||
install-sh
|
||||
libtool
|
||||
ltmain.sh
|
||||
Makefile*
|
||||
missing
|
||||
mkinstalldirs
|
||||
modules/
|
||||
phpunit.xml
|
||||
run-tests.php
|
||||
t.php
|
||||
/test.php
|
||||
tmp-php.ini
|
||||
vendor/
|
3
vendor/maxmind-db/reader/.gitmodules
vendored
Normal file
3
vendor/maxmind-db/reader/.gitmodules
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
[submodule "tests/data"]
|
||||
path = tests/data
|
||||
url = git://github.com/maxmind/MaxMind-DB.git
|
17
vendor/maxmind-db/reader/.travis-build.sh
vendored
Normal file
17
vendor/maxmind-db/reader/.travis-build.sh
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -e
|
||||
set -x
|
||||
|
||||
if [ "hhvm" != $TRAVIS_PHP_VERSION ]
|
||||
then
|
||||
export CFLAGS="-L$HOME/libmaxminddb/lib"
|
||||
export CPPFLAGS="-I$HOME/libmaxminddb/include"
|
||||
cd ext
|
||||
phpize
|
||||
./configure --with-maxminddb --enable-maxminddb-debug
|
||||
make clean
|
||||
make
|
||||
NO_INTERACTION=1 make test
|
||||
cd ..
|
||||
fi
|
18
vendor/maxmind-db/reader/.travis-install-prereqs.sh
vendored
Normal file
18
vendor/maxmind-db/reader/.travis-install-prereqs.sh
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -e
|
||||
set -x
|
||||
|
||||
git submodule update --init --recursive
|
||||
composer self-update
|
||||
composer install --dev -n --prefer-source
|
||||
if [ "hhvm" != "$TRAVIS_PHP_VERSION" ]
|
||||
then
|
||||
mkdir -p "$HOME/libmaxminddb"
|
||||
git clone --recursive git://github.com/maxmind/libmaxminddb
|
||||
cd libmaxminddb
|
||||
./bootstrap
|
||||
./configure --prefix="$HOME/libmaxminddb"
|
||||
make
|
||||
make install
|
||||
fi
|
19
vendor/maxmind-db/reader/.travis-test.sh
vendored
Normal file
19
vendor/maxmind-db/reader/.travis-test.sh
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -e
|
||||
set -x
|
||||
|
||||
mkdir -p build/logs
|
||||
./vendor/bin/phpunit -c .coveralls-phpunit.xml.dist
|
||||
|
||||
if [ "hhvm" != "$TRAVIS_PHP_VERSION" ]
|
||||
then
|
||||
echo "mbstring.internal_encoding=utf-8" >> ~/.phpenv/versions/"$(phpenv version-name)"/etc/php.ini
|
||||
echo "mbstring.func_overload = 7" >> ~/.phpenv/versions/"$(phpenv version-name)"/etc/php.ini
|
||||
./vendor/bin/phpunit
|
||||
|
||||
echo "extension = ext/modules/maxminddb.so" >> ~/.phpenv/versions/"$(phpenv version-name)"/etc/php.ini
|
||||
./vendor/bin/phpunit
|
||||
fi
|
||||
|
||||
./vendor/bin/phpcs --standard=PSR2 src/
|
43
vendor/maxmind-db/reader/.travis.yml
vendored
Normal file
43
vendor/maxmind-db/reader/.travis.yml
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
language: php
|
||||
|
||||
php:
|
||||
- 5.3
|
||||
- 5.4
|
||||
- 5.5
|
||||
- 5.6
|
||||
- 7.0
|
||||
- hhvm
|
||||
|
||||
before_install:
|
||||
- ./.travis-install-prereqs.sh
|
||||
|
||||
install:
|
||||
- ./.travis-build.sh
|
||||
- phpenv rehash
|
||||
|
||||
|
||||
script:
|
||||
- ./.travis-test.sh
|
||||
|
||||
after_script:
|
||||
- php vendor/bin/coveralls
|
||||
|
||||
notifications:
|
||||
email:
|
||||
recipients:
|
||||
- dev-ci@maxmind.com
|
||||
on_success: change
|
||||
on_failure: always
|
||||
|
||||
env:
|
||||
global:
|
||||
- secure: "RMIBN2tNKlrGA07coRW4B9m9jCobrYxDkEq3T3jGoGtXgQe/Mr3bI/4zQo7U3bvVTSF90lzkWbxATY45GQXRxWC7Ed2HI2jwUF96CXecdRhKiE9x051HsvXakvbODPLocV7/2LOZqz+eXCUeazLgRaSrIhAqMddFqMQSSM5STlc="
|
||||
|
||||
addons:
|
||||
coverity_scan:
|
||||
project:
|
||||
name: "maxmind/MaxMind-DB-Reader-php"
|
||||
description: "Build submitted via Travis CI"
|
||||
notification_email: dev-ci@maxmind.com
|
||||
build_command: "./.travis-build.sh"
|
||||
branch_pattern: .*coverity.*
|
80
vendor/maxmind-db/reader/CHANGELOG.md
vendored
Normal file
80
vendor/maxmind-db/reader/CHANGELOG.md
vendored
Normal file
@@ -0,0 +1,80 @@
|
||||
CHANGELOG
|
||||
=========
|
||||
|
||||
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
|
202
vendor/maxmind-db/reader/LICENSE
vendored
Normal file
202
vendor/maxmind-db/reader/LICENSE
vendored
Normal file
@@ -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.
|
140
vendor/maxmind-db/reader/README.md
vendored
Normal file
140
vendor/maxmind-db/reader/README.md
vendored
Normal file
@@ -0,0 +1,140 @@
|
||||
# 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 ##
|
||||
|
||||
We recommend installing this package with [Composer](http://getcomposer.org/).
|
||||
|
||||
### Download Composer ###
|
||||
|
||||
To download Composer, run in the root directory of your project:
|
||||
|
||||
```bash
|
||||
curl -sS https://getcomposer.org/installer | php
|
||||
```
|
||||
|
||||
You should now have the file `composer.phar` in your project directory.
|
||||
|
||||
### Install Dependencies ###
|
||||
|
||||
Run in your project root:
|
||||
|
||||
```
|
||||
php composer.phar require maxmind-db/reader:~1.0
|
||||
```
|
||||
|
||||
You should now have the files `composer.json` and `composer.lock` as well as
|
||||
the directory `vendor` in your project directory. If you use a version control
|
||||
system, `composer.json` should be added to it.
|
||||
|
||||
### Require Autoloader ###
|
||||
|
||||
After installing the dependencies, you need to require the Composer autoloader
|
||||
from your code:
|
||||
|
||||
```php
|
||||
require 'vendor/autoload.php';
|
||||
```
|
||||
|
||||
## Usage ##
|
||||
|
||||
## Example ##
|
||||
|
||||
```php
|
||||
<?php
|
||||
require_once 'vendor/autoload.php';
|
||||
|
||||
use MaxMind\Db\Reader;
|
||||
|
||||
$ipAddress = '24.24.24.24';
|
||||
$databaseFile = 'GeoIP2-City.mmdb';
|
||||
|
||||
$reader = new Reader($databaseFile);
|
||||
|
||||
print_r($reader->get($ipAddress));
|
||||
|
||||
$reader->close()
|
||||
```
|
||||
|
||||
## Optional PHP C Extension ##
|
||||
|
||||
MaxMind provides an optional C extension that is a drop-in replacement for for
|
||||
`MaxMind\Db\Reader`. In order to use this extension, you must install the
|
||||
Reader API as described above and install the extension as described below. If
|
||||
you are using an autoloader, no changes to your code should be necessary.
|
||||
|
||||
### Installing Extension ###
|
||||
|
||||
First install [libmaxminddb](https://github.com/maxmind/libmaxminddb) as
|
||||
described in its [README.md
|
||||
file](https://github.com/maxmind/libmaxminddb/blob/master/README.md#installing-from-a-tarball).
|
||||
After successfully installing libmaxmindb, run the following commands from the
|
||||
top-level directory of this distribution:
|
||||
|
||||
```
|
||||
cd ext
|
||||
phpize
|
||||
./configure
|
||||
make
|
||||
make test
|
||||
sudo make install
|
||||
```
|
||||
|
||||
You then must load your extension. The recommend method is to add the
|
||||
following to your `php.ini` file:
|
||||
|
||||
```
|
||||
extension=maxminddb.so
|
||||
```
|
||||
|
||||
Note: You may need to install the PHP development package on your OS such as
|
||||
php5-dev for Debian-based systems or php-devel for RedHat/Fedora-based ones.
|
||||
|
||||
## 128-bit Integer Support ##
|
||||
|
||||
The MaxMind DB format includes 128-bit unsigned integer as a type. Although
|
||||
no MaxMind-distributed database currently makes use of this type, both the
|
||||
pure PHP reader and the C extension support this type. The pure PHP reader
|
||||
requires gmp or bcmath to read databases with 128-bit unsigned integers.
|
||||
|
||||
The integer is currently returned as a hexadecimal string (prefixed with "0x")
|
||||
by the C extension and a decimal string (no prefix) by the pure PHP reader.
|
||||
Any change to make the reader implementations always return either a
|
||||
hexadecimal or decimal representation of the integer will NOT be considered a
|
||||
breaking change.
|
||||
|
||||
## Support ##
|
||||
|
||||
Please report all issues with this code using the [GitHub issue tracker]
|
||||
(https://github.com/maxmind/MaxMind-DB-Reader-php/issues).
|
||||
|
||||
If you are having an issue with a MaxMind service that is not specific to the
|
||||
client API, please see [our support page](http://www.maxmind.com/en/support).
|
||||
|
||||
## Requirements ##
|
||||
|
||||
This library requires PHP 5.3 or greater. Older versions of PHP are not
|
||||
supported. The pure PHP reader included with this library is works and is
|
||||
tested with HHVM.
|
||||
|
||||
The GMP or BCMath extension may be required to read some databases
|
||||
using the pure PHP API.
|
||||
|
||||
## Contributing ##
|
||||
|
||||
Patches and pull requests are encouraged. All code should follow the PSR-1 and
|
||||
PSR-2 style guidelines. Please include unit tests whenever possible.
|
||||
|
||||
## Versioning ##
|
||||
|
||||
The MaxMind DB Reader PHP API uses [Semantic Versioning](http://semver.org/).
|
||||
|
||||
## Copyright and License ##
|
||||
|
||||
This software is Copyright (c) 2014 by MaxMind, Inc.
|
||||
|
||||
This is free software, licensed under the Apache License, Version 2.0.
|
28
vendor/maxmind-db/reader/composer.json
vendored
Normal file
28
vendor/maxmind-db/reader/composer.json
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
{
|
||||
"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": "http://www.maxmind.com/"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": ">=5.3.1"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "4.2.*",
|
||||
"satooshi/php-coveralls": "dev-master",
|
||||
"squizlabs/php_codesniffer": "2.*"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-0": {
|
||||
"MaxMind": "src/"
|
||||
}
|
||||
}
|
||||
}
|
35
vendor/maxmind-db/reader/dev-bin/make-release.sh
vendored
Normal file
35
vendor/maxmind-db/reader/dev-bin/make-release.sh
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -e
|
||||
|
||||
VERSION=$(perl -MFile::Slurp::Tiny=read_file -MDateTime <<EOF
|
||||
use v5.16;
|
||||
my \$log = read_file(q{CHANGELOG.md});
|
||||
\$log =~ /\n(\d+\.\d+\.\d+) \((\d{4}-\d{2}-\d{2})\)\n/;
|
||||
die 'Release time is not today!' unless DateTime->now->ymd eq \$2;
|
||||
say \$1;
|
||||
EOF
|
||||
)
|
||||
|
||||
perl -pi -e "s/(?<=#define PHP_MAXMINDDB_VERSION \")\d+\.\d+\.\d+(?=\")/$VERSION/" ext/php_maxminddb.h
|
||||
|
||||
git diff
|
||||
|
||||
if [ -n "$(git status --porcelain)" ]; then
|
||||
git commit -m "Bumped version to $VERSION" -a
|
||||
fi
|
||||
|
||||
TAG="v$VERSION"
|
||||
echo "Creating tag $TAG"
|
||||
git tag -a -m "Release for $VERSION" "$TAG"
|
||||
|
||||
|
||||
read -p "Push to origin? (y/n) " SHOULD_PUSH
|
||||
|
||||
if [ "$SHOULD_PUSH" != "y" ]; then
|
||||
echo "Aborting"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
git push
|
||||
git push --tags
|
21
vendor/maxmind-db/reader/examples/benchmark.php
vendored
Normal file
21
vendor/maxmind-db/reader/examples/benchmark.php
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
require_once '../vendor/autoload.php';
|
||||
|
||||
use MaxMind\Db\Reader;
|
||||
|
||||
$reader = new Reader('GeoIP2-City.mmdb');
|
||||
$count = 10000;
|
||||
$startTime = microtime(true);
|
||||
for ($i = 0; $i < $count; $i++) {
|
||||
$ip = long2ip(rand(0, pow(2, 32) -1));
|
||||
$t = $reader->get($ip);
|
||||
if ($i % 1000 == 0) {
|
||||
print($i . ' ' . $ip . "\n");
|
||||
// print_r($t);
|
||||
}
|
||||
}
|
||||
$endTime = microtime(true);
|
||||
|
||||
$duration = $endTime - $startTime;
|
||||
print('Requests per second: ' . $count / $duration . "\n");
|
83
vendor/maxmind-db/reader/ext/.uncrustify.cfg
vendored
Normal file
83
vendor/maxmind-db/reader/ext/.uncrustify.cfg
vendored
Normal file
@@ -0,0 +1,83 @@
|
||||
#
|
||||
# uncrustify config file for the linux kernel
|
||||
#
|
||||
# - modified to use spaces instead of tabs
|
||||
# - added "sp_before_ptr_star = force"
|
||||
|
||||
indent_with_tabs = 0
|
||||
indent_columns = 4
|
||||
indent_label = 2 # pos: absolute col, neg: relative column
|
||||
indent_case_brace = 4
|
||||
code_width = 80
|
||||
|
||||
|
||||
#
|
||||
# inter-symbol newlines
|
||||
#
|
||||
|
||||
nl_enum_brace = remove # "enum {" vs "enum \n {"
|
||||
nl_union_brace = remove # "union {" vs "union \n {"
|
||||
nl_struct_brace = remove # "struct {" vs "struct \n {"
|
||||
nl_do_brace = remove # "do {" vs "do \n {"
|
||||
nl_if_brace = remove # "if () {" vs "if () \n {"
|
||||
nl_for_brace = remove # "for () {" vs "for () \n {"
|
||||
nl_else_brace = remove # "else {" vs "else \n {"
|
||||
nl_while_brace = remove # "while () {" vs "while () \n {"
|
||||
nl_switch_brace = remove # "switch () {" vs "switch () \n {"
|
||||
nl_brace_while = remove # "} while" vs "} \n while" - cuddle while
|
||||
nl_brace_else = remove # "} else" vs "} \n else" - cuddle else
|
||||
nl_func_var_def_blk = 0 # don't add newlines after a block of var declarations
|
||||
nl_fcall_brace = remove # "list_for_each() {" vs "list_for_each()\n{"
|
||||
nl_fdef_brace = force # "int foo() {" vs "int foo()\n{"
|
||||
nl_multi_line_define = true
|
||||
|
||||
|
||||
#
|
||||
# Source code modifications
|
||||
#
|
||||
|
||||
mod_paren_on_return = remove # "return 1;" vs "return (1);"
|
||||
mod_full_brace_if = force # "if (a) a--;" vs "if (a) { a--; }"
|
||||
mod_full_brace_for = force # "for () a--;" vs "for () { a--; }"
|
||||
mod_full_brace_do = force # "do a--; while ();" vs "do { a--; } while ();"
|
||||
mod_full_brace_while = force # "while (a) a--;" vs "while (a) { a--; }"
|
||||
mod_full_brace_nl = 3 # don't remove if more than 3 newlines
|
||||
|
||||
|
||||
#
|
||||
# inter-character spacing options
|
||||
#
|
||||
|
||||
# sp_return_paren = force # "return (1);" vs "return(1);"
|
||||
sp_sizeof_paren = remove # "sizeof (int)" vs "sizeof(int)"
|
||||
sp_before_sparen = force # "if (" vs "if("
|
||||
sp_after_sparen = force # "if () {" vs "if (){"
|
||||
sp_after_cast = remove # "(int) a" vs "(int)a"
|
||||
sp_inside_braces = force # "{ 1 }" vs "{1}"
|
||||
sp_inside_braces_struct = force # "{ 1 }" vs "{1}"
|
||||
sp_inside_braces_enum = force # "{ 1 }" vs "{1}"
|
||||
sp_assign = force
|
||||
sp_arith = force
|
||||
sp_bool = force
|
||||
sp_compare = force
|
||||
sp_assign = force
|
||||
sp_after_comma = force
|
||||
sp_func_def_paren = remove # "int foo (){" vs "int foo(){"
|
||||
sp_func_call_paren = remove # "foo (" vs "foo("
|
||||
sp_func_proto_paren = remove # "int foo ();" vs "int foo();"
|
||||
sp_before_ptr_star = force # "char *foo" vs "char* foo
|
||||
sp_between_ptr_star = remove # "char * *foo" vs "char **foo"
|
||||
|
||||
#
|
||||
# Aligning stuff
|
||||
#
|
||||
|
||||
align_with_tabs = FALSE # use tabs to align
|
||||
align_on_tabstop = FALSE # align on tabstops
|
||||
align_var_def_star_style = 1 # void *foo;
|
||||
align_var_struct_span = 0
|
||||
align_enum_equ_span = 4 # '=' in enum definition
|
||||
align_struct_init_span = 3 # align stuff in a structure init '= { }'
|
||||
align_right_cmt_span = 3
|
||||
align_nl_cont = true
|
||||
align_struct_init_span = 1
|
19
vendor/maxmind-db/reader/ext/config.m4
vendored
Normal file
19
vendor/maxmind-db/reader/ext/config.m4
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
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
|
||||
PHP_CHECK_LIBRARY(maxminddb, MMDB_open)
|
||||
|
||||
if test $PHP_MAXMINDDB_DEBUG != "no"; then
|
||||
CFLAGS="$CFLAGS -Wall -Wextra -Wno-unused-parameter -Wno-missing-field-initializers -Werror"
|
||||
fi
|
||||
|
||||
PHP_ADD_LIBRARY(maxminddb, 1, MAXMINDDB_SHARED_LIBADD)
|
||||
PHP_SUBST(MAXMINDDB_SHARED_LIBADD)
|
||||
|
||||
PHP_NEW_EXTENSION(maxminddb, maxminddb.c, $ext_shared)
|
||||
fi
|
565
vendor/maxmind-db/reader/ext/maxminddb.c
vendored
Normal file
565
vendor/maxmind-db/reader/ext/maxminddb.c
vendored
Normal file
@@ -0,0 +1,565 @@
|
||||
/* 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 <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
|
||||
|
||||
#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 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 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
|
||||
}
|
||||
|
||||
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 != 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 *)emalloc(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;
|
||||
}
|
||||
|
||||
PHP_METHOD(MaxMind_Db_Reader, get){
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
int gai_error = 0;
|
||||
int mmdb_error = MMDB_SUCCESS;
|
||||
MMDB_lookup_result_s result =
|
||||
MMDB_lookup_string(mmdb, ip_address, &gai_error,
|
||||
&mmdb_error);
|
||||
|
||||
if (MMDB_SUCCESS != gai_error) {
|
||||
THROW_EXCEPTION("InvalidArgumentException",
|
||||
"The value \"%s\" is not a valid IP address.",
|
||||
ip_address);
|
||||
return;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
MMDB_entry_data_list_s *entry_data_list = NULL;
|
||||
|
||||
if (!result.found_entry) {
|
||||
RETURN_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;
|
||||
} 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;
|
||||
}
|
||||
|
||||
handle_entry_data_list(entry_data_list, return_value TSRMLS_CC);
|
||||
MMDB_free_entry_data_list(entry_data_list);
|
||||
}
|
||||
|
||||
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);
|
||||
#ifdef 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:
|
||||
ZVAL_LONG(z_value, entry_data_list->entry_data.uint32);
|
||||
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_uint64(const MMDB_entry_data_list_s *entry_data_list,
|
||||
zval *z_value TSRMLS_DC)
|
||||
{
|
||||
// We return it as a string because PHP uses signed longs
|
||||
char *int_str;
|
||||
spprintf(&int_str, 0, "%" PRIu64,
|
||||
entry_data_list->entry_data.uint64);
|
||||
CHECK_ALLOCATED(int_str);
|
||||
|
||||
_ZVAL_STRING(z_value, int_str);
|
||||
efree(int_str);
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
/* *INDENT-OFF* */
|
||||
static zend_function_entry maxminddb_methods[] = {
|
||||
PHP_ME(MaxMind_Db_Reader, __construct, NULL,
|
||||
ZEND_ACC_PUBLIC | ZEND_ACC_CTOR)
|
||||
PHP_ME(MaxMind_Db_Reader, close, NULL, ZEND_ACC_PUBLIC)
|
||||
PHP_ME(MaxMind_Db_Reader, get, NULL, ZEND_ACC_PUBLIC)
|
||||
PHP_ME(MaxMind_Db_Reader, metadata, NULL, ZEND_ACC_PUBLIC)
|
||||
{ NULL, NULL, NULL }
|
||||
};
|
||||
/* *INDENT-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;
|
||||
maxminddb_ce->ce_flags |= ZEND_ACC_FINAL;
|
||||
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
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
zend_module_entry maxminddb_module_entry = {
|
||||
STANDARD_MODULE_HEADER,
|
||||
PHP_MAXMINDDB_EXTNAME,
|
||||
NULL,
|
||||
PHP_MINIT(maxminddb),
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
PHP_MAXMINDDB_VERSION,
|
||||
STANDARD_MODULE_PROPERTIES
|
||||
};
|
||||
|
||||
#ifdef COMPILE_DL_MAXMINDDB
|
||||
ZEND_GET_MODULE(maxminddb)
|
||||
#endif
|
24
vendor/maxmind-db/reader/ext/php_maxminddb.h
vendored
Normal file
24
vendor/maxmind-db/reader/ext/php_maxminddb.h
vendored
Normal file
@@ -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.1.0"
|
||||
#define PHP_MAXMINDDB_EXTNAME "maxminddb"
|
||||
|
||||
extern zend_module_entry maxminddb_module_entry;
|
||||
#define phpext_maxminddb_ptr &maxminddb_module_entry
|
||||
|
||||
#endif
|
10
vendor/maxmind-db/reader/ext/tests/001-load.phpt
vendored
Normal file
10
vendor/maxmind-db/reader/ext/tests/001-load.phpt
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
--TEST--
|
||||
Check for maxminddb presence
|
||||
--SKIPIF--
|
||||
<?php if (!extension_loaded("maxminddb")) print "skip"; ?>
|
||||
--FILE--
|
||||
<?php
|
||||
echo "maxminddb extension is available";
|
||||
?>
|
||||
--EXPECT--
|
||||
maxminddb extension is available
|
15
vendor/maxmind-db/reader/phpunit.xml.dist
vendored
Normal file
15
vendor/maxmind-db/reader/phpunit.xml.dist
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<phpunit bootstrap="./tests/bootstrap.php" colors="true">
|
||||
<testsuites>
|
||||
<testsuite name="MaxMind DB Test Suite">
|
||||
<directory suffix="Test.php">./tests/MaxMind/Db/Test/</directory>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
|
||||
<filter>
|
||||
<whitelist>
|
||||
<directory suffix=".php">./src/MaxMind/Db/</directory>
|
||||
</whitelist>
|
||||
</filter>
|
||||
</phpunit>
|
296
vendor/maxmind-db/reader/src/MaxMind/Db/Reader.php
vendored
Normal file
296
vendor/maxmind-db/reader/src/MaxMind/Db/Reader.php
vendored
Normal file
@@ -0,0 +1,296 @@
|
||||
<?php
|
||||
|
||||
namespace MaxMind\Db;
|
||||
|
||||
use MaxMind\Db\Reader\Decoder;
|
||||
use MaxMind\Db\Reader\InvalidDatabaseException;
|
||||
use MaxMind\Db\Reader\Metadata;
|
||||
use MaxMind\Db\Reader\Util;
|
||||
|
||||
/**
|
||||
* Instances of this class provide a reader for the MaxMind DB format. IP
|
||||
* addresses can be looked up using the <code>get</code> method.
|
||||
*/
|
||||
class Reader
|
||||
{
|
||||
private static $DATA_SECTION_SEPARATOR_SIZE = 16;
|
||||
private static $METADATA_START_MARKER = "\xAB\xCD\xEFMaxMind.com";
|
||||
private static $METADATA_START_MARKER_LENGTH = 14;
|
||||
|
||||
private $decoder;
|
||||
private $fileHandle;
|
||||
private $fileSize;
|
||||
private $ipV4Start;
|
||||
private $metadata;
|
||||
|
||||
/**
|
||||
* Constructs a Reader for the MaxMind DB format. The file passed to it must
|
||||
* be a valid MaxMind DB file such as a GeoIp2 database file.
|
||||
*
|
||||
* @param string $database
|
||||
* the MaxMind DB file to use.
|
||||
* @throws \InvalidArgumentException for invalid database path or unknown arguments
|
||||
* @throws \MaxMind\Db\Reader\InvalidDatabaseException
|
||||
* if the database is invalid or there is an error reading
|
||||
* from it.
|
||||
*/
|
||||
public function __construct($database)
|
||||
{
|
||||
if (func_num_args() != 1) {
|
||||
throw new \InvalidArgumentException(
|
||||
'The constructor takes exactly one argument.'
|
||||
);
|
||||
}
|
||||
|
||||
if (!is_readable($database)) {
|
||||
throw new \InvalidArgumentException(
|
||||
"The file \"$database\" does not exist or is not readable."
|
||||
);
|
||||
}
|
||||
$this->fileHandle = @fopen($database, 'rb');
|
||||
if ($this->fileHandle === false) {
|
||||
throw new \InvalidArgumentException(
|
||||
"Error opening \"$database\"."
|
||||
);
|
||||
}
|
||||
$this->fileSize = @filesize($database);
|
||||
if ($this->fileSize === false) {
|
||||
throw new \UnexpectedValueException(
|
||||
"Error determining the size of \"$database\"."
|
||||
);
|
||||
}
|
||||
|
||||
$start = $this->findMetadataStart($database);
|
||||
$metadataDecoder = new Decoder($this->fileHandle, $start);
|
||||
list($metadataArray) = $metadataDecoder->decode($start);
|
||||
$this->metadata = new Metadata($metadataArray);
|
||||
$this->decoder = new Decoder(
|
||||
$this->fileHandle,
|
||||
$this->metadata->searchTreeSize + self::$DATA_SECTION_SEPARATOR_SIZE
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Looks up the <code>address</code> in the MaxMind DB.
|
||||
*
|
||||
* @param string $ipAddress
|
||||
* the IP address to look up.
|
||||
* @return array the record for the IP address.
|
||||
* @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.
|
||||
*/
|
||||
public function get($ipAddress)
|
||||
{
|
||||
if (func_num_args() != 1) {
|
||||
throw new \InvalidArgumentException(
|
||||
'Method takes exactly one argument.'
|
||||
);
|
||||
}
|
||||
|
||||
if (!is_resource($this->fileHandle)) {
|
||||
throw new \BadMethodCallException(
|
||||
'Attempt to read from a closed MaxMind DB.'
|
||||
);
|
||||
}
|
||||
|
||||
if (!filter_var($ipAddress, FILTER_VALIDATE_IP)) {
|
||||
throw new \InvalidArgumentException(
|
||||
"The value \"$ipAddress\" is not a valid IP address."
|
||||
);
|
||||
}
|
||||
|
||||
if ($this->metadata->ipVersion == 4 && strrpos($ipAddress, ':')) {
|
||||
throw new \InvalidArgumentException(
|
||||
"Error looking up $ipAddress. You attempted to look up an"
|
||||
. " IPv6 address in an IPv4-only database."
|
||||
);
|
||||
}
|
||||
$pointer = $this->findAddressInTree($ipAddress);
|
||||
if ($pointer == 0) {
|
||||
return null;
|
||||
}
|
||||
return $this->resolveDataPointer($pointer);
|
||||
}
|
||||
|
||||
private function findAddressInTree($ipAddress)
|
||||
{
|
||||
// XXX - could simplify. Done as a byte array to ease porting
|
||||
$rawAddress = array_merge(unpack('C*', inet_pton($ipAddress)));
|
||||
|
||||
$bitCount = count($rawAddress) * 8;
|
||||
|
||||
// The first node of the tree is always node 0, at the beginning of the
|
||||
// value
|
||||
$node = $this->startNode($bitCount);
|
||||
|
||||
for ($i = 0; $i < $bitCount; $i++) {
|
||||
if ($node >= $this->metadata->nodeCount) {
|
||||
break;
|
||||
}
|
||||
$tempBit = 0xFF & $rawAddress[$i >> 3];
|
||||
$bit = 1 & ($tempBit >> 7 - ($i % 8));
|
||||
|
||||
$node = $this->readNode($node, $bit);
|
||||
}
|
||||
if ($node == $this->metadata->nodeCount) {
|
||||
// Record is empty
|
||||
return 0;
|
||||
} elseif ($node > $this->metadata->nodeCount) {
|
||||
// Record is a data pointer
|
||||
return $node;
|
||||
}
|
||||
throw new InvalidDatabaseException("Something bad happened");
|
||||
}
|
||||
|
||||
|
||||
private function startNode($length)
|
||||
{
|
||||
// Check if we are looking up an IPv4 address in an IPv6 tree. If this
|
||||
// is the case, we can skip over the first 96 nodes.
|
||||
if ($this->metadata->ipVersion == 6 && $length == 32) {
|
||||
return $this->ipV4StartNode();
|
||||
}
|
||||
// The first node of the tree is always node 0, at the beginning of the
|
||||
// value
|
||||
return 0;
|
||||
}
|
||||
|
||||
private function ipV4StartNode()
|
||||
{
|
||||
// This is a defensive check. There is no reason to call this when you
|
||||
// have an IPv4 tree.
|
||||
if ($this->metadata->ipVersion == 4) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ($this->ipV4Start != 0) {
|
||||
return $this->ipV4Start;
|
||||
}
|
||||
$node = 0;
|
||||
|
||||
for ($i = 0; $i < 96 && $node < $this->metadata->nodeCount; $i++) {
|
||||
$node = $this->readNode($node, 0);
|
||||
}
|
||||
$this->ipV4Start = $node;
|
||||
return $node;
|
||||
}
|
||||
|
||||
private function readNode($nodeNumber, $index)
|
||||
{
|
||||
$baseOffset = $nodeNumber * $this->metadata->nodeByteSize;
|
||||
|
||||
// XXX - probably could condense this.
|
||||
switch ($this->metadata->recordSize) {
|
||||
case 24:
|
||||
$bytes = Util::read($this->fileHandle, $baseOffset + $index * 3, 3);
|
||||
list(, $node) = unpack('N', "\x00" . $bytes);
|
||||
return $node;
|
||||
case 28:
|
||||
$middleByte = Util::read($this->fileHandle, $baseOffset + 3, 1);
|
||||
list(, $middle) = unpack('C', $middleByte);
|
||||
if ($index == 0) {
|
||||
$middle = (0xF0 & $middle) >> 4;
|
||||
} else {
|
||||
$middle = 0x0F & $middle;
|
||||
}
|
||||
$bytes = Util::read($this->fileHandle, $baseOffset + $index * 4, 3);
|
||||
list(, $node) = unpack('N', chr($middle) . $bytes);
|
||||
return $node;
|
||||
case 32:
|
||||
$bytes = Util::read($this->fileHandle, $baseOffset + $index * 4, 4);
|
||||
list(, $node) = unpack('N', $bytes);
|
||||
return $node;
|
||||
default:
|
||||
throw new InvalidDatabaseException(
|
||||
'Unknown record size: '
|
||||
. $this->metadata->recordSize
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private function resolveDataPointer($pointer)
|
||||
{
|
||||
$resolved = $pointer - $this->metadata->nodeCount
|
||||
+ $this->metadata->searchTreeSize;
|
||||
if ($resolved > $this->fileSize) {
|
||||
throw new InvalidDatabaseException(
|
||||
"The MaxMind DB file's search tree is corrupt"
|
||||
);
|
||||
}
|
||||
|
||||
list($data) = $this->decoder->decode($resolved);
|
||||
return $data;
|
||||
}
|
||||
|
||||
/*
|
||||
* This is an extremely naive but reasonably readable implementation. There
|
||||
* are much faster algorithms (e.g., Boyer-Moore) for this if speed is ever
|
||||
* an issue, but I suspect it won't be.
|
||||
*/
|
||||
private function findMetadataStart($filename)
|
||||
{
|
||||
$handle = $this->fileHandle;
|
||||
$fstat = fstat($handle);
|
||||
$fileSize = $fstat['size'];
|
||||
$marker = self::$METADATA_START_MARKER;
|
||||
$markerLength = self::$METADATA_START_MARKER_LENGTH;
|
||||
|
||||
for ($i = 0; $i < $fileSize - $markerLength + 1; $i++) {
|
||||
for ($j = 0; $j < $markerLength; $j++) {
|
||||
fseek($handle, $fileSize - $i - $j - 1);
|
||||
$matchBit = fgetc($handle);
|
||||
if ($matchBit != $marker[$markerLength - $j - 1]) {
|
||||
continue 2;
|
||||
}
|
||||
}
|
||||
return $fileSize - $i;
|
||||
}
|
||||
throw new InvalidDatabaseException(
|
||||
"Error opening database file ($filename). " .
|
||||
'Is this a valid MaxMind DB file?'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \InvalidArgumentException if arguments are passed to the method.
|
||||
* @throws \BadMethodCallException if the database has been closed.
|
||||
* @return Metadata object for the database.
|
||||
*/
|
||||
public function metadata()
|
||||
{
|
||||
if (func_num_args()) {
|
||||
throw new \InvalidArgumentException(
|
||||
'Method takes no arguments.'
|
||||
);
|
||||
}
|
||||
|
||||
// Not technically required, but this makes it consistent with
|
||||
// C extension and it allows us to change our implementation later.
|
||||
if (!is_resource($this->fileHandle)) {
|
||||
throw new \BadMethodCallException(
|
||||
'Attempt to read from a closed MaxMind DB.'
|
||||
);
|
||||
}
|
||||
|
||||
return $this->metadata;
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the MaxMind DB and returns resources to the system.
|
||||
*
|
||||
* @throws \Exception
|
||||
* if an I/O error occurs.
|
||||
*/
|
||||
public function close()
|
||||
{
|
||||
if (!is_resource($this->fileHandle)) {
|
||||
throw new \BadMethodCallException(
|
||||
'Attempt to close a closed MaxMind DB.'
|
||||
);
|
||||
}
|
||||
fclose($this->fileHandle);
|
||||
}
|
||||
}
|
309
vendor/maxmind-db/reader/src/MaxMind/Db/Reader/Decoder.php
vendored
Normal file
309
vendor/maxmind-db/reader/src/MaxMind/Db/Reader/Decoder.php
vendored
Normal file
@@ -0,0 +1,309 @@
|
||||
<?php
|
||||
|
||||
namespace MaxMind\Db\Reader;
|
||||
|
||||
use MaxMind\Db\Reader\InvalidDatabaseException;
|
||||
use MaxMind\Db\Reader\Util;
|
||||
|
||||
class Decoder
|
||||
{
|
||||
|
||||
private $fileStream;
|
||||
private $pointerBase;
|
||||
// This is only used for unit testing
|
||||
private $pointerTestHack;
|
||||
private $switchByteOrder;
|
||||
|
||||
private $types = array(
|
||||
0 => 'extended',
|
||||
1 => 'pointer',
|
||||
2 => 'utf8_string',
|
||||
3 => 'double',
|
||||
4 => 'bytes',
|
||||
5 => 'uint16',
|
||||
6 => 'uint32',
|
||||
7 => 'map',
|
||||
8 => 'int32',
|
||||
9 => 'uint64',
|
||||
10 => 'uint128',
|
||||
11 => 'array',
|
||||
12 => 'container',
|
||||
13 => 'end_marker',
|
||||
14 => 'boolean',
|
||||
15 => 'float',
|
||||
);
|
||||
|
||||
public function __construct(
|
||||
$fileStream,
|
||||
$pointerBase = 0,
|
||||
$pointerTestHack = false
|
||||
) {
|
||||
$this->fileStream = $fileStream;
|
||||
$this->pointerBase = $pointerBase;
|
||||
$this->pointerTestHack = $pointerTestHack;
|
||||
|
||||
$this->switchByteOrder = $this->isPlatformLittleEndian();
|
||||
}
|
||||
|
||||
|
||||
public function decode($offset)
|
||||
{
|
||||
list(, $ctrlByte) = unpack(
|
||||
'C',
|
||||
Util::read($this->fileStream, $offset, 1)
|
||||
);
|
||||
$offset++;
|
||||
|
||||
$type = $this->types[$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 == 'pointer') {
|
||||
list($pointer, $offset) = $this->decodePointer($ctrlByte, $offset);
|
||||
|
||||
// for unit testing
|
||||
if ($this->pointerTestHack) {
|
||||
return array($pointer);
|
||||
}
|
||||
|
||||
list($result) = $this->decode($pointer);
|
||||
|
||||
return array($result, $offset);
|
||||
}
|
||||
|
||||
if ($type == 'extended') {
|
||||
list(, $nextByte) = unpack(
|
||||
'C',
|
||||
Util::read($this->fileStream, $offset, 1)
|
||||
);
|
||||
|
||||
$typeNum = $nextByte + 7;
|
||||
|
||||
if ($typeNum < 8) {
|
||||
throw new InvalidDatabaseException(
|
||||
"Something went horribly wrong in the decoder. An extended type "
|
||||
. "resolved to a type number < 8 ("
|
||||
. $this->types[$typeNum]
|
||||
. ")"
|
||||
);
|
||||
}
|
||||
|
||||
$type = $this->types[$typeNum];
|
||||
$offset++;
|
||||
}
|
||||
|
||||
list($size, $offset) = $this->sizeFromCtrlByte($ctrlByte, $offset);
|
||||
|
||||
return $this->decodeByType($type, $offset, $size);
|
||||
}
|
||||
|
||||
private function decodeByType($type, $offset, $size)
|
||||
{
|
||||
switch ($type) {
|
||||
case 'map':
|
||||
return $this->decodeMap($size, $offset);
|
||||
case 'array':
|
||||
return $this->decodeArray($size, $offset);
|
||||
case 'boolean':
|
||||
return array($this->decodeBoolean($size), $offset);
|
||||
}
|
||||
|
||||
$newOffset = $offset + $size;
|
||||
$bytes = Util::read($this->fileStream, $offset, $size);
|
||||
switch ($type) {
|
||||
case 'utf8_string':
|
||||
return array($this->decodeString($bytes), $newOffset);
|
||||
case 'double':
|
||||
$this->verifySize(8, $size);
|
||||
return array($this->decodeDouble($bytes), $newOffset);
|
||||
case 'float':
|
||||
$this->verifySize(4, $size);
|
||||
return array($this->decodeFloat($bytes), $newOffset);
|
||||
case 'bytes':
|
||||
return array($bytes, $newOffset);
|
||||
case 'uint16':
|
||||
case 'uint32':
|
||||
return array($this->decodeUint($bytes), $newOffset);
|
||||
case 'int32':
|
||||
return array($this->decodeInt32($bytes), $newOffset);
|
||||
case 'uint64':
|
||||
case 'uint128':
|
||||
return array($this->decodeBigUint($bytes, $size), $newOffset);
|
||||
default:
|
||||
throw new InvalidDatabaseException(
|
||||
"Unknown or unexpected type: " . $type
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private function verifySize($expected, $actual)
|
||||
{
|
||||
if ($expected != $actual) {
|
||||
throw new InvalidDatabaseException(
|
||||
"The MaxMind DB file's data section contains bad data (unknown data type or corrupt data)"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private function decodeArray($size, $offset)
|
||||
{
|
||||
$array = array();
|
||||
|
||||
for ($i = 0; $i < $size; $i++) {
|
||||
list($value, $offset) = $this->decode($offset);
|
||||
array_push($array, $value);
|
||||
}
|
||||
|
||||
return array($array, $offset);
|
||||
}
|
||||
|
||||
private function decodeBoolean($size)
|
||||
{
|
||||
return $size == 0 ? false : true;
|
||||
}
|
||||
|
||||
private function decodeDouble($bits)
|
||||
{
|
||||
// XXX - Assumes IEEE 754 double on platform
|
||||
list(, $double) = unpack('d', $this->maybeSwitchByteOrder($bits));
|
||||
return $double;
|
||||
}
|
||||
|
||||
private function decodeFloat($bits)
|
||||
{
|
||||
// XXX - Assumes IEEE 754 floats on platform
|
||||
list(, $float) = unpack('f', $this->maybeSwitchByteOrder($bits));
|
||||
return $float;
|
||||
}
|
||||
|
||||
private function decodeInt32($bytes)
|
||||
{
|
||||
$bytes = $this->zeroPadLeft($bytes, 4);
|
||||
list(, $int) = unpack('l', $this->maybeSwitchByteOrder($bytes));
|
||||
return $int;
|
||||
}
|
||||
|
||||
private function decodeMap($size, $offset)
|
||||
{
|
||||
|
||||
$map = array();
|
||||
|
||||
for ($i = 0; $i < $size; $i++) {
|
||||
list($key, $offset) = $this->decode($offset);
|
||||
list($value, $offset) = $this->decode($offset);
|
||||
$map[$key] = $value;
|
||||
}
|
||||
|
||||
return array($map, $offset);
|
||||
}
|
||||
|
||||
private $pointerValueOffset = array(
|
||||
1 => 0,
|
||||
2 => 2048,
|
||||
3 => 526336,
|
||||
4 => 0,
|
||||
);
|
||||
|
||||
private function decodePointer($ctrlByte, $offset)
|
||||
{
|
||||
$pointerSize = (($ctrlByte >> 3) & 0x3) + 1;
|
||||
|
||||
$buffer = Util::read($this->fileStream, $offset, $pointerSize);
|
||||
$offset = $offset + $pointerSize;
|
||||
|
||||
$packed = $pointerSize == 4
|
||||
? $buffer
|
||||
: (pack('C', $ctrlByte & 0x7)) . $buffer;
|
||||
|
||||
$unpacked = $this->decodeUint($packed);
|
||||
$pointer = $unpacked + $this->pointerBase
|
||||
+ $this->pointerValueOffset[$pointerSize];
|
||||
|
||||
return array($pointer, $offset);
|
||||
}
|
||||
|
||||
private function decodeUint($bytes)
|
||||
{
|
||||
list(, $int) = unpack('N', $this->zeroPadLeft($bytes, 4));
|
||||
return $int;
|
||||
}
|
||||
|
||||
private function decodeBigUint($bytes, $byteLength)
|
||||
{
|
||||
$maxUintBytes = log(PHP_INT_MAX, 2) / 8;
|
||||
|
||||
if ($byteLength == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$numberOfLongs = ceil($byteLength / 4);
|
||||
$paddedLength = $numberOfLongs * 4;
|
||||
$paddedBytes = $this->zeroPadLeft($bytes, $paddedLength);
|
||||
$unpacked = array_merge(unpack("N$numberOfLongs", $paddedBytes));
|
||||
|
||||
$integer = 0;
|
||||
|
||||
// 2^32
|
||||
$twoTo32 = '4294967296';
|
||||
|
||||
foreach ($unpacked as $part) {
|
||||
// We only use gmp or bcmath if the final value is too big
|
||||
if ($byteLength <= $maxUintBytes) {
|
||||
$integer = ($integer << 32) + $part;
|
||||
} elseif (extension_loaded('gmp')) {
|
||||
$integer = gmp_strval(gmp_add(gmp_mul($integer, $twoTo32), $part));
|
||||
} elseif (extension_loaded('bcmath')) {
|
||||
$integer = bcadd(bcmul($integer, $twoTo32), $part);
|
||||
} else {
|
||||
throw new \RuntimeException(
|
||||
'The gmp or bcmath extension must be installed to read this database.'
|
||||
);
|
||||
}
|
||||
}
|
||||
return $integer;
|
||||
}
|
||||
|
||||
private function decodeString($bytes)
|
||||
{
|
||||
// XXX - NOOP. As far as I know, the end user has to explicitly set the
|
||||
// encoding in PHP. Strings are just bytes.
|
||||
return $bytes;
|
||||
}
|
||||
|
||||
private function sizeFromCtrlByte($ctrlByte, $offset)
|
||||
{
|
||||
$size = $ctrlByte & 0x1f;
|
||||
$bytesToRead = $size < 29 ? 0 : $size - 28;
|
||||
$bytes = Util::read($this->fileStream, $offset, $bytesToRead);
|
||||
$decoded = $this->decodeUint($bytes);
|
||||
|
||||
if ($size == 29) {
|
||||
$size = 29 + $decoded;
|
||||
} elseif ($size == 30) {
|
||||
$size = 285 + $decoded;
|
||||
} elseif ($size > 30) {
|
||||
$size = ($decoded & (0x0FFFFFFF >> (32 - (8 * $bytesToRead))))
|
||||
+ 65821;
|
||||
}
|
||||
|
||||
return array($size, $offset + $bytesToRead);
|
||||
}
|
||||
|
||||
private function zeroPadLeft($content, $desiredLength)
|
||||
{
|
||||
return str_pad($content, $desiredLength, "\x00", STR_PAD_LEFT);
|
||||
}
|
||||
|
||||
private function maybeSwitchByteOrder($bytes)
|
||||
{
|
||||
return $this->switchByteOrder ? strrev($bytes) : $bytes;
|
||||
}
|
||||
|
||||
private function isPlatformLittleEndian()
|
||||
{
|
||||
$testint = 0x00FF;
|
||||
$packed = pack('S', $testint);
|
||||
return $testint === current(unpack('v', $packed));
|
||||
}
|
||||
}
|
10
vendor/maxmind-db/reader/src/MaxMind/Db/Reader/InvalidDatabaseException.php
vendored
Normal file
10
vendor/maxmind-db/reader/src/MaxMind/Db/Reader/InvalidDatabaseException.php
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace MaxMind\Db\Reader;
|
||||
|
||||
/**
|
||||
* This class should be thrown when unexpected data is found in the database.
|
||||
*/
|
||||
class InvalidDatabaseException extends \Exception
|
||||
{
|
||||
}
|
77
vendor/maxmind-db/reader/src/MaxMind/Db/Reader/Metadata.php
vendored
Normal file
77
vendor/maxmind-db/reader/src/MaxMind/Db/Reader/Metadata.php
vendored
Normal file
@@ -0,0 +1,77 @@
|
||||
<?php
|
||||
|
||||
namespace MaxMind\Db\Reader;
|
||||
|
||||
/**
|
||||
* This class provides the metadata for the MaxMind DB file.
|
||||
*
|
||||
* @property integer nodeCount This is an unsigned 32-bit integer indicating
|
||||
* the number of nodes in the search tree.
|
||||
*
|
||||
* @property integer 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 integer 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 integer binaryFormatMajorVersion This is an unsigned 16-bit
|
||||
* integer indicating the major version number for the database's binary
|
||||
* format.
|
||||
*
|
||||
* @property integer binaryFormatMinorVersion This is an unsigned 16-bit
|
||||
* integer indicating the minor version number for the database's binary format.
|
||||
*
|
||||
* @property integer 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;
|
||||
}
|
||||
}
|
28
vendor/maxmind-db/reader/src/MaxMind/Db/Reader/Util.php
vendored
Normal file
28
vendor/maxmind-db/reader/src/MaxMind/Db/Reader/Util.php
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
namespace MaxMind\Db\Reader;
|
||||
|
||||
use MaxMind\Db\Reader\InvalidDatabaseException;
|
||||
|
||||
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"
|
||||
);
|
||||
}
|
||||
}
|
369
vendor/maxmind-db/reader/tests/MaxMind/Db/Test/Reader/DecoderTest.php
vendored
Normal file
369
vendor/maxmind-db/reader/tests/MaxMind/Db/Test/Reader/DecoderTest.php
vendored
Normal file
@@ -0,0 +1,369 @@
|
||||
<?php
|
||||
|
||||
namespace MaxMind\Db\Test\Reader;
|
||||
|
||||
use MaxMind\Db\Reader\Decoder;
|
||||
|
||||
class DecoderTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
private $arrays = array(
|
||||
array(
|
||||
'expected' => array(),
|
||||
'input' => array(0x0, 0x4),
|
||||
'name' => 'empty',
|
||||
),
|
||||
array(
|
||||
'expected' => array('Foo'),
|
||||
'input' => array(0x1, 0x4, /* Foo */
|
||||
0x43, 0x46, 0x6f, 0x6f),
|
||||
'name' => 'one element',
|
||||
),
|
||||
array(
|
||||
'expected' => array('Foo', '人'),
|
||||
'input' => array(
|
||||
0x2, 0x4,
|
||||
/* Foo */
|
||||
0x43, 0x46, 0x6f, 0x6f,
|
||||
/* 人 */
|
||||
0x43, 0xe4, 0xba, 0xba
|
||||
),
|
||||
'name' => 'two elements',
|
||||
),
|
||||
);
|
||||
|
||||
private $booleans = array(
|
||||
false => array(0x0, 0x7),
|
||||
true => array(0x1, 0x7),
|
||||
);
|
||||
|
||||
private $doubles = array(
|
||||
'0.0' => array(0x68, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0),
|
||||
'0.5' => array(0x68, 0x3F, 0xE0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0),
|
||||
'3.14159265359' => array(0x68, 0x40, 0x9, 0x21, 0xFB, 0x54, 0x44,
|
||||
0x2E, 0xEA),
|
||||
'123.0' => array(0x68, 0x40, 0x5E, 0xC0, 0x0, 0x0, 0x0, 0x0, 0x0),
|
||||
'1073741824.12457' => array(0x68, 0x41, 0xD0, 0x0, 0x0, 0x0, 0x7,
|
||||
0xF8, 0xF4),
|
||||
'-0.5' => array(0x68, 0xBF, 0xE0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0),
|
||||
'-3.14159265359' => array(0x68, 0xC0, 0x9, 0x21, 0xFB, 0x54, 0x44,
|
||||
0x2E, 0xEA),
|
||||
'-1073741824.12457' => array(0x68, 0xC1, 0xD0, 0x0, 0x0, 0x0, 0x7,
|
||||
0xF8, 0xF4),
|
||||
);
|
||||
|
||||
private $floats = array(
|
||||
'0.0' => array(0x4, 0x8, 0x0, 0x0, 0x0, 0x0),
|
||||
'1.0' => array(0x4, 0x8, 0x3F, 0x80, 0x0, 0x0),
|
||||
'1.1' => array(0x4, 0x8, 0x3F, 0x8C, 0xCC, 0xCD),
|
||||
'3.14' => array(0x4, 0x8, 0x40, 0x48, 0xF5, 0xC3),
|
||||
'9999.99' => array(0x4, 0x8, 0x46, 0x1C, 0x3F, 0xF6),
|
||||
'-1.0' => array(0x4, 0x8, 0xBF, 0x80, 0x0, 0x0),
|
||||
'-1.1' => array(0x4, 0x8, 0xBF, 0x8C, 0xCC, 0xCD),
|
||||
'-3.14' => array(0x4, 0x8, 0xC0, 0x48, 0xF5, 0xC3),
|
||||
'-9999.99' => array(0x4, 0x8, 0xC6, 0x1C, 0x3F, 0xF6)
|
||||
);
|
||||
|
||||
// PHP can't have arrays/objects as keys. Maybe redo all of the tests
|
||||
// this way so that we can use one test runner
|
||||
private $maps = array(
|
||||
array(
|
||||
'expected' => array(),
|
||||
'input' => array(0xe0),
|
||||
'name' => 'empty',
|
||||
),
|
||||
array(
|
||||
'expected' => array('en' => 'Foo'),
|
||||
'input' => array(0xe1, /* en */
|
||||
0x42, 0x65, 0x6e,
|
||||
/* Foo */
|
||||
0x43, 0x46, 0x6f, 0x6f),
|
||||
'name' => 'one key',
|
||||
),
|
||||
array(
|
||||
'expected' => array('en' => 'Foo', 'zh' => '人'),
|
||||
'input' => array(
|
||||
0xe2,
|
||||
/* en */
|
||||
0x42, 0x65, 0x6e,
|
||||
/* Foo */
|
||||
0x43, 0x46, 0x6f, 0x6f,
|
||||
/* zh */
|
||||
0x42, 0x7a, 0x68,
|
||||
/* 人 */
|
||||
0x43, 0xe4, 0xba, 0xba
|
||||
),
|
||||
'name' => 'two keys',
|
||||
),
|
||||
array(
|
||||
'expected' => array('name' => array('en' => 'Foo', 'zh' => '人')),
|
||||
'input' => array(
|
||||
0xe1,
|
||||
/* name */
|
||||
0x44, 0x6e, 0x61, 0x6d, 0x65, 0xe2,
|
||||
/* en */
|
||||
0x42, 0x65, 0x6e,
|
||||
/* Foo */
|
||||
0x43, 0x46, 0x6f, 0x6f,
|
||||
/* zh */
|
||||
0x42, 0x7a, 0x68,
|
||||
/* 人 */
|
||||
0x43, 0xe4, 0xba, 0xba
|
||||
),
|
||||
'name' => 'nested',
|
||||
),
|
||||
array(
|
||||
'expected' => array('languages' => array('en', 'zh')),
|
||||
'input' => array(
|
||||
0xe1,
|
||||
/* languages */
|
||||
0x49, 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61,
|
||||
0x67, 0x65, 0x73,
|
||||
/* array */
|
||||
0x2, 0x4,
|
||||
/* en */
|
||||
0x42, 0x65, 0x6e,
|
||||
/* zh */
|
||||
0x42, 0x7a, 0x68
|
||||
),
|
||||
'name' => 'map with array in it'
|
||||
),
|
||||
);
|
||||
|
||||
private $pointers = array(
|
||||
0 => array(0x20, 0x0),
|
||||
5 => array(0x20, 0x5),
|
||||
10 => array(0x20, 0xa),
|
||||
1023 => array(0x23, 0xff,),
|
||||
3017 => array(0x28, 0x3, 0xc9),
|
||||
524283 => array(0x2f, 0xf7, 0xfb),
|
||||
526335 => array(0x2f, 0xff, 0xff),
|
||||
134217726 => array(0x37, 0xf7, 0xf7, 0xfe),
|
||||
134744063 => array(0x37, 0xff, 0xff, 0xff),
|
||||
2147483647 => array(0x38, 0x7f, 0xff, 0xff, 0xff),
|
||||
4294967295 => array(0x38, 0xff, 0xff, 0xff, 0xff),
|
||||
);
|
||||
|
||||
private $uint16 = array(
|
||||
0 => array(0xa0),
|
||||
255 => array(0xa1, 0xff),
|
||||
500 => array(0xa2, 0x1, 0xf4),
|
||||
10872 => array(0xa2, 0x2a, 0x78),
|
||||
65535 => array(0xa2, 0xff, 0xff),
|
||||
);
|
||||
|
||||
|
||||
private $int32 = array(
|
||||
'0' => array(0x0, 0x1),
|
||||
'-1' => array(0x4, 0x1, 0xff, 0xff, 0xff, 0xff),
|
||||
'255' => array(0x1, 0x1, 0xff),
|
||||
'-255' => array(0x4, 0x1, 0xff, 0xff, 0xff, 0x1),
|
||||
'500' => array(0x2, 0x1, 0x1, 0xf4),
|
||||
'-500' => array(0x4, 0x1, 0xff, 0xff, 0xfe, 0xc),
|
||||
'65535' => array(0x2, 0x1, 0xff, 0xff),
|
||||
'-65535' => array(0x4, 0x1, 0xff, 0xff, 0x0, 0x1),
|
||||
'16777215' => array(0x3, 0x1, 0xff, 0xff, 0xff),
|
||||
'-16777215' => array(0x4, 0x1, 0xff, 0x0, 0x0, 0x1),
|
||||
'2147483647' => array(0x4, 0x1, 0x7f, 0xff, 0xff, 0xff),
|
||||
'-2147483647' => array(0x4, 0x1, 0x80, 0x0, 0x0, 0x1),
|
||||
);
|
||||
|
||||
private function strings()
|
||||
{
|
||||
$strings = array(
|
||||
'' => array(0x40),
|
||||
1 => array(0x41, 0x31),
|
||||
'人' => array(0x43, 0xE4, 0xBA, 0xBA),
|
||||
'123' => array(0x43, 0x31, 0x32, 0x33),
|
||||
'123456789012345678901234567' => array(0x5b, 0x31, 0x32, 0x33, 0x34,
|
||||
0x35, 0x36, 0x37, 0x38, 0x39, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35,
|
||||
0x36, 0x37, 0x38, 0x39, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36,
|
||||
0x37),
|
||||
'1234567890123456789012345678' => array(0x5c, 0x31, 0x32, 0x33, 0x34,
|
||||
0x35, 0x36, 0x37, 0x38, 0x39, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35,
|
||||
0x36, 0x37, 0x38, 0x39, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36,
|
||||
0x37, 0x38),
|
||||
'12345678901234567890123456789' => array(0x5d, 0x0, 0x31, 0x32, 0x33,
|
||||
0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x30, 0x31, 0x32, 0x33, 0x34,
|
||||
0x35, 0x36, 0x37, 0x38, 0x39, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35,
|
||||
0x36, 0x37, 0x38, 0x39),
|
||||
'123456789012345678901234567890' => array(0x5d, 0x1, 0x31, 0x32, 0x33,
|
||||
0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x30, 0x31, 0x32, 0x33, 0x34,
|
||||
0x35, 0x36, 0x37, 0x38, 0x39, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35,
|
||||
0x36, 0x37, 0x38, 0x39, 0x30),
|
||||
);
|
||||
|
||||
$strings[str_repeat('x', 500)] =
|
||||
array_pad(
|
||||
array(0x5e, 0x0, 0xd7),
|
||||
503,
|
||||
0x78
|
||||
);
|
||||
|
||||
$strings[str_repeat('x', 2000)] =
|
||||
array_pad(
|
||||
array(0x5e, 0x6, 0xb3),
|
||||
2003,
|
||||
0x78
|
||||
);
|
||||
|
||||
$strings[str_repeat('x', 70000)] =
|
||||
array_pad(
|
||||
array(0x5f, 0x0, 0x10, 0x53),
|
||||
70004,
|
||||
0x78
|
||||
);
|
||||
|
||||
return $strings;
|
||||
}
|
||||
|
||||
private $uint32 = array(
|
||||
0 => array(0xc0),
|
||||
255 => array(0xc1, 0xff),
|
||||
500 => array(0xc2, 0x1, 0xf4),
|
||||
10872 => array(0xc2, 0x2a, 0x78),
|
||||
65535 => array(0xc2, 0xff, 0xff),
|
||||
16777215 => array(0xc3, 0xff, 0xff, 0xff),
|
||||
4294967295 => array(0xc4, 0xff, 0xff, 0xff, 0xff),
|
||||
);
|
||||
|
||||
private function bytes()
|
||||
{
|
||||
// ugly deep clone
|
||||
$bytes = unserialize(serialize($this->strings()));
|
||||
|
||||
foreach ($bytes as $key => $byte_array) {
|
||||
$byte_array[0] ^= 0xc0;
|
||||
$bytes[$key] = $byte_array;
|
||||
|
||||
}
|
||||
return $bytes;
|
||||
}
|
||||
|
||||
public function generateLargeUint($bits)
|
||||
{
|
||||
|
||||
$ctrlByte = $bits == 64 ? 0x2 : 0x3;
|
||||
|
||||
$uints = array(
|
||||
0 => array(0x0, $ctrlByte),
|
||||
500 => array(0x2, $ctrlByte, 0x1, 0xf4),
|
||||
10872 => array(0x2, $ctrlByte, 0x2a, 0x78),
|
||||
);
|
||||
|
||||
for ($power = 1; $power <= $bits / 8; $power++) {
|
||||
$expected = bcsub(bcpow(2, 8 * $power), 1);
|
||||
$input = array($power, $ctrlByte);
|
||||
for ($i = 2; $i < 2 + $power; $i++) {
|
||||
$input[$i] = 0xff;
|
||||
}
|
||||
$uints[$expected] = $input;
|
||||
}
|
||||
return $uints;
|
||||
}
|
||||
|
||||
public function testArrays()
|
||||
{
|
||||
$this->validateTypeDecodingList('array', $this->arrays);
|
||||
}
|
||||
|
||||
public function testBooleans()
|
||||
{
|
||||
$this->validateTypeDecoding('boolean', $this->booleans);
|
||||
}
|
||||
|
||||
public function testBytes()
|
||||
{
|
||||
$this->validateTypeDecoding('byte', $this->bytes());
|
||||
}
|
||||
|
||||
public function testDoubles()
|
||||
{
|
||||
$this->validateTypeDecoding('double', $this->doubles);
|
||||
}
|
||||
|
||||
public function testFloats()
|
||||
{
|
||||
$this->validateTypeDecoding('float', $this->floats);
|
||||
}
|
||||
|
||||
public function testInt32()
|
||||
{
|
||||
$this->validateTypeDecoding('int32', $this->int32);
|
||||
}
|
||||
|
||||
public function testMaps()
|
||||
{
|
||||
$this->validateTypeDecodingList('map', $this->maps);
|
||||
}
|
||||
|
||||
public function testPointers()
|
||||
{
|
||||
$this->validateTypeDecoding('pointers', $this->pointers);
|
||||
}
|
||||
|
||||
public function testStrings()
|
||||
{
|
||||
$this->validateTypeDecoding('utf8_string', $this->strings());
|
||||
}
|
||||
|
||||
public function testUint16()
|
||||
{
|
||||
$this->validateTypeDecoding('uint16', $this->uint16);
|
||||
}
|
||||
|
||||
public function testUint32()
|
||||
{
|
||||
$this->validateTypeDecoding('uint32', $this->uint32);
|
||||
}
|
||||
|
||||
public function testUint64()
|
||||
{
|
||||
$this->validateTypeDecoding('uint64', $this->generateLargeUint(64));
|
||||
}
|
||||
|
||||
public function testUint128()
|
||||
{
|
||||
$this->validateTypeDecoding('uint128', $this->generateLargeUint(128));
|
||||
}
|
||||
|
||||
private function validateTypeDecoding($type, $tests)
|
||||
{
|
||||
|
||||
foreach ($tests as $expected => $input) {
|
||||
$this->checkDecoding($type, $input, $expected);
|
||||
}
|
||||
}
|
||||
|
||||
private function validateTypeDecodingList($type, $tests)
|
||||
{
|
||||
foreach ($tests as $test) {
|
||||
$this->checkDecoding(
|
||||
$type,
|
||||
$test['input'],
|
||||
$test['expected'],
|
||||
$test['name']
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private function checkDecoding($type, $input, $expected, $name = null)
|
||||
{
|
||||
$name = $name || $expected;
|
||||
$description = "decoded $type - $name";
|
||||
$handle = fopen('php://memory', 'rw');
|
||||
|
||||
foreach ($input as $byte) {
|
||||
fwrite($handle, pack('C', $byte));
|
||||
}
|
||||
fseek($handle, 0);
|
||||
$decoder = new Decoder($handle, 0, true);
|
||||
list($actual) = $decoder->decode(0);
|
||||
|
||||
if ($type == 'float') {
|
||||
$actual = round($actual, 2);
|
||||
}
|
||||
|
||||
$this->assertEquals($expected, $actual, $description);
|
||||
|
||||
}
|
||||
}
|
45
vendor/maxmind-db/reader/tests/MaxMind/Db/Test/Reader/PointerTest.php
vendored
Normal file
45
vendor/maxmind-db/reader/tests/MaxMind/Db/Test/Reader/PointerTest.php
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
namespace MaxMind\Db\Test\Reader;
|
||||
|
||||
use MaxMind\Db\Reader\Decoder;
|
||||
|
||||
class PointerTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
|
||||
public function testWithPointers()
|
||||
{
|
||||
$handle = fopen('tests/data/test-data/maps-with-pointers.raw', 'r');
|
||||
$decoder = new Decoder($handle, 0);
|
||||
|
||||
$this->assertEquals(
|
||||
array(array('long_key' => 'long_value1'), 22),
|
||||
$decoder->decode(0)
|
||||
);
|
||||
|
||||
$this->assertEquals(
|
||||
array(array('long_key' => 'long_value2'), 37),
|
||||
$decoder->decode(22)
|
||||
);
|
||||
|
||||
$this->assertEquals(
|
||||
array(array('long_key2' => 'long_value1'), 50),
|
||||
$decoder->decode(37)
|
||||
);
|
||||
|
||||
$this->assertEquals(
|
||||
array(array('long_key2' => 'long_value2'), 55),
|
||||
$decoder->decode(50)
|
||||
);
|
||||
|
||||
$this->assertEquals(
|
||||
array(array('long_key' => 'long_value1'), 57),
|
||||
$decoder->decode(55)
|
||||
);
|
||||
|
||||
$this->assertEquals(
|
||||
array(array('long_key2' => 'long_value2'), 59),
|
||||
$decoder->decode(57)
|
||||
);
|
||||
}
|
||||
}
|
391
vendor/maxmind-db/reader/tests/MaxMind/Db/Test/ReaderTest.php
vendored
Normal file
391
vendor/maxmind-db/reader/tests/MaxMind/Db/Test/ReaderTest.php
vendored
Normal file
@@ -0,0 +1,391 @@
|
||||
<?php
|
||||
|
||||
namespace MaxMind\Db\Test\Reader;
|
||||
|
||||
use MaxMind\Db\Reader;
|
||||
|
||||
class ReaderTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
public function testReader()
|
||||
{
|
||||
foreach (array(24, 28, 32) as $recordSize) {
|
||||
foreach (array(4, 6) as $ipVersion) {
|
||||
$fileName = 'tests/data/test-data/MaxMind-DB-test-ipv'
|
||||
. $ipVersion . '-' . $recordSize . '.mmdb';
|
||||
$reader = new Reader($fileName);
|
||||
|
||||
$this->checkMetadata($reader, $ipVersion, $recordSize);
|
||||
|
||||
if ($ipVersion == 4) {
|
||||
$this->checkIpV4($reader, $fileName);
|
||||
} else {
|
||||
$this->checkIpV6($reader, $fileName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function testDecoder()
|
||||
{
|
||||
$reader = new Reader('tests/data/test-data/MaxMind-DB-test-decoder.mmdb');
|
||||
$record = $reader->get('::1.1.1.0');
|
||||
|
||||
$this->assertEquals(true, $record['boolean']);
|
||||
$this->assertEquals(pack('N', 42), $record['bytes']);
|
||||
$this->assertEquals('unicode! ☯ - ♫', $record['utf8_string']);
|
||||
|
||||
$this->assertEquals(array(1, 2, 3), $record['array']);
|
||||
|
||||
$this->assertEquals(
|
||||
array(
|
||||
'mapX' => array(
|
||||
'arrayX' => array(7, 8, 9),
|
||||
'utf8_stringX' => 'hello'
|
||||
),
|
||||
),
|
||||
$record['map']
|
||||
);
|
||||
|
||||
$this->assertEquals(42.123456, $record['double']);
|
||||
$this->assertEquals(1.1, $record['float'], 'float', 0.000001);
|
||||
|
||||
$this->assertEquals(-268435456, $record['int32']);
|
||||
$this->assertEquals(100, $record['uint16']);
|
||||
$this->assertEquals(268435456, $record['uint32']);
|
||||
$this->assertEquals('1152921504606846976', $record['uint64']);
|
||||
|
||||
$uint128 = $record['uint128'];
|
||||
|
||||
// For the C extension, which returns a hexadecimal
|
||||
if (extension_loaded('gmp')) {
|
||||
$uint128 = gmp_strval($uint128);
|
||||
} else {
|
||||
$this->markTestIncomplete('Requires gmp extension to check value of uint128');
|
||||
}
|
||||
|
||||
$this->assertEquals(
|
||||
'1329227995784915872903807060280344576',
|
||||
$uint128
|
||||
);
|
||||
}
|
||||
|
||||
public function testZeros()
|
||||
{
|
||||
$reader = new Reader('tests/data/test-data/MaxMind-DB-test-decoder.mmdb');
|
||||
$record = $reader->get('::');
|
||||
|
||||
$this->assertEquals(false, $record['boolean']);
|
||||
$this->assertEquals('', $record['bytes']);
|
||||
$this->assertEquals('', $record['utf8_string']);
|
||||
|
||||
$this->assertEquals(array(), $record['array']);
|
||||
$this->assertEquals(array(), $record['map']);
|
||||
|
||||
$this->assertEquals(0, $record['double']);
|
||||
$this->assertEquals(0, $record['float'], 'float', 0.000001);
|
||||
$this->assertEquals(0, $record['int32']);
|
||||
$this->assertEquals(0, $record['uint16']);
|
||||
$this->assertEquals(0, $record['uint32']);
|
||||
$this->assertEquals(0, $record['uint64']);
|
||||
|
||||
$uint128 = $record['uint128'];
|
||||
if (extension_loaded('gmp')) {
|
||||
$uint128 = gmp_strval($uint128);
|
||||
} else {
|
||||
$this->markTestIncomplete('Requires gmp extension to check value of uint128');
|
||||
}
|
||||
$this->assertEquals('0', $uint128);
|
||||
}
|
||||
|
||||
public function testNoIpV4SearchTree()
|
||||
{
|
||||
$reader = new Reader(
|
||||
'tests/data/test-data/MaxMind-DB-no-ipv4-search-tree.mmdb'
|
||||
);
|
||||
$this->assertEquals('::0/64', $reader->get('1.1.1.1'));
|
||||
$this->assertEquals('::0/64', $reader->get('192.1.1.1'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException InvalidArgumentException
|
||||
* @expectedExceptionMessage Error looking up 2001::. You attempted to look up an IPv6 address in an IPv4-only database
|
||||
*/
|
||||
public function testV6AddressV4Database()
|
||||
{
|
||||
$reader = new Reader('tests/data/test-data/MaxMind-DB-test-ipv4-24.mmdb');
|
||||
$reader->get('2001::');
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException InvalidArgumentException
|
||||
* @expectedExceptionMessage The value "not_ip" is not a valid IP address.
|
||||
*/
|
||||
public function testIpValidation()
|
||||
{
|
||||
$reader = new Reader('tests/data/test-data/MaxMind-DB-test-decoder.mmdb');
|
||||
$reader->get('not_ip');
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException MaxMind\Db\Reader\InvalidDatabaseException
|
||||
* @expectedExceptionMessage The MaxMind DB file's data section contains bad data (unknown data type or corrupt data)
|
||||
*/
|
||||
public function testBrokenDatabase()
|
||||
{
|
||||
$reader = new Reader('tests/data/test-data/GeoIP2-City-Test-Broken-Double-Format.mmdb');
|
||||
$reader->get('2001:220::');
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException MaxMind\Db\Reader\InvalidDatabaseException
|
||||
* @expectedExceptionMessage The MaxMind DB file's search tree is corrupt
|
||||
*/
|
||||
public function testBrokenSearchTreePointer()
|
||||
{
|
||||
$reader = new Reader('tests/data/test-data/MaxMind-DB-test-broken-pointers-24.mmdb');
|
||||
$reader->get('1.1.1.32');
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException MaxMind\Db\Reader\InvalidDatabaseException
|
||||
* @expectedExceptionMessage contains bad data
|
||||
*/
|
||||
public function testBrokenDataPointer()
|
||||
{
|
||||
$reader = new Reader('tests/data/test-data/MaxMind-DB-test-broken-pointers-24.mmdb');
|
||||
$reader->get('1.1.1.16');
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException InvalidArgumentException
|
||||
* @expectedExceptionMessage The file "file-does-not-exist.mmdb" does not exist or is not readable.
|
||||
*/
|
||||
public function testMissingDatabase()
|
||||
{
|
||||
new Reader('file-does-not-exist.mmdb');
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException MaxMind\Db\Reader\InvalidDatabaseException
|
||||
* @expectedExceptionMessage Error opening database file (README.md). Is this a valid MaxMind DB file?
|
||||
*/
|
||||
public function testNonDatabase()
|
||||
{
|
||||
new Reader('README.md');
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException InvalidArgumentException
|
||||
* @expectedExceptionMessage The constructor takes exactly one argument.
|
||||
*/
|
||||
public function testTooManyConstructorArgs()
|
||||
{
|
||||
new Reader('README.md', 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException InvalidArgumentException
|
||||
*
|
||||
* This test only matters for the extension.
|
||||
*/
|
||||
public function testNoConstructorArgs()
|
||||
{
|
||||
if (extension_loaded('maxminddb')) {
|
||||
new Reader();
|
||||
} else {
|
||||
throw new \InvalidArgumentException();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException InvalidArgumentException
|
||||
* @expectedExceptionMessage Method takes exactly one argument.
|
||||
*/
|
||||
public function testTooManyGetAgs()
|
||||
{
|
||||
$reader = new Reader(
|
||||
'tests/data/test-data/MaxMind-DB-test-decoder.mmdb'
|
||||
);
|
||||
$reader->get('1.1.1.1', 'blah');
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException InvalidArgumentException
|
||||
*
|
||||
* This test only matters for the extension.
|
||||
*/
|
||||
public function testNoGetArgs()
|
||||
{
|
||||
if (extension_loaded('maxminddb')) {
|
||||
$reader = new Reader(
|
||||
'tests/data/test-data/MaxMind-DB-test-decoder.mmdb'
|
||||
);
|
||||
$reader->get();
|
||||
} else {
|
||||
throw new \InvalidArgumentException();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException InvalidArgumentException
|
||||
* @expectedExceptionMessage Method takes no arguments.
|
||||
*/
|
||||
public function testMetadataAgs()
|
||||
{
|
||||
$reader = new Reader(
|
||||
'tests/data/test-data/MaxMind-DB-test-decoder.mmdb'
|
||||
);
|
||||
$reader->metadata('blah');
|
||||
}
|
||||
|
||||
public function testClose()
|
||||
{
|
||||
$reader = new Reader(
|
||||
'tests/data/test-data/MaxMind-DB-test-decoder.mmdb'
|
||||
);
|
||||
$reader->close();
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException BadMethodCallException
|
||||
* @expectedExceptionMessage Attempt to close a closed MaxMind DB.
|
||||
*/
|
||||
public function testDoubleClose()
|
||||
{
|
||||
$reader = new Reader(
|
||||
'tests/data/test-data/MaxMind-DB-test-decoder.mmdb'
|
||||
);
|
||||
$reader->close();
|
||||
$reader->close();
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException BadMethodCallException
|
||||
* @expectedExceptionMessage Attempt to read from a closed MaxMind DB.
|
||||
*/
|
||||
public function testClosedGet()
|
||||
{
|
||||
$reader = new Reader(
|
||||
'tests/data/test-data/MaxMind-DB-test-decoder.mmdb'
|
||||
);
|
||||
$reader->close();
|
||||
$reader->get('1.1.1.1');
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException BadMethodCallException
|
||||
* @expectedExceptionMessage Attempt to read from a closed MaxMind DB.
|
||||
*/
|
||||
public function testClosedMetadata()
|
||||
{
|
||||
$reader = new Reader(
|
||||
'tests/data/test-data/MaxMind-DB-test-decoder.mmdb'
|
||||
);
|
||||
$reader->close();
|
||||
$reader->metadata();
|
||||
}
|
||||
|
||||
private function checkMetadata($reader, $ipVersion, $recordSize)
|
||||
{
|
||||
$metadata = $reader->metadata();
|
||||
|
||||
$this->assertEquals(
|
||||
2,
|
||||
$metadata->binaryFormatMajorVersion,
|
||||
'major version'
|
||||
);
|
||||
$this->assertEquals(0, $metadata->binaryFormatMinorVersion);
|
||||
$this->assertGreaterThan(1373571901, $metadata->buildEpoch);
|
||||
$this->assertEquals('Test', $metadata->databaseType);
|
||||
|
||||
$this->assertEquals(
|
||||
array('en' => 'Test Database', 'zh' => 'Test Database Chinese'),
|
||||
$metadata->description
|
||||
);
|
||||
|
||||
$this->assertEquals($ipVersion, $metadata->ipVersion);
|
||||
$this->assertEquals(array('en', 'zh'), $metadata->languages);
|
||||
$this->assertEquals($recordSize / 4, $metadata->nodeByteSize);
|
||||
$this->assertGreaterThan(36, $metadata->nodeCount);
|
||||
|
||||
$this->assertEquals($recordSize, $metadata->recordSize);
|
||||
$this->assertGreaterThan(200, $metadata->searchTreeSize);
|
||||
}
|
||||
|
||||
private function checkIpV4(Reader $reader, $fileName)
|
||||
{
|
||||
for ($i = 0; $i <= 5; $i++) {
|
||||
$address = '1.1.1.' . pow(2, $i);
|
||||
$this->assertEquals(
|
||||
array('ip' => $address),
|
||||
$reader->get($address),
|
||||
'found expected data record for '
|
||||
. $address . ' in ' . $fileName
|
||||
);
|
||||
}
|
||||
|
||||
$pairs = array(
|
||||
'1.1.1.3' => '1.1.1.2',
|
||||
'1.1.1.5' => '1.1.1.4',
|
||||
'1.1.1.7' => '1.1.1.4',
|
||||
'1.1.1.9' => '1.1.1.8',
|
||||
'1.1.1.15' => '1.1.1.8',
|
||||
'1.1.1.17' => '1.1.1.16',
|
||||
'1.1.1.31' => '1.1.1.16'
|
||||
);
|
||||
foreach ($pairs as $keyAddress => $valueAddress) {
|
||||
$data = array('ip' => $valueAddress);
|
||||
|
||||
$this->assertEquals(
|
||||
$data,
|
||||
$reader->get($keyAddress),
|
||||
'found expected data record for ' . $keyAddress . ' in '
|
||||
. $fileName
|
||||
);
|
||||
}
|
||||
|
||||
foreach (array('1.1.1.33', '255.254.253.123') as $ip) {
|
||||
$this->assertNull($reader->get($ip));
|
||||
}
|
||||
}
|
||||
|
||||
// XXX - logic could be combined with above
|
||||
private function checkIpV6(Reader $reader, $fileName)
|
||||
{
|
||||
$subnets = array('::1:ffff:ffff', '::2:0:0',
|
||||
'::2:0:40', '::2:0:50', '::2:0:58');
|
||||
|
||||
foreach ($subnets as $address) {
|
||||
$this->assertEquals(
|
||||
array('ip' => $address),
|
||||
$reader->get($address),
|
||||
'found expected data record for ' . $address . ' in '
|
||||
. $fileName
|
||||
);
|
||||
}
|
||||
|
||||
$pairs = array(
|
||||
'::2:0:1' => '::2:0:0',
|
||||
'::2:0:33' => '::2:0:0',
|
||||
'::2:0:39' => '::2:0:0',
|
||||
'::2:0:41' => '::2:0:40',
|
||||
'::2:0:49' => '::2:0:40',
|
||||
'::2:0:52' => '::2:0:50',
|
||||
'::2:0:57' => '::2:0:50',
|
||||
'::2:0:59' => '::2:0:58'
|
||||
);
|
||||
|
||||
foreach ($pairs as $keyAddress => $valueAddress) {
|
||||
$this->assertEquals(
|
||||
array('ip' => $valueAddress),
|
||||
$reader->get($keyAddress),
|
||||
'found expected data record for ' . $keyAddress . ' in '
|
||||
. $fileName
|
||||
);
|
||||
}
|
||||
|
||||
foreach (array('1.1.1.33', '255.254.253.123', '89fa::') as $ip) {
|
||||
$this->assertNull($reader->get($ip));
|
||||
}
|
||||
}
|
||||
}
|
7
vendor/maxmind-db/reader/tests/bootstrap.php
vendored
Normal file
7
vendor/maxmind-db/reader/tests/bootstrap.php
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
<?php
|
||||
|
||||
if (!$loader = @include __DIR__.'/../vendor/autoload.php') {
|
||||
die('Project dependencies missing');
|
||||
}
|
||||
|
||||
$loader->add('MaxMind\Db\Test', __DIR__);
|
Reference in New Issue
Block a user