initial commit
This commit is contained in:
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.
|
45
vendor/maxmind-db/reader/autoload.php
vendored
Normal file
45
vendor/maxmind-db/reader/autoload.php
vendored
Normal file
@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* PSR-4 autoloader implementation for the MaxMind\DB namespace.
|
||||
* First we define the 'mmdb_autoload' function, and then we register
|
||||
* it with 'spl_autoload_register' so that PHP knows to use it.
|
||||
*
|
||||
* @param mixed $class
|
||||
*/
|
||||
|
||||
/**
|
||||
* Automatically include the file that defines <code>class</code>.
|
||||
*
|
||||
* @param string $class
|
||||
* the name of the class to load
|
||||
*/
|
||||
function mmdb_autoload($class)
|
||||
{
|
||||
/*
|
||||
* A project-specific mapping between the namespaces and where
|
||||
* they're located. By convention, we include the trailing
|
||||
* slashes. The one-element array here simply makes things easy
|
||||
* to extend in the future if (for example) the test classes
|
||||
* begin to use one another.
|
||||
*/
|
||||
$namespace_map = ['MaxMind\\Db\\' => __DIR__ . '/src/MaxMind/Db/'];
|
||||
|
||||
foreach ($namespace_map as $prefix => $dir) {
|
||||
/* First swap out the namespace prefix with a directory... */
|
||||
$path = str_replace($prefix, $dir, $class);
|
||||
|
||||
/* replace the namespace separator with a directory separator... */
|
||||
$path = str_replace('\\', '/', $path);
|
||||
|
||||
/* and finally, add the PHP file extension to the result. */
|
||||
$path = $path . '.php';
|
||||
|
||||
/* $path should now contain the path to a PHP file defining $class */
|
||||
if (file_exists($path)) {
|
||||
include $path;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
spl_autoload_register('mmdb_autoload');
|
40
vendor/maxmind-db/reader/ext/config.m4
vendored
Normal file
40
vendor/maxmind-db/reader/ext/config.m4
vendored
Normal file
@ -0,0 +1,40 @@
|
||||
PHP_ARG_WITH(maxminddb,
|
||||
[Whether to enable the MaxMind DB Reader extension],
|
||||
[ --with-maxminddb Enable MaxMind DB Reader extension support])
|
||||
|
||||
PHP_ARG_ENABLE(maxminddb-debug, for MaxMind DB debug support,
|
||||
[ --enable-maxminddb-debug Enable enable MaxMind DB deubg support], no, no)
|
||||
|
||||
if test $PHP_MAXMINDDB != "no"; then
|
||||
|
||||
AC_PATH_PROG(PKG_CONFIG, pkg-config, no)
|
||||
|
||||
AC_MSG_CHECKING(for libmaxminddb)
|
||||
if test -x "$PKG_CONFIG" && $PKG_CONFIG --exists libmaxminddb; then
|
||||
dnl retrieve build options from pkg-config
|
||||
if $PKG_CONFIG libmaxminddb --atleast-version 1.0.0; then
|
||||
LIBMAXMINDDB_INC=`$PKG_CONFIG libmaxminddb --cflags`
|
||||
LIBMAXMINDDB_LIB=`$PKG_CONFIG libmaxminddb --libs`
|
||||
LIBMAXMINDDB_VER=`$PKG_CONFIG libmaxminddb --modversion`
|
||||
AC_MSG_RESULT(found version $LIBMAXMINDDB_VER)
|
||||
else
|
||||
AC_MSG_ERROR(system libmaxminddb must be upgraded to version >= 1.0.0)
|
||||
fi
|
||||
PHP_EVAL_LIBLINE($LIBMAXMINDDB_LIB, MAXMINDDB_SHARED_LIBADD)
|
||||
PHP_EVAL_INCLINE($LIBMAXMINDDB_INC)
|
||||
else
|
||||
AC_MSG_RESULT(pkg-config information missing)
|
||||
AC_MSG_WARN(will use libmaxmxinddb from compiler default path)
|
||||
|
||||
PHP_CHECK_LIBRARY(maxminddb, MMDB_open)
|
||||
PHP_ADD_LIBRARY(maxminddb, 1, MAXMINDDB_SHARED_LIBADD)
|
||||
fi
|
||||
|
||||
if test $PHP_MAXMINDDB_DEBUG != "no"; then
|
||||
CFLAGS="$CFLAGS -Wall -Wextra -Wno-unused-parameter -Wno-missing-field-initializers -Werror"
|
||||
fi
|
||||
|
||||
PHP_SUBST(MAXMINDDB_SHARED_LIBADD)
|
||||
|
||||
PHP_NEW_EXTENSION(maxminddb, maxminddb.c, $ext_shared)
|
||||
fi
|
704
vendor/maxmind-db/reader/ext/maxminddb.c
vendored
Normal file
704
vendor/maxmind-db/reader/ext/maxminddb.c
vendored
Normal file
@ -0,0 +1,704 @@
|
||||
/* MaxMind, Inc., licenses this file to you under the Apache License, Version
|
||||
* 2.0 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#include "php_maxminddb.h"
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <php.h>
|
||||
#include <zend.h>
|
||||
|
||||
#include "Zend/zend_exceptions.h"
|
||||
#include "ext/standard/info.h"
|
||||
#include <maxminddb.h>
|
||||
|
||||
#ifdef ZTS
|
||||
#include <TSRM.h>
|
||||
#endif
|
||||
|
||||
#define __STDC_FORMAT_MACROS
|
||||
#include <inttypes.h>
|
||||
|
||||
#define PHP_MAXMINDDB_NS ZEND_NS_NAME("MaxMind", "Db")
|
||||
#define PHP_MAXMINDDB_READER_NS ZEND_NS_NAME(PHP_MAXMINDDB_NS, "Reader")
|
||||
#define PHP_MAXMINDDB_READER_EX_NS \
|
||||
ZEND_NS_NAME(PHP_MAXMINDDB_READER_NS, "InvalidDatabaseException")
|
||||
|
||||
#ifdef ZEND_ENGINE_3
|
||||
#define Z_MAXMINDDB_P(zv) php_maxminddb_fetch_object(Z_OBJ_P(zv))
|
||||
#define _ZVAL_STRING ZVAL_STRING
|
||||
#define _ZVAL_STRINGL ZVAL_STRINGL
|
||||
typedef size_t strsize_t;
|
||||
typedef zend_object free_obj_t;
|
||||
#else
|
||||
#define Z_MAXMINDDB_P(zv) \
|
||||
(maxminddb_obj *)zend_object_store_get_object(zv TSRMLS_CC)
|
||||
#define _ZVAL_STRING(a, b) ZVAL_STRING(a, b, 1)
|
||||
#define _ZVAL_STRINGL(a, b, c) ZVAL_STRINGL(a, b, c, 1)
|
||||
typedef int strsize_t;
|
||||
typedef void free_obj_t;
|
||||
#endif
|
||||
|
||||
/* For PHP 8 compatibility */
|
||||
#ifndef TSRMLS_C
|
||||
#define TSRMLS_C
|
||||
#endif
|
||||
#ifndef TSRMLS_CC
|
||||
#define TSRMLS_CC
|
||||
#endif
|
||||
#ifndef TSRMLS_DC
|
||||
#define TSRMLS_DC
|
||||
#endif
|
||||
#ifndef ZEND_ACC_CTOR
|
||||
#define ZEND_ACC_CTOR 0
|
||||
#endif
|
||||
|
||||
#ifdef ZEND_ENGINE_3
|
||||
typedef struct _maxminddb_obj {
|
||||
MMDB_s *mmdb;
|
||||
zend_object std;
|
||||
} maxminddb_obj;
|
||||
#else
|
||||
typedef struct _maxminddb_obj {
|
||||
zend_object std;
|
||||
MMDB_s *mmdb;
|
||||
} maxminddb_obj;
|
||||
#endif
|
||||
|
||||
PHP_FUNCTION(maxminddb);
|
||||
|
||||
static int
|
||||
get_record(INTERNAL_FUNCTION_PARAMETERS, zval *record, int *prefix_len);
|
||||
static const MMDB_entry_data_list_s *
|
||||
handle_entry_data_list(const MMDB_entry_data_list_s *entry_data_list,
|
||||
zval *z_value TSRMLS_DC);
|
||||
static const MMDB_entry_data_list_s *
|
||||
handle_array(const MMDB_entry_data_list_s *entry_data_list,
|
||||
zval *z_value TSRMLS_DC);
|
||||
static const MMDB_entry_data_list_s *
|
||||
handle_map(const MMDB_entry_data_list_s *entry_data_list,
|
||||
zval *z_value TSRMLS_DC);
|
||||
static void handle_uint128(const MMDB_entry_data_list_s *entry_data_list,
|
||||
zval *z_value TSRMLS_DC);
|
||||
static void handle_uint64(const MMDB_entry_data_list_s *entry_data_list,
|
||||
zval *z_value TSRMLS_DC);
|
||||
static void handle_uint32(const MMDB_entry_data_list_s *entry_data_list,
|
||||
zval *z_value TSRMLS_DC);
|
||||
static zend_class_entry *lookup_class(const char *name TSRMLS_DC);
|
||||
|
||||
#define CHECK_ALLOCATED(val) \
|
||||
if (!val) { \
|
||||
zend_error(E_ERROR, "Out of memory"); \
|
||||
return; \
|
||||
}
|
||||
|
||||
#define THROW_EXCEPTION(name, ...) \
|
||||
{ \
|
||||
zend_class_entry *exception_ce = lookup_class(name TSRMLS_CC); \
|
||||
zend_throw_exception_ex(exception_ce, 0 TSRMLS_CC, __VA_ARGS__); \
|
||||
}
|
||||
|
||||
#if PHP_VERSION_ID < 50399
|
||||
#define object_properties_init(zo, class_type) \
|
||||
{ \
|
||||
zval *tmp; \
|
||||
zend_hash_copy((*zo).properties, \
|
||||
&class_type->default_properties, \
|
||||
(copy_ctor_func_t)zval_add_ref, \
|
||||
(void *)&tmp, \
|
||||
sizeof(zval *)); \
|
||||
}
|
||||
#endif
|
||||
|
||||
static zend_object_handlers maxminddb_obj_handlers;
|
||||
static zend_class_entry *maxminddb_ce;
|
||||
|
||||
static inline maxminddb_obj *
|
||||
php_maxminddb_fetch_object(zend_object *obj TSRMLS_DC) {
|
||||
#ifdef ZEND_ENGINE_3
|
||||
return (maxminddb_obj *)((char *)(obj)-XtOffsetOf(maxminddb_obj, std));
|
||||
#else
|
||||
return (maxminddb_obj *)obj;
|
||||
#endif
|
||||
}
|
||||
|
||||
ZEND_BEGIN_ARG_INFO_EX(arginfo_maxmindbreader_construct, 0, 0, 1)
|
||||
ZEND_ARG_INFO(0, db_file)
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
PHP_METHOD(MaxMind_Db_Reader, __construct) {
|
||||
char *db_file = NULL;
|
||||
strsize_t name_len;
|
||||
zval *_this_zval = NULL;
|
||||
|
||||
if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
|
||||
getThis(),
|
||||
"Os",
|
||||
&_this_zval,
|
||||
maxminddb_ce,
|
||||
&db_file,
|
||||
&name_len) == FAILURE) {
|
||||
THROW_EXCEPTION("InvalidArgumentException",
|
||||
"The constructor takes exactly one argument.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (0 != php_check_open_basedir(db_file TSRMLS_CC) ||
|
||||
0 != access(db_file, R_OK)) {
|
||||
THROW_EXCEPTION("InvalidArgumentException",
|
||||
"The file \"%s\" does not exist or is not readable.",
|
||||
db_file);
|
||||
return;
|
||||
}
|
||||
|
||||
MMDB_s *mmdb = (MMDB_s *)ecalloc(1, sizeof(MMDB_s));
|
||||
uint16_t status = MMDB_open(db_file, MMDB_MODE_MMAP, mmdb);
|
||||
|
||||
if (MMDB_SUCCESS != status) {
|
||||
THROW_EXCEPTION(PHP_MAXMINDDB_READER_EX_NS,
|
||||
"Error opening database file (%s). Is this a valid "
|
||||
"MaxMind DB file?",
|
||||
db_file);
|
||||
efree(mmdb);
|
||||
return;
|
||||
}
|
||||
|
||||
maxminddb_obj *mmdb_obj = Z_MAXMINDDB_P(getThis());
|
||||
mmdb_obj->mmdb = mmdb;
|
||||
}
|
||||
|
||||
ZEND_BEGIN_ARG_INFO_EX(arginfo_maxmindbreader_get, 0, 0, 1)
|
||||
ZEND_ARG_INFO(0, ip_address)
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
PHP_METHOD(MaxMind_Db_Reader, get) {
|
||||
int prefix_len = 0;
|
||||
get_record(INTERNAL_FUNCTION_PARAM_PASSTHRU, return_value, &prefix_len);
|
||||
}
|
||||
|
||||
PHP_METHOD(MaxMind_Db_Reader, getWithPrefixLen) {
|
||||
zval *record, *z_prefix_len;
|
||||
#ifdef ZEND_ENGINE_3
|
||||
zval _record, _z_prefix_len;
|
||||
record = &_record;
|
||||
z_prefix_len = &_z_prefix_len;
|
||||
#else
|
||||
ALLOC_INIT_ZVAL(record);
|
||||
ALLOC_INIT_ZVAL(z_prefix_len);
|
||||
#endif
|
||||
|
||||
int prefix_len = 0;
|
||||
if (get_record(INTERNAL_FUNCTION_PARAM_PASSTHRU, record, &prefix_len)) {
|
||||
return;
|
||||
}
|
||||
|
||||
array_init(return_value);
|
||||
add_next_index_zval(return_value, record);
|
||||
|
||||
ZVAL_LONG(z_prefix_len, prefix_len);
|
||||
add_next_index_zval(return_value, z_prefix_len);
|
||||
}
|
||||
|
||||
static int
|
||||
get_record(INTERNAL_FUNCTION_PARAMETERS, zval *record, int *prefix_len) {
|
||||
char *ip_address = NULL;
|
||||
strsize_t name_len;
|
||||
zval *_this_zval = NULL;
|
||||
|
||||
if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
|
||||
getThis(),
|
||||
"Os",
|
||||
&_this_zval,
|
||||
maxminddb_ce,
|
||||
&ip_address,
|
||||
&name_len) == FAILURE) {
|
||||
THROW_EXCEPTION("InvalidArgumentException",
|
||||
"Method takes exactly one argument.");
|
||||
return 1;
|
||||
}
|
||||
|
||||
const maxminddb_obj *mmdb_obj = (maxminddb_obj *)Z_MAXMINDDB_P(getThis());
|
||||
|
||||
MMDB_s *mmdb = mmdb_obj->mmdb;
|
||||
|
||||
if (NULL == mmdb) {
|
||||
THROW_EXCEPTION("BadMethodCallException",
|
||||
"Attempt to read from a closed MaxMind DB.");
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct addrinfo hints = {
|
||||
.ai_family = AF_UNSPEC,
|
||||
.ai_flags = AI_NUMERICHOST,
|
||||
// We set ai_socktype so that we only get one result back
|
||||
.ai_socktype = SOCK_STREAM};
|
||||
|
||||
struct addrinfo *addresses = NULL;
|
||||
int gai_status = getaddrinfo(ip_address, NULL, &hints, &addresses);
|
||||
if (gai_status) {
|
||||
THROW_EXCEPTION("InvalidArgumentException",
|
||||
"The value \"%s\" is not a valid IP address.",
|
||||
ip_address);
|
||||
return 1;
|
||||
}
|
||||
if (!addresses || !addresses->ai_addr) {
|
||||
THROW_EXCEPTION(
|
||||
"InvalidArgumentException",
|
||||
"getaddrinfo was successful but failed to set the addrinfo");
|
||||
return 1;
|
||||
}
|
||||
|
||||
int sa_family = addresses->ai_addr->sa_family;
|
||||
|
||||
int mmdb_error = MMDB_SUCCESS;
|
||||
MMDB_lookup_result_s result =
|
||||
MMDB_lookup_sockaddr(mmdb, addresses->ai_addr, &mmdb_error);
|
||||
|
||||
freeaddrinfo(addresses);
|
||||
|
||||
if (MMDB_SUCCESS != mmdb_error) {
|
||||
char *exception_name;
|
||||
if (MMDB_IPV6_LOOKUP_IN_IPV4_DATABASE_ERROR == mmdb_error) {
|
||||
exception_name = "InvalidArgumentException";
|
||||
} else {
|
||||
exception_name = PHP_MAXMINDDB_READER_EX_NS;
|
||||
}
|
||||
THROW_EXCEPTION(exception_name,
|
||||
"Error looking up %s. %s",
|
||||
ip_address,
|
||||
MMDB_strerror(mmdb_error));
|
||||
return 1;
|
||||
}
|
||||
|
||||
*prefix_len = result.netmask;
|
||||
|
||||
if (sa_family == AF_INET && mmdb->metadata.ip_version == 6) {
|
||||
// We return the prefix length given the IPv4 address. If there is
|
||||
// no IPv4 subtree, we return a prefix length of 0.
|
||||
*prefix_len = *prefix_len >= 96 ? *prefix_len - 96 : 0;
|
||||
}
|
||||
|
||||
if (!result.found_entry) {
|
||||
ZVAL_NULL(record);
|
||||
return 0;
|
||||
}
|
||||
|
||||
MMDB_entry_data_list_s *entry_data_list = NULL;
|
||||
int status = MMDB_get_entry_data_list(&result.entry, &entry_data_list);
|
||||
|
||||
if (MMDB_SUCCESS != status) {
|
||||
THROW_EXCEPTION(PHP_MAXMINDDB_READER_EX_NS,
|
||||
"Error while looking up data for %s. %s",
|
||||
ip_address,
|
||||
MMDB_strerror(status));
|
||||
MMDB_free_entry_data_list(entry_data_list);
|
||||
return 1;
|
||||
} else if (NULL == entry_data_list) {
|
||||
THROW_EXCEPTION(PHP_MAXMINDDB_READER_EX_NS,
|
||||
"Error while looking up data for %s. Your database may "
|
||||
"be corrupt or you have found a bug in libmaxminddb.",
|
||||
ip_address);
|
||||
return 1;
|
||||
}
|
||||
|
||||
handle_entry_data_list(entry_data_list, record TSRMLS_CC);
|
||||
MMDB_free_entry_data_list(entry_data_list);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ZEND_BEGIN_ARG_INFO_EX(arginfo_maxmindbreader_void, 0, 0, 0)
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
PHP_METHOD(MaxMind_Db_Reader, metadata) {
|
||||
if (ZEND_NUM_ARGS() != 0) {
|
||||
THROW_EXCEPTION("InvalidArgumentException",
|
||||
"Method takes no arguments.");
|
||||
return;
|
||||
}
|
||||
|
||||
const maxminddb_obj *const mmdb_obj =
|
||||
(maxminddb_obj *)Z_MAXMINDDB_P(getThis());
|
||||
|
||||
if (NULL == mmdb_obj->mmdb) {
|
||||
THROW_EXCEPTION("BadMethodCallException",
|
||||
"Attempt to read from a closed MaxMind DB.");
|
||||
return;
|
||||
}
|
||||
|
||||
const char *const name = ZEND_NS_NAME(PHP_MAXMINDDB_READER_NS, "Metadata");
|
||||
zend_class_entry *metadata_ce = lookup_class(name TSRMLS_CC);
|
||||
|
||||
object_init_ex(return_value, metadata_ce);
|
||||
|
||||
#ifdef ZEND_ENGINE_3
|
||||
zval _metadata_array;
|
||||
zval *metadata_array = &_metadata_array;
|
||||
ZVAL_NULL(metadata_array);
|
||||
#else
|
||||
zval *metadata_array;
|
||||
ALLOC_INIT_ZVAL(metadata_array);
|
||||
#endif
|
||||
|
||||
MMDB_entry_data_list_s *entry_data_list;
|
||||
MMDB_get_metadata_as_entry_data_list(mmdb_obj->mmdb, &entry_data_list);
|
||||
|
||||
handle_entry_data_list(entry_data_list, metadata_array TSRMLS_CC);
|
||||
MMDB_free_entry_data_list(entry_data_list);
|
||||
#if PHP_VERSION_ID >= 80000
|
||||
zend_call_method_with_1_params(Z_OBJ_P(return_value),
|
||||
metadata_ce,
|
||||
&metadata_ce->constructor,
|
||||
ZEND_CONSTRUCTOR_FUNC_NAME,
|
||||
NULL,
|
||||
metadata_array);
|
||||
zval_ptr_dtor(metadata_array);
|
||||
#elif defined(ZEND_ENGINE_3)
|
||||
zend_call_method_with_1_params(return_value,
|
||||
metadata_ce,
|
||||
&metadata_ce->constructor,
|
||||
ZEND_CONSTRUCTOR_FUNC_NAME,
|
||||
NULL,
|
||||
metadata_array);
|
||||
zval_ptr_dtor(metadata_array);
|
||||
#else
|
||||
zend_call_method_with_1_params(&return_value,
|
||||
metadata_ce,
|
||||
&metadata_ce->constructor,
|
||||
ZEND_CONSTRUCTOR_FUNC_NAME,
|
||||
NULL,
|
||||
metadata_array);
|
||||
zval_ptr_dtor(&metadata_array);
|
||||
#endif
|
||||
}
|
||||
|
||||
PHP_METHOD(MaxMind_Db_Reader, close) {
|
||||
if (ZEND_NUM_ARGS() != 0) {
|
||||
THROW_EXCEPTION("InvalidArgumentException",
|
||||
"Method takes no arguments.");
|
||||
return;
|
||||
}
|
||||
|
||||
maxminddb_obj *mmdb_obj = (maxminddb_obj *)Z_MAXMINDDB_P(getThis());
|
||||
|
||||
if (NULL == mmdb_obj->mmdb) {
|
||||
THROW_EXCEPTION("BadMethodCallException",
|
||||
"Attempt to close a closed MaxMind DB.");
|
||||
return;
|
||||
}
|
||||
MMDB_close(mmdb_obj->mmdb);
|
||||
efree(mmdb_obj->mmdb);
|
||||
mmdb_obj->mmdb = NULL;
|
||||
}
|
||||
|
||||
static const MMDB_entry_data_list_s *
|
||||
handle_entry_data_list(const MMDB_entry_data_list_s *entry_data_list,
|
||||
zval *z_value TSRMLS_DC) {
|
||||
switch (entry_data_list->entry_data.type) {
|
||||
case MMDB_DATA_TYPE_MAP:
|
||||
return handle_map(entry_data_list, z_value TSRMLS_CC);
|
||||
case MMDB_DATA_TYPE_ARRAY:
|
||||
return handle_array(entry_data_list, z_value TSRMLS_CC);
|
||||
case MMDB_DATA_TYPE_UTF8_STRING:
|
||||
_ZVAL_STRINGL(z_value,
|
||||
(char *)entry_data_list->entry_data.utf8_string,
|
||||
entry_data_list->entry_data.data_size);
|
||||
break;
|
||||
case MMDB_DATA_TYPE_BYTES:
|
||||
_ZVAL_STRINGL(z_value,
|
||||
(char *)entry_data_list->entry_data.bytes,
|
||||
entry_data_list->entry_data.data_size);
|
||||
break;
|
||||
case MMDB_DATA_TYPE_DOUBLE:
|
||||
ZVAL_DOUBLE(z_value, entry_data_list->entry_data.double_value);
|
||||
break;
|
||||
case MMDB_DATA_TYPE_FLOAT:
|
||||
ZVAL_DOUBLE(z_value, entry_data_list->entry_data.float_value);
|
||||
break;
|
||||
case MMDB_DATA_TYPE_UINT16:
|
||||
ZVAL_LONG(z_value, entry_data_list->entry_data.uint16);
|
||||
break;
|
||||
case MMDB_DATA_TYPE_UINT32:
|
||||
handle_uint32(entry_data_list, z_value TSRMLS_CC);
|
||||
break;
|
||||
case MMDB_DATA_TYPE_BOOLEAN:
|
||||
ZVAL_BOOL(z_value, entry_data_list->entry_data.boolean);
|
||||
break;
|
||||
case MMDB_DATA_TYPE_UINT64:
|
||||
handle_uint64(entry_data_list, z_value TSRMLS_CC);
|
||||
break;
|
||||
case MMDB_DATA_TYPE_UINT128:
|
||||
handle_uint128(entry_data_list, z_value TSRMLS_CC);
|
||||
break;
|
||||
case MMDB_DATA_TYPE_INT32:
|
||||
ZVAL_LONG(z_value, entry_data_list->entry_data.int32);
|
||||
break;
|
||||
default:
|
||||
THROW_EXCEPTION(PHP_MAXMINDDB_READER_EX_NS,
|
||||
"Invalid data type arguments: %d",
|
||||
entry_data_list->entry_data.type);
|
||||
return NULL;
|
||||
}
|
||||
return entry_data_list;
|
||||
}
|
||||
|
||||
static const MMDB_entry_data_list_s *
|
||||
handle_map(const MMDB_entry_data_list_s *entry_data_list,
|
||||
zval *z_value TSRMLS_DC) {
|
||||
array_init(z_value);
|
||||
const uint32_t map_size = entry_data_list->entry_data.data_size;
|
||||
|
||||
uint i;
|
||||
for (i = 0; i < map_size && entry_data_list; i++) {
|
||||
entry_data_list = entry_data_list->next;
|
||||
|
||||
char *key = estrndup((char *)entry_data_list->entry_data.utf8_string,
|
||||
entry_data_list->entry_data.data_size);
|
||||
if (NULL == key) {
|
||||
THROW_EXCEPTION(PHP_MAXMINDDB_READER_EX_NS,
|
||||
"Invalid data type arguments");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
entry_data_list = entry_data_list->next;
|
||||
#ifdef ZEND_ENGINE_3
|
||||
zval _new_value;
|
||||
zval *new_value = &_new_value;
|
||||
ZVAL_NULL(new_value);
|
||||
#else
|
||||
zval *new_value;
|
||||
ALLOC_INIT_ZVAL(new_value);
|
||||
#endif
|
||||
entry_data_list =
|
||||
handle_entry_data_list(entry_data_list, new_value TSRMLS_CC);
|
||||
add_assoc_zval(z_value, key, new_value);
|
||||
efree(key);
|
||||
}
|
||||
return entry_data_list;
|
||||
}
|
||||
|
||||
static const MMDB_entry_data_list_s *
|
||||
handle_array(const MMDB_entry_data_list_s *entry_data_list,
|
||||
zval *z_value TSRMLS_DC) {
|
||||
const uint32_t size = entry_data_list->entry_data.data_size;
|
||||
|
||||
array_init(z_value);
|
||||
|
||||
uint i;
|
||||
for (i = 0; i < size && entry_data_list; i++) {
|
||||
entry_data_list = entry_data_list->next;
|
||||
#ifdef ZEND_ENGINE_3
|
||||
zval _new_value;
|
||||
zval *new_value = &_new_value;
|
||||
ZVAL_NULL(new_value);
|
||||
#else
|
||||
zval *new_value;
|
||||
ALLOC_INIT_ZVAL(new_value);
|
||||
#endif
|
||||
entry_data_list =
|
||||
handle_entry_data_list(entry_data_list, new_value TSRMLS_CC);
|
||||
add_next_index_zval(z_value, new_value);
|
||||
}
|
||||
return entry_data_list;
|
||||
}
|
||||
|
||||
static void handle_uint128(const MMDB_entry_data_list_s *entry_data_list,
|
||||
zval *z_value TSRMLS_DC) {
|
||||
uint64_t high = 0;
|
||||
uint64_t low = 0;
|
||||
#if MMDB_UINT128_IS_BYTE_ARRAY
|
||||
int i;
|
||||
for (i = 0; i < 8; i++) {
|
||||
high = (high << 8) | entry_data_list->entry_data.uint128[i];
|
||||
}
|
||||
|
||||
for (i = 8; i < 16; i++) {
|
||||
low = (low << 8) | entry_data_list->entry_data.uint128[i];
|
||||
}
|
||||
#else
|
||||
high = entry_data_list->entry_data.uint128 >> 64;
|
||||
low = (uint64_t)entry_data_list->entry_data.uint128;
|
||||
#endif
|
||||
|
||||
char *num_str;
|
||||
spprintf(&num_str, 0, "0x%016" PRIX64 "%016" PRIX64, high, low);
|
||||
CHECK_ALLOCATED(num_str);
|
||||
|
||||
_ZVAL_STRING(z_value, num_str);
|
||||
efree(num_str);
|
||||
}
|
||||
|
||||
static void handle_uint32(const MMDB_entry_data_list_s *entry_data_list,
|
||||
zval *z_value TSRMLS_DC) {
|
||||
uint32_t val = entry_data_list->entry_data.uint32;
|
||||
|
||||
#if LONG_MAX >= UINT32_MAX
|
||||
ZVAL_LONG(z_value, val);
|
||||
return;
|
||||
#else
|
||||
if (val <= LONG_MAX) {
|
||||
ZVAL_LONG(z_value, val);
|
||||
return;
|
||||
}
|
||||
|
||||
char *int_str;
|
||||
spprintf(&int_str, 0, "%" PRIu32, val);
|
||||
CHECK_ALLOCATED(int_str);
|
||||
|
||||
_ZVAL_STRING(z_value, int_str);
|
||||
efree(int_str);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void handle_uint64(const MMDB_entry_data_list_s *entry_data_list,
|
||||
zval *z_value TSRMLS_DC) {
|
||||
uint64_t val = entry_data_list->entry_data.uint64;
|
||||
|
||||
#if LONG_MAX >= UINT64_MAX
|
||||
ZVAL_LONG(z_value, val);
|
||||
return;
|
||||
#else
|
||||
if (val <= LONG_MAX) {
|
||||
ZVAL_LONG(z_value, val);
|
||||
return;
|
||||
}
|
||||
|
||||
char *int_str;
|
||||
spprintf(&int_str, 0, "%" PRIu64, val);
|
||||
CHECK_ALLOCATED(int_str);
|
||||
|
||||
_ZVAL_STRING(z_value, int_str);
|
||||
efree(int_str);
|
||||
#endif
|
||||
}
|
||||
|
||||
static zend_class_entry *lookup_class(const char *name TSRMLS_DC) {
|
||||
#ifdef ZEND_ENGINE_3
|
||||
zend_string *n = zend_string_init(name, strlen(name), 0);
|
||||
zend_class_entry *ce = zend_lookup_class(n);
|
||||
zend_string_release(n);
|
||||
if (NULL == ce) {
|
||||
zend_error(E_ERROR, "Class %s not found", name);
|
||||
}
|
||||
return ce;
|
||||
#else
|
||||
zend_class_entry **ce;
|
||||
if (FAILURE == zend_lookup_class(name, strlen(name), &ce TSRMLS_CC)) {
|
||||
zend_error(E_ERROR, "Class %s not found", name);
|
||||
}
|
||||
return *ce;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void maxminddb_free_storage(free_obj_t *object TSRMLS_DC) {
|
||||
maxminddb_obj *obj =
|
||||
php_maxminddb_fetch_object((zend_object *)object TSRMLS_CC);
|
||||
if (obj->mmdb != NULL) {
|
||||
MMDB_close(obj->mmdb);
|
||||
efree(obj->mmdb);
|
||||
}
|
||||
|
||||
zend_object_std_dtor(&obj->std TSRMLS_CC);
|
||||
#ifndef ZEND_ENGINE_3
|
||||
efree(object);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef ZEND_ENGINE_3
|
||||
static zend_object *maxminddb_create_handler(zend_class_entry *type TSRMLS_DC) {
|
||||
maxminddb_obj *obj = (maxminddb_obj *)ecalloc(1, sizeof(maxminddb_obj));
|
||||
zend_object_std_init(&obj->std, type TSRMLS_CC);
|
||||
object_properties_init(&(obj->std), type);
|
||||
|
||||
obj->std.handlers = &maxminddb_obj_handlers;
|
||||
|
||||
return &obj->std;
|
||||
}
|
||||
#else
|
||||
static zend_object_value
|
||||
maxminddb_create_handler(zend_class_entry *type TSRMLS_DC) {
|
||||
zend_object_value retval;
|
||||
|
||||
maxminddb_obj *obj = (maxminddb_obj *)ecalloc(1, sizeof(maxminddb_obj));
|
||||
zend_object_std_init(&obj->std, type TSRMLS_CC);
|
||||
object_properties_init(&(obj->std), type);
|
||||
|
||||
retval.handle = zend_objects_store_put(
|
||||
obj, NULL, maxminddb_free_storage, NULL TSRMLS_CC);
|
||||
retval.handlers = &maxminddb_obj_handlers;
|
||||
|
||||
return retval;
|
||||
}
|
||||
#endif
|
||||
|
||||
// clang-format off
|
||||
static zend_function_entry maxminddb_methods[] = {
|
||||
PHP_ME(MaxMind_Db_Reader, __construct, arginfo_maxmindbreader_construct,
|
||||
ZEND_ACC_PUBLIC | ZEND_ACC_CTOR)
|
||||
PHP_ME(MaxMind_Db_Reader, close, arginfo_maxmindbreader_void, ZEND_ACC_PUBLIC)
|
||||
PHP_ME(MaxMind_Db_Reader, get, arginfo_maxmindbreader_get, ZEND_ACC_PUBLIC)
|
||||
PHP_ME(MaxMind_Db_Reader, getWithPrefixLen, arginfo_maxmindbreader_get, ZEND_ACC_PUBLIC)
|
||||
PHP_ME(MaxMind_Db_Reader, metadata, arginfo_maxmindbreader_void, ZEND_ACC_PUBLIC)
|
||||
{ NULL, NULL, NULL }
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
PHP_MINIT_FUNCTION(maxminddb) {
|
||||
zend_class_entry ce;
|
||||
|
||||
INIT_CLASS_ENTRY(ce, PHP_MAXMINDDB_READER_NS, maxminddb_methods);
|
||||
maxminddb_ce = zend_register_internal_class(&ce TSRMLS_CC);
|
||||
maxminddb_ce->create_object = maxminddb_create_handler;
|
||||
memcpy(&maxminddb_obj_handlers,
|
||||
zend_get_std_object_handlers(),
|
||||
sizeof(zend_object_handlers));
|
||||
maxminddb_obj_handlers.clone_obj = NULL;
|
||||
#ifdef ZEND_ENGINE_3
|
||||
maxminddb_obj_handlers.offset = XtOffsetOf(maxminddb_obj, std);
|
||||
maxminddb_obj_handlers.free_obj = maxminddb_free_storage;
|
||||
#endif
|
||||
zend_declare_class_constant_string(maxminddb_ce,
|
||||
"MMDB_LIB_VERSION",
|
||||
sizeof("MMDB_LIB_VERSION") - 1,
|
||||
MMDB_lib_version() TSRMLS_CC);
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
static PHP_MINFO_FUNCTION(maxminddb) {
|
||||
php_info_print_table_start();
|
||||
|
||||
php_info_print_table_row(2, "MaxMind DB Reader", "enabled");
|
||||
php_info_print_table_row(
|
||||
2, "maxminddb extension version", PHP_MAXMINDDB_VERSION);
|
||||
php_info_print_table_row(
|
||||
2, "libmaxminddb library version", MMDB_lib_version());
|
||||
|
||||
php_info_print_table_end();
|
||||
}
|
||||
|
||||
zend_module_entry maxminddb_module_entry = {STANDARD_MODULE_HEADER,
|
||||
PHP_MAXMINDDB_EXTNAME,
|
||||
NULL,
|
||||
PHP_MINIT(maxminddb),
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
PHP_MINFO(maxminddb),
|
||||
PHP_MAXMINDDB_VERSION,
|
||||
STANDARD_MODULE_PROPERTIES};
|
||||
|
||||
#ifdef COMPILE_DL_MAXMINDDB
|
||||
ZEND_GET_MODULE(maxminddb)
|
||||
#endif
|
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.6.0"
|
||||
#define PHP_MAXMINDDB_EXTNAME "maxminddb"
|
||||
|
||||
extern zend_module_entry maxminddb_module_entry;
|
||||
#define phpext_maxminddb_ptr &maxminddb_module_entry
|
||||
|
||||
#endif
|
12
vendor/maxmind-db/reader/ext/tests/001-load.phpt
vendored
Normal file
12
vendor/maxmind-db/reader/ext/tests/001-load.phpt
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
--TEST--
|
||||
Check for maxminddb presence
|
||||
--SKIPIF--
|
||||
<?php if (!extension_loaded('maxminddb')) {
|
||||
echo 'skip';
|
||||
} ?>
|
||||
--FILE--
|
||||
<?php
|
||||
echo 'maxminddb extension is available';
|
||||
?>
|
||||
--EXPECT--
|
||||
maxminddb extension is available
|
13
vendor/maxmind-db/reader/ext/tests/002-final.phpt
vendored
Normal file
13
vendor/maxmind-db/reader/ext/tests/002-final.phpt
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
--TEST--
|
||||
Check that Reader class is not final
|
||||
--SKIPIF--
|
||||
<?php if (!extension_loaded('maxminddb')) {
|
||||
echo 'skip';
|
||||
} ?>
|
||||
--FILE--
|
||||
<?php
|
||||
$reflectionClass = new \ReflectionClass('MaxMind\Db\Reader');
|
||||
var_dump($reflectionClass->isFinal());
|
||||
?>
|
||||
--EXPECT--
|
||||
bool(false)
|
12
vendor/maxmind-db/reader/ext/tests/003-open-basedir.phpt
vendored
Normal file
12
vendor/maxmind-db/reader/ext/tests/003-open-basedir.phpt
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
--TEST--
|
||||
openbase_dir is followed
|
||||
--INI--
|
||||
open_basedir=/--dne--
|
||||
--FILE--
|
||||
<?php
|
||||
use MaxMind\Db\Reader;
|
||||
|
||||
$reader = new Reader('/usr/local/share/GeoIP/GeoIP2-City.mmdb');
|
||||
?>
|
||||
--EXPECTREGEX--
|
||||
.*open_basedir restriction in effect.*
|
327
vendor/maxmind-db/reader/src/MaxMind/Db/Reader.php
vendored
Normal file
327
vendor/maxmind-db/reader/src/MaxMind/Db/Reader.php
vendored
Normal file
@ -0,0 +1,327 @@
|
||||
<?php
|
||||
|
||||
namespace MaxMind\Db;
|
||||
|
||||
use BadMethodCallException;
|
||||
use Exception;
|
||||
use InvalidArgumentException;
|
||||
use MaxMind\Db\Reader\Decoder;
|
||||
use MaxMind\Db\Reader\InvalidDatabaseException;
|
||||
use MaxMind\Db\Reader\Metadata;
|
||||
use MaxMind\Db\Reader\Util;
|
||||
use UnexpectedValueException;
|
||||
|
||||
/**
|
||||
* Instances of this class provide a reader for the MaxMind DB format. IP
|
||||
* addresses can be looked up using the get method.
|
||||
*/
|
||||
class Reader
|
||||
{
|
||||
private static $DATA_SECTION_SEPARATOR_SIZE = 16;
|
||||
private static $METADATA_START_MARKER = "\xAB\xCD\xEFMaxMind.com";
|
||||
private static $METADATA_START_MARKER_LENGTH = 14;
|
||||
private static $METADATA_MAX_SIZE = 131072; // 128 * 1024 = 128KB
|
||||
|
||||
private $decoder;
|
||||
private $fileHandle;
|
||||
private $fileSize;
|
||||
private $ipV4Start;
|
||||
private $metadata;
|
||||
|
||||
/**
|
||||
* Constructs a Reader for the MaxMind DB format. The file passed to it must
|
||||
* be a valid MaxMind DB file such as a GeoIp2 database file.
|
||||
*
|
||||
* @param string $database
|
||||
* the MaxMind DB file to use
|
||||
*
|
||||
* @throws InvalidArgumentException for invalid database path or unknown arguments
|
||||
* @throws \MaxMind\Db\Reader\InvalidDatabaseException
|
||||
* if the database is invalid or there is an error reading
|
||||
* from it
|
||||
*/
|
||||
public function __construct($database)
|
||||
{
|
||||
if (\func_num_args() !== 1) {
|
||||
throw new InvalidArgumentException(
|
||||
'The constructor takes exactly one argument.'
|
||||
);
|
||||
}
|
||||
|
||||
if (!is_readable($database)) {
|
||||
throw new InvalidArgumentException(
|
||||
"The file \"$database\" does not exist or is not readable."
|
||||
);
|
||||
}
|
||||
$this->fileHandle = @fopen($database, 'rb');
|
||||
if ($this->fileHandle === false) {
|
||||
throw new InvalidArgumentException(
|
||||
"Error opening \"$database\"."
|
||||
);
|
||||
}
|
||||
$this->fileSize = @filesize($database);
|
||||
if ($this->fileSize === false) {
|
||||
throw new UnexpectedValueException(
|
||||
"Error determining the size of \"$database\"."
|
||||
);
|
||||
}
|
||||
|
||||
$start = $this->findMetadataStart($database);
|
||||
$metadataDecoder = new Decoder($this->fileHandle, $start);
|
||||
list($metadataArray) = $metadataDecoder->decode($start);
|
||||
$this->metadata = new Metadata($metadataArray);
|
||||
$this->decoder = new Decoder(
|
||||
$this->fileHandle,
|
||||
$this->metadata->searchTreeSize + self::$DATA_SECTION_SEPARATOR_SIZE
|
||||
);
|
||||
$this->ipV4Start = $this->ipV4StartNode();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the record for the IP address.
|
||||
*
|
||||
* @param string $ipAddress
|
||||
* the IP address to look up
|
||||
*
|
||||
* @throws BadMethodCallException if this method is called on a closed database
|
||||
* @throws InvalidArgumentException if something other than a single IP address is passed to the method
|
||||
* @throws InvalidDatabaseException
|
||||
* if the database is invalid or there is an error reading
|
||||
* from it
|
||||
*
|
||||
* @return mixed the record for the IP address
|
||||
*/
|
||||
public function get($ipAddress)
|
||||
{
|
||||
if (\func_num_args() !== 1) {
|
||||
throw new InvalidArgumentException(
|
||||
'Method takes exactly one argument.'
|
||||
);
|
||||
}
|
||||
list($record) = $this->getWithPrefixLen($ipAddress);
|
||||
|
||||
return $record;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the record for the IP address and its associated network prefix length.
|
||||
*
|
||||
* @param string $ipAddress
|
||||
* the IP address to look up
|
||||
*
|
||||
* @throws BadMethodCallException if this method is called on a closed database
|
||||
* @throws InvalidArgumentException if something other than a single IP address is passed to the method
|
||||
* @throws InvalidDatabaseException
|
||||
* if the database is invalid or there is an error reading
|
||||
* from it
|
||||
*
|
||||
* @return array an array where the first element is the record and the
|
||||
* second the network prefix length for the record
|
||||
*/
|
||||
public function getWithPrefixLen($ipAddress)
|
||||
{
|
||||
if (\func_num_args() !== 1) {
|
||||
throw new InvalidArgumentException(
|
||||
'Method takes exactly one argument.'
|
||||
);
|
||||
}
|
||||
|
||||
if (!\is_resource($this->fileHandle)) {
|
||||
throw new BadMethodCallException(
|
||||
'Attempt to read from a closed MaxMind DB.'
|
||||
);
|
||||
}
|
||||
|
||||
if (!filter_var($ipAddress, FILTER_VALIDATE_IP)) {
|
||||
throw new InvalidArgumentException(
|
||||
"The value \"$ipAddress\" is not a valid IP address."
|
||||
);
|
||||
}
|
||||
|
||||
list($pointer, $prefixLen) = $this->findAddressInTree($ipAddress);
|
||||
if ($pointer === 0) {
|
||||
return [null, $prefixLen];
|
||||
}
|
||||
|
||||
return [$this->resolveDataPointer($pointer), $prefixLen];
|
||||
}
|
||||
|
||||
private function findAddressInTree($ipAddress)
|
||||
{
|
||||
$rawAddress = unpack('C*', inet_pton($ipAddress));
|
||||
|
||||
$bitCount = \count($rawAddress) * 8;
|
||||
|
||||
// The first node of the tree is always node 0, at the beginning of the
|
||||
// value
|
||||
$node = 0;
|
||||
|
||||
$metadata = $this->metadata;
|
||||
|
||||
// Check if we are looking up an IPv4 address in an IPv6 tree. If this
|
||||
// is the case, we can skip over the first 96 nodes.
|
||||
if ($metadata->ipVersion === 6) {
|
||||
if ($bitCount === 32) {
|
||||
$node = $this->ipV4Start;
|
||||
}
|
||||
} elseif ($metadata->ipVersion === 4 && $bitCount === 128) {
|
||||
throw new InvalidArgumentException(
|
||||
"Error looking up $ipAddress. You attempted to look up an"
|
||||
. ' IPv6 address in an IPv4-only database.'
|
||||
);
|
||||
}
|
||||
|
||||
$nodeCount = $metadata->nodeCount;
|
||||
|
||||
for ($i = 0; $i < $bitCount && $node < $nodeCount; ++$i) {
|
||||
$tempBit = 0xFF & $rawAddress[($i >> 3) + 1];
|
||||
$bit = 1 & ($tempBit >> 7 - ($i % 8));
|
||||
|
||||
$node = $this->readNode($node, $bit);
|
||||
}
|
||||
if ($node === $nodeCount) {
|
||||
// Record is empty
|
||||
return [0, $i];
|
||||
} elseif ($node > $nodeCount) {
|
||||
// Record is a data pointer
|
||||
return [$node, $i];
|
||||
}
|
||||
throw new InvalidDatabaseException('Something bad happened');
|
||||
}
|
||||
|
||||
private function ipV4StartNode()
|
||||
{
|
||||
// If we have an IPv4 database, the start node is the first node
|
||||
if ($this->metadata->ipVersion === 4) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$node = 0;
|
||||
|
||||
for ($i = 0; $i < 96 && $node < $this->metadata->nodeCount; ++$i) {
|
||||
$node = $this->readNode($node, 0);
|
||||
}
|
||||
|
||||
return $node;
|
||||
}
|
||||
|
||||
private function readNode($nodeNumber, $index)
|
||||
{
|
||||
$baseOffset = $nodeNumber * $this->metadata->nodeByteSize;
|
||||
|
||||
switch ($this->metadata->recordSize) {
|
||||
case 24:
|
||||
$bytes = Util::read($this->fileHandle, $baseOffset + $index * 3, 3);
|
||||
list(, $node) = unpack('N', "\x00" . $bytes);
|
||||
|
||||
return $node;
|
||||
case 28:
|
||||
$bytes = Util::read($this->fileHandle, $baseOffset + 3 * $index, 4);
|
||||
if ($index === 0) {
|
||||
$middle = (0xF0 & \ord($bytes[3])) >> 4;
|
||||
} else {
|
||||
$middle = 0x0F & \ord($bytes[0]);
|
||||
}
|
||||
list(, $node) = unpack('N', \chr($middle) . substr($bytes, $index, 3));
|
||||
|
||||
return $node;
|
||||
case 32:
|
||||
$bytes = Util::read($this->fileHandle, $baseOffset + $index * 4, 4);
|
||||
list(, $node) = unpack('N', $bytes);
|
||||
|
||||
return $node;
|
||||
default:
|
||||
throw new InvalidDatabaseException(
|
||||
'Unknown record size: '
|
||||
. $this->metadata->recordSize
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private function resolveDataPointer($pointer)
|
||||
{
|
||||
$resolved = $pointer - $this->metadata->nodeCount
|
||||
+ $this->metadata->searchTreeSize;
|
||||
if ($resolved >= $this->fileSize) {
|
||||
throw new InvalidDatabaseException(
|
||||
"The MaxMind DB file's search tree is corrupt"
|
||||
);
|
||||
}
|
||||
|
||||
list($data) = $this->decoder->decode($resolved);
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/*
|
||||
* This is an extremely naive but reasonably readable implementation. There
|
||||
* are much faster algorithms (e.g., Boyer-Moore) for this if speed is ever
|
||||
* an issue, but I suspect it won't be.
|
||||
*/
|
||||
private function findMetadataStart($filename)
|
||||
{
|
||||
$handle = $this->fileHandle;
|
||||
$fstat = fstat($handle);
|
||||
$fileSize = $fstat['size'];
|
||||
$marker = self::$METADATA_START_MARKER;
|
||||
$markerLength = self::$METADATA_START_MARKER_LENGTH;
|
||||
|
||||
$minStart = $fileSize - min(self::$METADATA_MAX_SIZE, $fileSize);
|
||||
|
||||
for ($offset = $fileSize - $markerLength; $offset >= $minStart; --$offset) {
|
||||
if (fseek($handle, $offset) !== 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
$value = fread($handle, $markerLength);
|
||||
if ($value === $marker) {
|
||||
return $offset + $markerLength;
|
||||
}
|
||||
}
|
||||
throw new InvalidDatabaseException(
|
||||
"Error opening database file ($filename). " .
|
||||
'Is this a valid MaxMind DB file?'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws InvalidArgumentException if arguments are passed to the method
|
||||
* @throws BadMethodCallException if the database has been closed
|
||||
*
|
||||
* @return Metadata object for the database
|
||||
*/
|
||||
public function metadata()
|
||||
{
|
||||
if (\func_num_args()) {
|
||||
throw new InvalidArgumentException(
|
||||
'Method takes no arguments.'
|
||||
);
|
||||
}
|
||||
|
||||
// Not technically required, but this makes it consistent with
|
||||
// C extension and it allows us to change our implementation later.
|
||||
if (!\is_resource($this->fileHandle)) {
|
||||
throw new BadMethodCallException(
|
||||
'Attempt to read from a closed MaxMind DB.'
|
||||
);
|
||||
}
|
||||
|
||||
return $this->metadata;
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the MaxMind DB and returns resources to the system.
|
||||
*
|
||||
* @throws Exception
|
||||
* if an I/O error occurs
|
||||
*/
|
||||
public function close()
|
||||
{
|
||||
if (!\is_resource($this->fileHandle)) {
|
||||
throw new BadMethodCallException(
|
||||
'Attempt to close a closed MaxMind DB.'
|
||||
);
|
||||
}
|
||||
fclose($this->fileHandle);
|
||||
}
|
||||
}
|
356
vendor/maxmind-db/reader/src/MaxMind/Db/Reader/Decoder.php
vendored
Normal file
356
vendor/maxmind-db/reader/src/MaxMind/Db/Reader/Decoder.php
vendored
Normal file
@ -0,0 +1,356 @@
|
||||
<?php
|
||||
|
||||
namespace MaxMind\Db\Reader;
|
||||
|
||||
// @codingStandardsIgnoreLine
|
||||
use RuntimeException;
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*
|
||||
* We subtract 1 from the log to protect against precision loss.
|
||||
*/
|
||||
\define(__NAMESPACE__ . '\_MM_MAX_INT_BYTES', (log(PHP_INT_MAX, 2) - 1) / 8);
|
||||
|
||||
class Decoder
|
||||
{
|
||||
private $fileStream;
|
||||
private $pointerBase;
|
||||
private $pointerBaseByteSize;
|
||||
// This is only used for unit testing
|
||||
private $pointerTestHack;
|
||||
private $switchByteOrder;
|
||||
|
||||
/** @ignore */
|
||||
const _EXTENDED = 0;
|
||||
/** @ignore */
|
||||
const _POINTER = 1;
|
||||
/** @ignore */
|
||||
const _UTF8_STRING = 2;
|
||||
/** @ignore */
|
||||
const _DOUBLE = 3;
|
||||
/** @ignore */
|
||||
const _BYTES = 4;
|
||||
/** @ignore */
|
||||
const _UINT16 = 5;
|
||||
/** @ignore */
|
||||
const _UINT32 = 6;
|
||||
/** @ignore */
|
||||
const _MAP = 7;
|
||||
/** @ignore */
|
||||
const _INT32 = 8;
|
||||
/** @ignore */
|
||||
const _UINT64 = 9;
|
||||
/** @ignore */
|
||||
const _UINT128 = 10;
|
||||
/** @ignore */
|
||||
const _ARRAY = 11;
|
||||
/** @ignore */
|
||||
const _CONTAINER = 12;
|
||||
/** @ignore */
|
||||
const _END_MARKER = 13;
|
||||
/** @ignore */
|
||||
const _BOOLEAN = 14;
|
||||
/** @ignore */
|
||||
const _FLOAT = 15;
|
||||
|
||||
public function __construct(
|
||||
$fileStream,
|
||||
$pointerBase = 0,
|
||||
$pointerTestHack = false
|
||||
) {
|
||||
$this->fileStream = $fileStream;
|
||||
$this->pointerBase = $pointerBase;
|
||||
|
||||
$this->pointerBaseByteSize = $pointerBase > 0 ? log($pointerBase, 2) / 8 : 0;
|
||||
$this->pointerTestHack = $pointerTestHack;
|
||||
|
||||
$this->switchByteOrder = $this->isPlatformLittleEndian();
|
||||
}
|
||||
|
||||
public function decode($offset)
|
||||
{
|
||||
$ctrlByte = \ord(Util::read($this->fileStream, $offset, 1));
|
||||
++$offset;
|
||||
|
||||
$type = $ctrlByte >> 5;
|
||||
|
||||
// Pointers are a special case, we don't read the next $size bytes, we
|
||||
// use the size to determine the length of the pointer and then follow
|
||||
// it.
|
||||
if ($type === self::_POINTER) {
|
||||
list($pointer, $offset) = $this->decodePointer($ctrlByte, $offset);
|
||||
|
||||
// for unit testing
|
||||
if ($this->pointerTestHack) {
|
||||
return [$pointer];
|
||||
}
|
||||
|
||||
list($result) = $this->decode($pointer);
|
||||
|
||||
return [$result, $offset];
|
||||
}
|
||||
|
||||
if ($type === self::_EXTENDED) {
|
||||
$nextByte = \ord(Util::read($this->fileStream, $offset, 1));
|
||||
|
||||
$type = $nextByte + 7;
|
||||
|
||||
if ($type < 8) {
|
||||
throw new InvalidDatabaseException(
|
||||
'Something went horribly wrong in the decoder. An extended type '
|
||||
. 'resolved to a type number < 8 ('
|
||||
. $type
|
||||
. ')'
|
||||
);
|
||||
}
|
||||
|
||||
++$offset;
|
||||
}
|
||||
|
||||
list($size, $offset) = $this->sizeFromCtrlByte($ctrlByte, $offset);
|
||||
|
||||
return $this->decodeByType($type, $offset, $size);
|
||||
}
|
||||
|
||||
private function decodeByType($type, $offset, $size)
|
||||
{
|
||||
switch ($type) {
|
||||
case self::_MAP:
|
||||
return $this->decodeMap($size, $offset);
|
||||
case self::_ARRAY:
|
||||
return $this->decodeArray($size, $offset);
|
||||
case self::_BOOLEAN:
|
||||
return [$this->decodeBoolean($size), $offset];
|
||||
}
|
||||
|
||||
$newOffset = $offset + $size;
|
||||
$bytes = Util::read($this->fileStream, $offset, $size);
|
||||
switch ($type) {
|
||||
case self::_BYTES:
|
||||
case self::_UTF8_STRING:
|
||||
return [$bytes, $newOffset];
|
||||
case self::_DOUBLE:
|
||||
$this->verifySize(8, $size);
|
||||
|
||||
return [$this->decodeDouble($bytes), $newOffset];
|
||||
case self::_FLOAT:
|
||||
$this->verifySize(4, $size);
|
||||
|
||||
return [$this->decodeFloat($bytes), $newOffset];
|
||||
case self::_INT32:
|
||||
return [$this->decodeInt32($bytes, $size), $newOffset];
|
||||
case self::_UINT16:
|
||||
case self::_UINT32:
|
||||
case self::_UINT64:
|
||||
case self::_UINT128:
|
||||
return [$this->decodeUint($bytes, $size), $newOffset];
|
||||
default:
|
||||
throw new InvalidDatabaseException(
|
||||
'Unknown or unexpected type: ' . $type
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private function verifySize($expected, $actual)
|
||||
{
|
||||
if ($expected !== $actual) {
|
||||
throw new InvalidDatabaseException(
|
||||
"The MaxMind DB file's data section contains bad data (unknown data type or corrupt data)"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private function decodeArray($size, $offset)
|
||||
{
|
||||
$array = [];
|
||||
|
||||
for ($i = 0; $i < $size; ++$i) {
|
||||
list($value, $offset) = $this->decode($offset);
|
||||
array_push($array, $value);
|
||||
}
|
||||
|
||||
return [$array, $offset];
|
||||
}
|
||||
|
||||
private function decodeBoolean($size)
|
||||
{
|
||||
return $size === 0 ? false : true;
|
||||
}
|
||||
|
||||
private function decodeDouble($bits)
|
||||
{
|
||||
// This assumes IEEE 754 doubles, but most (all?) modern platforms
|
||||
// use them.
|
||||
//
|
||||
// We are not using the "E" format as that was only added in
|
||||
// 7.0.15 and 7.1.1. As such, we must switch byte order on
|
||||
// little endian machines.
|
||||
list(, $double) = unpack('d', $this->maybeSwitchByteOrder($bits));
|
||||
|
||||
return $double;
|
||||
}
|
||||
|
||||
private function decodeFloat($bits)
|
||||
{
|
||||
// This assumes IEEE 754 floats, but most (all?) modern platforms
|
||||
// use them.
|
||||
//
|
||||
// We are not using the "G" format as that was only added in
|
||||
// 7.0.15 and 7.1.1. As such, we must switch byte order on
|
||||
// little endian machines.
|
||||
list(, $float) = unpack('f', $this->maybeSwitchByteOrder($bits));
|
||||
|
||||
return $float;
|
||||
}
|
||||
|
||||
private function decodeInt32($bytes, $size)
|
||||
{
|
||||
switch ($size) {
|
||||
case 0:
|
||||
return 0;
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
$bytes = str_pad($bytes, 4, "\x00", STR_PAD_LEFT);
|
||||
break;
|
||||
case 4:
|
||||
break;
|
||||
default:
|
||||
throw new InvalidDatabaseException(
|
||||
"The MaxMind DB file's data section contains bad data (unknown data type or corrupt data)"
|
||||
);
|
||||
}
|
||||
|
||||
list(, $int) = unpack('l', $this->maybeSwitchByteOrder($bytes));
|
||||
|
||||
return $int;
|
||||
}
|
||||
|
||||
private function decodeMap($size, $offset)
|
||||
{
|
||||
$map = [];
|
||||
|
||||
for ($i = 0; $i < $size; ++$i) {
|
||||
list($key, $offset) = $this->decode($offset);
|
||||
list($value, $offset) = $this->decode($offset);
|
||||
$map[$key] = $value;
|
||||
}
|
||||
|
||||
return [$map, $offset];
|
||||
}
|
||||
|
||||
private function decodePointer($ctrlByte, $offset)
|
||||
{
|
||||
$pointerSize = (($ctrlByte >> 3) & 0x3) + 1;
|
||||
|
||||
$buffer = Util::read($this->fileStream, $offset, $pointerSize);
|
||||
$offset = $offset + $pointerSize;
|
||||
|
||||
switch ($pointerSize) {
|
||||
case 1:
|
||||
$packed = \chr($ctrlByte & 0x7) . $buffer;
|
||||
list(, $pointer) = unpack('n', $packed);
|
||||
$pointer += $this->pointerBase;
|
||||
break;
|
||||
case 2:
|
||||
$packed = "\x00" . \chr($ctrlByte & 0x7) . $buffer;
|
||||
list(, $pointer) = unpack('N', $packed);
|
||||
$pointer += $this->pointerBase + 2048;
|
||||
break;
|
||||
case 3:
|
||||
$packed = \chr($ctrlByte & 0x7) . $buffer;
|
||||
|
||||
// It is safe to use 'N' here, even on 32 bit machines as the
|
||||
// first bit is 0.
|
||||
list(, $pointer) = unpack('N', $packed);
|
||||
$pointer += $this->pointerBase + 526336;
|
||||
break;
|
||||
case 4:
|
||||
// We cannot use unpack here as we might overflow on 32 bit
|
||||
// machines
|
||||
$pointerOffset = $this->decodeUint($buffer, $pointerSize);
|
||||
|
||||
$byteLength = $pointerSize + $this->pointerBaseByteSize;
|
||||
|
||||
if ($byteLength <= _MM_MAX_INT_BYTES) {
|
||||
$pointer = $pointerOffset + $this->pointerBase;
|
||||
} elseif (\extension_loaded('gmp')) {
|
||||
$pointer = gmp_strval(gmp_add($pointerOffset, $this->pointerBase));
|
||||
} elseif (\extension_loaded('bcmath')) {
|
||||
$pointer = bcadd($pointerOffset, $this->pointerBase);
|
||||
} else {
|
||||
throw new RuntimeException(
|
||||
'The gmp or bcmath extension must be installed to read this database.'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return [$pointer, $offset];
|
||||
}
|
||||
|
||||
private function decodeUint($bytes, $byteLength)
|
||||
{
|
||||
if ($byteLength === 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$integer = 0;
|
||||
|
||||
for ($i = 0; $i < $byteLength; ++$i) {
|
||||
$part = \ord($bytes[$i]);
|
||||
|
||||
// We only use gmp or bcmath if the final value is too big
|
||||
if ($byteLength <= _MM_MAX_INT_BYTES) {
|
||||
$integer = ($integer << 8) + $part;
|
||||
} elseif (\extension_loaded('gmp')) {
|
||||
$integer = gmp_strval(gmp_add(gmp_mul($integer, 256), $part));
|
||||
} elseif (\extension_loaded('bcmath')) {
|
||||
$integer = bcadd(bcmul($integer, 256), $part);
|
||||
} else {
|
||||
throw new RuntimeException(
|
||||
'The gmp or bcmath extension must be installed to read this database.'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return $integer;
|
||||
}
|
||||
|
||||
private function sizeFromCtrlByte($ctrlByte, $offset)
|
||||
{
|
||||
$size = $ctrlByte & 0x1f;
|
||||
|
||||
if ($size < 29) {
|
||||
return [$size, $offset];
|
||||
}
|
||||
|
||||
$bytesToRead = $size - 28;
|
||||
$bytes = Util::read($this->fileStream, $offset, $bytesToRead);
|
||||
|
||||
if ($size === 29) {
|
||||
$size = 29 + \ord($bytes);
|
||||
} elseif ($size === 30) {
|
||||
list(, $adjust) = unpack('n', $bytes);
|
||||
$size = 285 + $adjust;
|
||||
} elseif ($size > 30) {
|
||||
list(, $adjust) = unpack('N', "\x00" . $bytes);
|
||||
$size = $adjust + 65821;
|
||||
}
|
||||
|
||||
return [$size, $offset + $bytesToRead];
|
||||
}
|
||||
|
||||
private function maybeSwitchByteOrder($bytes)
|
||||
{
|
||||
return $this->switchByteOrder ? strrev($bytes) : $bytes;
|
||||
}
|
||||
|
||||
private function isPlatformLittleEndian()
|
||||
{
|
||||
$testint = 0x00FF;
|
||||
$packed = pack('S', $testint);
|
||||
|
||||
return $testint === current(unpack('v', $packed));
|
||||
}
|
||||
}
|
12
vendor/maxmind-db/reader/src/MaxMind/Db/Reader/InvalidDatabaseException.php
vendored
Normal file
12
vendor/maxmind-db/reader/src/MaxMind/Db/Reader/InvalidDatabaseException.php
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
<?php
|
||||
|
||||
namespace MaxMind\Db\Reader;
|
||||
|
||||
use Exception;
|
||||
|
||||
/**
|
||||
* This class should be thrown when unexpected data is found in the database.
|
||||
*/
|
||||
class InvalidDatabaseException extends Exception
|
||||
{
|
||||
}
|
88
vendor/maxmind-db/reader/src/MaxMind/Db/Reader/Metadata.php
vendored
Normal file
88
vendor/maxmind-db/reader/src/MaxMind/Db/Reader/Metadata.php
vendored
Normal file
@ -0,0 +1,88 @@
|
||||
<?php
|
||||
|
||||
namespace MaxMind\Db\Reader;
|
||||
|
||||
/**
|
||||
* This class provides the metadata for the MaxMind DB file.
|
||||
*
|
||||
* @property int $nodeCount This is an unsigned 32-bit
|
||||
* integer indicating the number of
|
||||
* nodes in the search tree.
|
||||
* @property int $recordSize This is an unsigned 16-bit
|
||||
* integer. It indicates the number
|
||||
* of bits in a record in the search
|
||||
* tree. Note that each node
|
||||
* consists of two records.
|
||||
* @property int $ipVersion This is an unsigned 16-bit
|
||||
* integer which is always 4 or 6.
|
||||
* It indicates whether the database
|
||||
* contains IPv4 or IPv6 address
|
||||
* data.
|
||||
* @property string $databaseType This is a string that indicates
|
||||
* the structure of each data record
|
||||
* associated with an IP address.
|
||||
* The actual definition of these
|
||||
* structures is left up to the
|
||||
* database creator.
|
||||
* @property array $languages An array of strings, each of
|
||||
* which is a language code. A given
|
||||
* record may contain data items
|
||||
* that have been localized to some
|
||||
* or all of these languages. This
|
||||
* may be undefined.
|
||||
* @property int $binaryFormatMajorVersion This is an unsigned 16-bit
|
||||
* integer indicating the major
|
||||
* version number for the database's
|
||||
* binary format.
|
||||
* @property int $binaryFormatMinorVersion This is an unsigned 16-bit
|
||||
* integer indicating the minor
|
||||
* version number for the database's
|
||||
* binary format.
|
||||
* @property int $buildEpoch This is an unsigned 64-bit
|
||||
* integer that contains the
|
||||
* database build timestamp as a
|
||||
* Unix epoch value.
|
||||
* @property array $description This key will always point to a
|
||||
* map (associative array). The keys
|
||||
* of that map will be language
|
||||
* codes, and the values will be a
|
||||
* description in that language as a
|
||||
* UTF-8 string. May be undefined
|
||||
* for some databases.
|
||||
*/
|
||||
class Metadata
|
||||
{
|
||||
private $binaryFormatMajorVersion;
|
||||
private $binaryFormatMinorVersion;
|
||||
private $buildEpoch;
|
||||
private $databaseType;
|
||||
private $description;
|
||||
private $ipVersion;
|
||||
private $languages;
|
||||
private $nodeByteSize;
|
||||
private $nodeCount;
|
||||
private $recordSize;
|
||||
private $searchTreeSize;
|
||||
|
||||
public function __construct($metadata)
|
||||
{
|
||||
$this->binaryFormatMajorVersion =
|
||||
$metadata['binary_format_major_version'];
|
||||
$this->binaryFormatMinorVersion =
|
||||
$metadata['binary_format_minor_version'];
|
||||
$this->buildEpoch = $metadata['build_epoch'];
|
||||
$this->databaseType = $metadata['database_type'];
|
||||
$this->languages = $metadata['languages'];
|
||||
$this->description = $metadata['description'];
|
||||
$this->ipVersion = $metadata['ip_version'];
|
||||
$this->nodeCount = $metadata['node_count'];
|
||||
$this->recordSize = $metadata['record_size'];
|
||||
$this->nodeByteSize = $this->recordSize / 4;
|
||||
$this->searchTreeSize = $this->nodeCount * $this->nodeByteSize;
|
||||
}
|
||||
|
||||
public function __get($var)
|
||||
{
|
||||
return $this->$var;
|
||||
}
|
||||
}
|
26
vendor/maxmind-db/reader/src/MaxMind/Db/Reader/Util.php
vendored
Normal file
26
vendor/maxmind-db/reader/src/MaxMind/Db/Reader/Util.php
vendored
Normal file
@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
namespace MaxMind\Db\Reader;
|
||||
|
||||
class Util
|
||||
{
|
||||
public static function read($stream, $offset, $numberOfBytes)
|
||||
{
|
||||
if ($numberOfBytes === 0) {
|
||||
return '';
|
||||
}
|
||||
if (fseek($stream, $offset) === 0) {
|
||||
$value = fread($stream, $numberOfBytes);
|
||||
|
||||
// We check that the number of bytes read is equal to the number
|
||||
// asked for. We use ftell as getting the length of $value is
|
||||
// much slower.
|
||||
if (ftell($stream) - $offset === $numberOfBytes) {
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
throw new InvalidDatabaseException(
|
||||
'The MaxMind DB file contains bad data'
|
||||
);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user