acf
This commit is contained in:
42
plugins/system/tgeoip/vendor/maxmind-db/reader/autoload.php
vendored
Normal file
42
plugins/system/tgeoip/vendor/maxmind-db/reader/autoload.php
vendored
Normal file
@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace Tassos\Vendor;
|
||||
|
||||
/**
|
||||
* PSR-4 autoloader implementation for the MaxMind\DB namespace.
|
||||
* First we define the 'mmdb_autoload' function, and then we register
|
||||
* it with 'spl_autoload_register' so that PHP knows to use it.
|
||||
*
|
||||
* @param mixed $class
|
||||
*/
|
||||
/**
|
||||
* Automatically include the file that defines <code>class</code>.
|
||||
*
|
||||
* @param string $class
|
||||
* the name of the class to load
|
||||
*/
|
||||
function mmdb_autoload($class) : void
|
||||
{
|
||||
/*
|
||||
* A project-specific mapping between the namespaces and where
|
||||
* they're located. By convention, we include the trailing
|
||||
* slashes. The one-element array here simply makes things easy
|
||||
* to extend in the future if (for example) the test classes
|
||||
* begin to use one another.
|
||||
*/
|
||||
$namespace_map = ['MaxMind\\Db\\' => __DIR__ . '/src/MaxMind/Db/'];
|
||||
foreach ($namespace_map as $prefix => $dir) {
|
||||
// First swap out the namespace prefix with a directory...
|
||||
$path = \str_replace($prefix, $dir, $class);
|
||||
// replace the namespace separator with a directory separator...
|
||||
$path = \str_replace('\\', '/', $path);
|
||||
// and finally, add the PHP file extension to the result.
|
||||
$path = $path . '.php';
|
||||
// $path should now contain the path to a PHP file defining $class
|
||||
if (\file_exists($path)) {
|
||||
include $path;
|
||||
}
|
||||
}
|
||||
}
|
||||
\spl_autoload_register('mmdb_autoload');
|
||||
40
plugins/system/tgeoip/vendor/maxmind-db/reader/ext/config.m4
vendored
Normal file
40
plugins/system/tgeoip/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
|
||||
10
plugins/system/tgeoip/vendor/maxmind-db/reader/ext/config.w32
vendored
Normal file
10
plugins/system/tgeoip/vendor/maxmind-db/reader/ext/config.w32
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
ARG_WITH("maxminddb", "Enable MaxMind DB Reader extension support", "no");
|
||||
|
||||
if (PHP_MAXMINDDB == "yes") {
|
||||
if (CHECK_HEADER_ADD_INCLUDE("maxminddb.h", "CFLAGS_MAXMINDDB", PHP_MAXMINDDB + ";" + PHP_PHP_BUILD + "\\include\\maxminddb") &&
|
||||
CHECK_LIB("libmaxminddb.lib", "maxminddb", PHP_MAXMINDDB)) {
|
||||
EXTENSION("maxminddb", "maxminddb.c");
|
||||
} else {
|
||||
WARNING('Could not find maxminddb.h or libmaxminddb.lib; skipping');
|
||||
}
|
||||
}
|
||||
811
plugins/system/tgeoip/vendor/maxmind-db/reader/ext/maxminddb.c
vendored
Normal file
811
plugins/system/tgeoip/vendor/maxmind-db/reader/ext/maxminddb.c
vendored
Normal file
@ -0,0 +1,811 @@
|
||||
/* MaxMind, Inc., licenses this file to you under the Apache License, Version
|
||||
* 2.0 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#include "php_maxminddb.h"
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <php.h>
|
||||
#include <zend.h>
|
||||
|
||||
#include "Zend/zend_exceptions.h"
|
||||
#include "Zend/zend_types.h"
|
||||
#include "ext/spl/spl_exceptions.h"
|
||||
#include "ext/standard/info.h"
|
||||
#include <maxminddb.h>
|
||||
|
||||
#ifdef ZTS
|
||||
#include <TSRM.h>
|
||||
#endif
|
||||
|
||||
#define __STDC_FORMAT_MACROS
|
||||
#include <inttypes.h>
|
||||
|
||||
#define PHP_MAXMINDDB_NS ZEND_NS_NAME("MaxMind", "Db")
|
||||
#define PHP_MAXMINDDB_READER_NS ZEND_NS_NAME(PHP_MAXMINDDB_NS, "Reader")
|
||||
#define PHP_MAXMINDDB_METADATA_NS \
|
||||
ZEND_NS_NAME(PHP_MAXMINDDB_READER_NS, "Metadata")
|
||||
#define PHP_MAXMINDDB_READER_EX_NS \
|
||||
ZEND_NS_NAME(PHP_MAXMINDDB_READER_NS, "InvalidDatabaseException")
|
||||
|
||||
#define Z_MAXMINDDB_P(zv) php_maxminddb_fetch_object(Z_OBJ_P(zv))
|
||||
typedef size_t strsize_t;
|
||||
typedef zend_object free_obj_t;
|
||||
|
||||
/* For PHP 8 compatibility */
|
||||
#if PHP_VERSION_ID < 80000
|
||||
|
||||
#define PROP_OBJ(zv) (zv)
|
||||
|
||||
#else
|
||||
|
||||
#define PROP_OBJ(zv) Z_OBJ_P(zv)
|
||||
|
||||
#define TSRMLS_C
|
||||
#define TSRMLS_CC
|
||||
#define TSRMLS_DC
|
||||
|
||||
/* End PHP 8 compatibility */
|
||||
#endif
|
||||
|
||||
#ifndef ZEND_ACC_CTOR
|
||||
#define ZEND_ACC_CTOR 0
|
||||
#endif
|
||||
|
||||
/* IS_MIXED was added in 2020 */
|
||||
#ifndef IS_MIXED
|
||||
#define IS_MIXED IS_UNDEF
|
||||
#endif
|
||||
|
||||
/* ZEND_THIS was added in 7.4 */
|
||||
#ifndef ZEND_THIS
|
||||
#define ZEND_THIS (&EX(This))
|
||||
#endif
|
||||
|
||||
typedef struct _maxminddb_obj {
|
||||
MMDB_s *mmdb;
|
||||
zend_object std;
|
||||
} maxminddb_obj;
|
||||
|
||||
PHP_FUNCTION(maxminddb);
|
||||
|
||||
static int
|
||||
get_record(INTERNAL_FUNCTION_PARAMETERS, zval *record, int *prefix_len);
|
||||
static const MMDB_entry_data_list_s *
|
||||
handle_entry_data_list(const MMDB_entry_data_list_s *entry_data_list,
|
||||
zval *z_value TSRMLS_DC);
|
||||
static const MMDB_entry_data_list_s *
|
||||
handle_array(const MMDB_entry_data_list_s *entry_data_list,
|
||||
zval *z_value TSRMLS_DC);
|
||||
static const MMDB_entry_data_list_s *
|
||||
handle_map(const MMDB_entry_data_list_s *entry_data_list,
|
||||
zval *z_value TSRMLS_DC);
|
||||
static void handle_uint128(const MMDB_entry_data_list_s *entry_data_list,
|
||||
zval *z_value TSRMLS_DC);
|
||||
static void handle_uint64(const MMDB_entry_data_list_s *entry_data_list,
|
||||
zval *z_value TSRMLS_DC);
|
||||
static void handle_uint32(const MMDB_entry_data_list_s *entry_data_list,
|
||||
zval *z_value TSRMLS_DC);
|
||||
|
||||
#define CHECK_ALLOCATED(val) \
|
||||
if (!val) { \
|
||||
zend_error(E_ERROR, "Out of memory"); \
|
||||
return; \
|
||||
}
|
||||
|
||||
static zend_object_handlers maxminddb_obj_handlers;
|
||||
static zend_class_entry *maxminddb_ce, *maxminddb_exception_ce, *metadata_ce;
|
||||
|
||||
static inline maxminddb_obj *
|
||||
php_maxminddb_fetch_object(zend_object *obj TSRMLS_DC) {
|
||||
return (maxminddb_obj *)((char *)(obj)-XtOffsetOf(maxminddb_obj, std));
|
||||
}
|
||||
|
||||
ZEND_BEGIN_ARG_INFO_EX(arginfo_maxminddbreader_construct, 0, 0, 1)
|
||||
ZEND_ARG_TYPE_INFO(0, db_file, IS_STRING, 0)
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
PHP_METHOD(MaxMind_Db_Reader, __construct) {
|
||||
char *db_file = NULL;
|
||||
strsize_t name_len;
|
||||
zval *_this_zval = NULL;
|
||||
|
||||
if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
|
||||
getThis(),
|
||||
"Os",
|
||||
&_this_zval,
|
||||
maxminddb_ce,
|
||||
&db_file,
|
||||
&name_len) == FAILURE) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (0 != php_check_open_basedir(db_file TSRMLS_CC) ||
|
||||
0 != access(db_file, R_OK)) {
|
||||
zend_throw_exception_ex(
|
||||
spl_ce_InvalidArgumentException,
|
||||
0 TSRMLS_CC,
|
||||
"The file \"%s\" does not exist or is not readable.",
|
||||
db_file);
|
||||
return;
|
||||
}
|
||||
|
||||
MMDB_s *mmdb = (MMDB_s *)ecalloc(1, sizeof(MMDB_s));
|
||||
uint16_t status = MMDB_open(db_file, MMDB_MODE_MMAP, mmdb);
|
||||
|
||||
if (MMDB_SUCCESS != status) {
|
||||
zend_throw_exception_ex(
|
||||
maxminddb_exception_ce,
|
||||
0 TSRMLS_CC,
|
||||
"Error opening database file (%s). Is this a valid "
|
||||
"MaxMind DB file?",
|
||||
db_file);
|
||||
efree(mmdb);
|
||||
return;
|
||||
}
|
||||
|
||||
maxminddb_obj *mmdb_obj = Z_MAXMINDDB_P(ZEND_THIS);
|
||||
mmdb_obj->mmdb = mmdb;
|
||||
}
|
||||
|
||||
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(
|
||||
arginfo_maxminddbreader_get, 0, 1, IS_MIXED, 1)
|
||||
ZEND_ARG_TYPE_INFO(0, ip_address, IS_STRING, 0)
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
PHP_METHOD(MaxMind_Db_Reader, get) {
|
||||
int prefix_len = 0;
|
||||
get_record(INTERNAL_FUNCTION_PARAM_PASSTHRU, return_value, &prefix_len);
|
||||
}
|
||||
|
||||
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(
|
||||
arginfo_maxminddbreader_getWithPrefixLen, 0, 1, IS_ARRAY, 1)
|
||||
ZEND_ARG_TYPE_INFO(0, ip_address, IS_STRING, 0)
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
PHP_METHOD(MaxMind_Db_Reader, getWithPrefixLen) {
|
||||
zval record, z_prefix_len;
|
||||
|
||||
int prefix_len = 0;
|
||||
if (get_record(INTERNAL_FUNCTION_PARAM_PASSTHRU, &record, &prefix_len) ==
|
||||
FAILURE) {
|
||||
return;
|
||||
}
|
||||
|
||||
array_init(return_value);
|
||||
add_next_index_zval(return_value, &record);
|
||||
|
||||
ZVAL_LONG(&z_prefix_len, prefix_len);
|
||||
add_next_index_zval(return_value, &z_prefix_len);
|
||||
}
|
||||
|
||||
static int
|
||||
get_record(INTERNAL_FUNCTION_PARAMETERS, zval *record, int *prefix_len) {
|
||||
char *ip_address = NULL;
|
||||
strsize_t name_len;
|
||||
zval *this_zval = NULL;
|
||||
|
||||
if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
|
||||
getThis(),
|
||||
"Os",
|
||||
&this_zval,
|
||||
maxminddb_ce,
|
||||
&ip_address,
|
||||
&name_len) == FAILURE) {
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
const maxminddb_obj *mmdb_obj = (maxminddb_obj *)Z_MAXMINDDB_P(ZEND_THIS);
|
||||
|
||||
MMDB_s *mmdb = mmdb_obj->mmdb;
|
||||
|
||||
if (NULL == mmdb) {
|
||||
zend_throw_exception_ex(spl_ce_BadMethodCallException,
|
||||
0 TSRMLS_CC,
|
||||
"Attempt to read from a closed MaxMind DB.");
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
struct addrinfo hints = {
|
||||
.ai_family = AF_UNSPEC,
|
||||
.ai_flags = AI_NUMERICHOST,
|
||||
/* We set ai_socktype so that we only get one result back */
|
||||
.ai_socktype = SOCK_STREAM};
|
||||
|
||||
struct addrinfo *addresses = NULL;
|
||||
int gai_status = getaddrinfo(ip_address, NULL, &hints, &addresses);
|
||||
if (gai_status) {
|
||||
zend_throw_exception_ex(spl_ce_InvalidArgumentException,
|
||||
0 TSRMLS_CC,
|
||||
"The value \"%s\" is not a valid IP address.",
|
||||
ip_address);
|
||||
return FAILURE;
|
||||
}
|
||||
if (!addresses || !addresses->ai_addr) {
|
||||
zend_throw_exception_ex(
|
||||
spl_ce_InvalidArgumentException,
|
||||
0 TSRMLS_CC,
|
||||
"getaddrinfo was successful but failed to set the addrinfo");
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
int sa_family = addresses->ai_addr->sa_family;
|
||||
|
||||
int mmdb_error = MMDB_SUCCESS;
|
||||
MMDB_lookup_result_s result =
|
||||
MMDB_lookup_sockaddr(mmdb, addresses->ai_addr, &mmdb_error);
|
||||
|
||||
freeaddrinfo(addresses);
|
||||
|
||||
if (MMDB_SUCCESS != mmdb_error) {
|
||||
zend_class_entry *ex;
|
||||
if (MMDB_IPV6_LOOKUP_IN_IPV4_DATABASE_ERROR == mmdb_error) {
|
||||
ex = spl_ce_InvalidArgumentException;
|
||||
} else {
|
||||
ex = maxminddb_exception_ce;
|
||||
}
|
||||
zend_throw_exception_ex(ex,
|
||||
0 TSRMLS_CC,
|
||||
"Error looking up %s. %s",
|
||||
ip_address,
|
||||
MMDB_strerror(mmdb_error));
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
*prefix_len = result.netmask;
|
||||
|
||||
if (sa_family == AF_INET && mmdb->metadata.ip_version == 6) {
|
||||
/* We return the prefix length given the IPv4 address. If there is
|
||||
no IPv4 subtree, we return a prefix length of 0. */
|
||||
*prefix_len = *prefix_len >= 96 ? *prefix_len - 96 : 0;
|
||||
}
|
||||
|
||||
if (!result.found_entry) {
|
||||
ZVAL_NULL(record);
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
MMDB_entry_data_list_s *entry_data_list = NULL;
|
||||
int status = MMDB_get_entry_data_list(&result.entry, &entry_data_list);
|
||||
|
||||
if (MMDB_SUCCESS != status) {
|
||||
zend_throw_exception_ex(maxminddb_exception_ce,
|
||||
0 TSRMLS_CC,
|
||||
"Error while looking up data for %s. %s",
|
||||
ip_address,
|
||||
MMDB_strerror(status));
|
||||
MMDB_free_entry_data_list(entry_data_list);
|
||||
return FAILURE;
|
||||
} else if (NULL == entry_data_list) {
|
||||
zend_throw_exception_ex(
|
||||
maxminddb_exception_ce,
|
||||
0 TSRMLS_CC,
|
||||
"Error while looking up data for %s. Your database may "
|
||||
"be corrupt or you have found a bug in libmaxminddb.",
|
||||
ip_address);
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
const MMDB_entry_data_list_s *rv =
|
||||
handle_entry_data_list(entry_data_list, record TSRMLS_CC);
|
||||
if (rv == NULL) {
|
||||
/* We should have already thrown the exception in handle_entry_data_list
|
||||
*/
|
||||
return FAILURE;
|
||||
}
|
||||
MMDB_free_entry_data_list(entry_data_list);
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
ZEND_BEGIN_ARG_INFO_EX(arginfo_maxminddbreader_void, 0, 0, 0)
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
PHP_METHOD(MaxMind_Db_Reader, metadata) {
|
||||
zval *this_zval = NULL;
|
||||
|
||||
if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
|
||||
getThis(),
|
||||
"O",
|
||||
&this_zval,
|
||||
maxminddb_ce) == FAILURE) {
|
||||
return;
|
||||
}
|
||||
|
||||
const maxminddb_obj *const mmdb_obj =
|
||||
(maxminddb_obj *)Z_MAXMINDDB_P(this_zval);
|
||||
|
||||
if (NULL == mmdb_obj->mmdb) {
|
||||
zend_throw_exception_ex(spl_ce_BadMethodCallException,
|
||||
0 TSRMLS_CC,
|
||||
"Attempt to read from a closed MaxMind DB.");
|
||||
return;
|
||||
}
|
||||
|
||||
object_init_ex(return_value, metadata_ce);
|
||||
|
||||
MMDB_entry_data_list_s *entry_data_list;
|
||||
MMDB_get_metadata_as_entry_data_list(mmdb_obj->mmdb, &entry_data_list);
|
||||
|
||||
zval metadata_array;
|
||||
const MMDB_entry_data_list_s *rv =
|
||||
handle_entry_data_list(entry_data_list, &metadata_array TSRMLS_CC);
|
||||
if (rv == NULL) {
|
||||
return;
|
||||
}
|
||||
MMDB_free_entry_data_list(entry_data_list);
|
||||
zend_call_method_with_1_params(PROP_OBJ(return_value),
|
||||
metadata_ce,
|
||||
&metadata_ce->constructor,
|
||||
ZEND_CONSTRUCTOR_FUNC_NAME,
|
||||
NULL,
|
||||
&metadata_array);
|
||||
zval_ptr_dtor(&metadata_array);
|
||||
}
|
||||
|
||||
PHP_METHOD(MaxMind_Db_Reader, close) {
|
||||
zval *this_zval = NULL;
|
||||
|
||||
if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
|
||||
getThis(),
|
||||
"O",
|
||||
&this_zval,
|
||||
maxminddb_ce) == FAILURE) {
|
||||
return;
|
||||
}
|
||||
|
||||
maxminddb_obj *mmdb_obj = (maxminddb_obj *)Z_MAXMINDDB_P(this_zval);
|
||||
|
||||
if (NULL == mmdb_obj->mmdb) {
|
||||
zend_throw_exception_ex(spl_ce_BadMethodCallException,
|
||||
0 TSRMLS_CC,
|
||||
"Attempt to close a closed MaxMind DB.");
|
||||
return;
|
||||
}
|
||||
MMDB_close(mmdb_obj->mmdb);
|
||||
efree(mmdb_obj->mmdb);
|
||||
mmdb_obj->mmdb = NULL;
|
||||
}
|
||||
|
||||
static const MMDB_entry_data_list_s *
|
||||
handle_entry_data_list(const MMDB_entry_data_list_s *entry_data_list,
|
||||
zval *z_value TSRMLS_DC) {
|
||||
switch (entry_data_list->entry_data.type) {
|
||||
case MMDB_DATA_TYPE_MAP:
|
||||
return handle_map(entry_data_list, z_value TSRMLS_CC);
|
||||
case MMDB_DATA_TYPE_ARRAY:
|
||||
return handle_array(entry_data_list, z_value TSRMLS_CC);
|
||||
case MMDB_DATA_TYPE_UTF8_STRING:
|
||||
ZVAL_STRINGL(z_value,
|
||||
(char *)entry_data_list->entry_data.utf8_string,
|
||||
entry_data_list->entry_data.data_size);
|
||||
break;
|
||||
case MMDB_DATA_TYPE_BYTES:
|
||||
ZVAL_STRINGL(z_value,
|
||||
(char *)entry_data_list->entry_data.bytes,
|
||||
entry_data_list->entry_data.data_size);
|
||||
break;
|
||||
case MMDB_DATA_TYPE_DOUBLE:
|
||||
ZVAL_DOUBLE(z_value, entry_data_list->entry_data.double_value);
|
||||
break;
|
||||
case MMDB_DATA_TYPE_FLOAT:
|
||||
ZVAL_DOUBLE(z_value, entry_data_list->entry_data.float_value);
|
||||
break;
|
||||
case MMDB_DATA_TYPE_UINT16:
|
||||
ZVAL_LONG(z_value, entry_data_list->entry_data.uint16);
|
||||
break;
|
||||
case MMDB_DATA_TYPE_UINT32:
|
||||
handle_uint32(entry_data_list, z_value TSRMLS_CC);
|
||||
break;
|
||||
case MMDB_DATA_TYPE_BOOLEAN:
|
||||
ZVAL_BOOL(z_value, entry_data_list->entry_data.boolean);
|
||||
break;
|
||||
case MMDB_DATA_TYPE_UINT64:
|
||||
handle_uint64(entry_data_list, z_value TSRMLS_CC);
|
||||
break;
|
||||
case MMDB_DATA_TYPE_UINT128:
|
||||
handle_uint128(entry_data_list, z_value TSRMLS_CC);
|
||||
break;
|
||||
case MMDB_DATA_TYPE_INT32:
|
||||
ZVAL_LONG(z_value, entry_data_list->entry_data.int32);
|
||||
break;
|
||||
default:
|
||||
zend_throw_exception_ex(maxminddb_exception_ce,
|
||||
0 TSRMLS_CC,
|
||||
"Invalid data type arguments: %d",
|
||||
entry_data_list->entry_data.type);
|
||||
return NULL;
|
||||
}
|
||||
return entry_data_list;
|
||||
}
|
||||
|
||||
static const MMDB_entry_data_list_s *
|
||||
handle_map(const MMDB_entry_data_list_s *entry_data_list,
|
||||
zval *z_value TSRMLS_DC) {
|
||||
array_init(z_value);
|
||||
const uint32_t map_size = entry_data_list->entry_data.data_size;
|
||||
|
||||
uint32_t i;
|
||||
for (i = 0; i < map_size && entry_data_list; i++) {
|
||||
entry_data_list = entry_data_list->next;
|
||||
|
||||
char *key = estrndup((char *)entry_data_list->entry_data.utf8_string,
|
||||
entry_data_list->entry_data.data_size);
|
||||
if (NULL == key) {
|
||||
zend_throw_exception_ex(maxminddb_exception_ce,
|
||||
0 TSRMLS_CC,
|
||||
"Invalid data type arguments");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
entry_data_list = entry_data_list->next;
|
||||
zval new_value;
|
||||
entry_data_list =
|
||||
handle_entry_data_list(entry_data_list, &new_value TSRMLS_CC);
|
||||
if (entry_data_list != NULL) {
|
||||
add_assoc_zval(z_value, key, &new_value);
|
||||
}
|
||||
efree(key);
|
||||
}
|
||||
return entry_data_list;
|
||||
}
|
||||
|
||||
static const MMDB_entry_data_list_s *
|
||||
handle_array(const MMDB_entry_data_list_s *entry_data_list,
|
||||
zval *z_value TSRMLS_DC) {
|
||||
const uint32_t size = entry_data_list->entry_data.data_size;
|
||||
|
||||
array_init(z_value);
|
||||
|
||||
uint32_t i;
|
||||
for (i = 0; i < size && entry_data_list; i++) {
|
||||
entry_data_list = entry_data_list->next;
|
||||
zval new_value;
|
||||
entry_data_list =
|
||||
handle_entry_data_list(entry_data_list, &new_value TSRMLS_CC);
|
||||
if (entry_data_list != NULL) {
|
||||
add_next_index_zval(z_value, &new_value);
|
||||
}
|
||||
}
|
||||
return entry_data_list;
|
||||
}
|
||||
|
||||
static void handle_uint128(const MMDB_entry_data_list_s *entry_data_list,
|
||||
zval *z_value TSRMLS_DC) {
|
||||
uint64_t high = 0;
|
||||
uint64_t low = 0;
|
||||
#if MMDB_UINT128_IS_BYTE_ARRAY
|
||||
int i;
|
||||
for (i = 0; i < 8; i++) {
|
||||
high = (high << 8) | entry_data_list->entry_data.uint128[i];
|
||||
}
|
||||
|
||||
for (i = 8; i < 16; i++) {
|
||||
low = (low << 8) | entry_data_list->entry_data.uint128[i];
|
||||
}
|
||||
#else
|
||||
high = entry_data_list->entry_data.uint128 >> 64;
|
||||
low = (uint64_t)entry_data_list->entry_data.uint128;
|
||||
#endif
|
||||
|
||||
char *num_str;
|
||||
spprintf(&num_str, 0, "0x%016" PRIX64 "%016" PRIX64, high, low);
|
||||
CHECK_ALLOCATED(num_str);
|
||||
|
||||
ZVAL_STRING(z_value, num_str);
|
||||
efree(num_str);
|
||||
}
|
||||
|
||||
static void handle_uint32(const MMDB_entry_data_list_s *entry_data_list,
|
||||
zval *z_value TSRMLS_DC) {
|
||||
uint32_t val = entry_data_list->entry_data.uint32;
|
||||
|
||||
#if LONG_MAX >= UINT32_MAX
|
||||
ZVAL_LONG(z_value, val);
|
||||
return;
|
||||
#else
|
||||
if (val <= LONG_MAX) {
|
||||
ZVAL_LONG(z_value, val);
|
||||
return;
|
||||
}
|
||||
|
||||
char *int_str;
|
||||
spprintf(&int_str, 0, "%" PRIu32, val);
|
||||
CHECK_ALLOCATED(int_str);
|
||||
|
||||
ZVAL_STRING(z_value, int_str);
|
||||
efree(int_str);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void handle_uint64(const MMDB_entry_data_list_s *entry_data_list,
|
||||
zval *z_value TSRMLS_DC) {
|
||||
uint64_t val = entry_data_list->entry_data.uint64;
|
||||
|
||||
#if LONG_MAX >= UINT64_MAX
|
||||
ZVAL_LONG(z_value, val);
|
||||
return;
|
||||
#else
|
||||
if (val <= LONG_MAX) {
|
||||
ZVAL_LONG(z_value, val);
|
||||
return;
|
||||
}
|
||||
|
||||
char *int_str;
|
||||
spprintf(&int_str, 0, "%" PRIu64, val);
|
||||
CHECK_ALLOCATED(int_str);
|
||||
|
||||
ZVAL_STRING(z_value, int_str);
|
||||
efree(int_str);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void maxminddb_free_storage(free_obj_t *object TSRMLS_DC) {
|
||||
maxminddb_obj *obj =
|
||||
php_maxminddb_fetch_object((zend_object *)object TSRMLS_CC);
|
||||
if (obj->mmdb != NULL) {
|
||||
MMDB_close(obj->mmdb);
|
||||
efree(obj->mmdb);
|
||||
}
|
||||
|
||||
zend_object_std_dtor(&obj->std TSRMLS_CC);
|
||||
}
|
||||
|
||||
static zend_object *maxminddb_create_handler(zend_class_entry *type TSRMLS_DC) {
|
||||
maxminddb_obj *obj = (maxminddb_obj *)ecalloc(1, sizeof(maxminddb_obj));
|
||||
zend_object_std_init(&obj->std, type TSRMLS_CC);
|
||||
object_properties_init(&(obj->std), type);
|
||||
|
||||
obj->std.handlers = &maxminddb_obj_handlers;
|
||||
|
||||
return &obj->std;
|
||||
}
|
||||
|
||||
/* clang-format off */
|
||||
static zend_function_entry maxminddb_methods[] = {
|
||||
PHP_ME(MaxMind_Db_Reader, __construct, arginfo_maxminddbreader_construct,
|
||||
ZEND_ACC_PUBLIC | ZEND_ACC_CTOR)
|
||||
PHP_ME(MaxMind_Db_Reader, close, arginfo_maxminddbreader_void, ZEND_ACC_PUBLIC)
|
||||
PHP_ME(MaxMind_Db_Reader, get, arginfo_maxminddbreader_get, ZEND_ACC_PUBLIC)
|
||||
PHP_ME(MaxMind_Db_Reader, getWithPrefixLen, arginfo_maxminddbreader_getWithPrefixLen, ZEND_ACC_PUBLIC)
|
||||
PHP_ME(MaxMind_Db_Reader, metadata, arginfo_maxminddbreader_void, ZEND_ACC_PUBLIC)
|
||||
{ NULL, NULL, NULL }
|
||||
};
|
||||
/* clang-format on */
|
||||
|
||||
ZEND_BEGIN_ARG_INFO_EX(arginfo_metadata_construct, 0, 0, 1)
|
||||
ZEND_ARG_TYPE_INFO(0, metadata, IS_ARRAY, 0)
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
PHP_METHOD(MaxMind_Db_Reader_Metadata, __construct) {
|
||||
zval *object = NULL;
|
||||
zval *metadata_array = NULL;
|
||||
zend_long node_count = 0;
|
||||
zend_long record_size = 0;
|
||||
|
||||
if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
|
||||
getThis(),
|
||||
"Oa",
|
||||
&object,
|
||||
metadata_ce,
|
||||
&metadata_array) == FAILURE) {
|
||||
return;
|
||||
}
|
||||
|
||||
zval *tmp = NULL;
|
||||
if ((tmp = zend_hash_str_find(HASH_OF(metadata_array),
|
||||
"binary_format_major_version",
|
||||
sizeof("binary_format_major_version") - 1))) {
|
||||
zend_update_property(metadata_ce,
|
||||
PROP_OBJ(object),
|
||||
"binaryFormatMajorVersion",
|
||||
sizeof("binaryFormatMajorVersion") - 1,
|
||||
tmp);
|
||||
}
|
||||
|
||||
if ((tmp = zend_hash_str_find(HASH_OF(metadata_array),
|
||||
"binary_format_minor_version",
|
||||
sizeof("binary_format_minor_version") - 1))) {
|
||||
zend_update_property(metadata_ce,
|
||||
PROP_OBJ(object),
|
||||
"binaryFormatMinorVersion",
|
||||
sizeof("binaryFormatMinorVersion") - 1,
|
||||
tmp);
|
||||
}
|
||||
|
||||
if ((tmp = zend_hash_str_find(HASH_OF(metadata_array),
|
||||
"build_epoch",
|
||||
sizeof("build_epoch") - 1))) {
|
||||
zend_update_property(metadata_ce,
|
||||
PROP_OBJ(object),
|
||||
"buildEpoch",
|
||||
sizeof("buildEpoch") - 1,
|
||||
tmp);
|
||||
}
|
||||
|
||||
if ((tmp = zend_hash_str_find(HASH_OF(metadata_array),
|
||||
"database_type",
|
||||
sizeof("database_type") - 1))) {
|
||||
zend_update_property(metadata_ce,
|
||||
PROP_OBJ(object),
|
||||
"databaseType",
|
||||
sizeof("databaseType") - 1,
|
||||
tmp);
|
||||
}
|
||||
|
||||
if ((tmp = zend_hash_str_find(HASH_OF(metadata_array),
|
||||
"description",
|
||||
sizeof("description") - 1))) {
|
||||
zend_update_property(metadata_ce,
|
||||
PROP_OBJ(object),
|
||||
"description",
|
||||
sizeof("description") - 1,
|
||||
tmp);
|
||||
}
|
||||
|
||||
if ((tmp = zend_hash_str_find(HASH_OF(metadata_array),
|
||||
"ip_version",
|
||||
sizeof("ip_version") - 1))) {
|
||||
zend_update_property(metadata_ce,
|
||||
PROP_OBJ(object),
|
||||
"ipVersion",
|
||||
sizeof("ipVersion") - 1,
|
||||
tmp);
|
||||
}
|
||||
|
||||
if ((tmp = zend_hash_str_find(
|
||||
HASH_OF(metadata_array), "languages", sizeof("languages") - 1))) {
|
||||
zend_update_property(metadata_ce,
|
||||
PROP_OBJ(object),
|
||||
"languages",
|
||||
sizeof("languages") - 1,
|
||||
tmp);
|
||||
}
|
||||
|
||||
if ((tmp = zend_hash_str_find(HASH_OF(metadata_array),
|
||||
"record_size",
|
||||
sizeof("record_size") - 1))) {
|
||||
zend_update_property(metadata_ce,
|
||||
PROP_OBJ(object),
|
||||
"recordSize",
|
||||
sizeof("recordSize") - 1,
|
||||
tmp);
|
||||
if (Z_TYPE_P(tmp) == IS_LONG) {
|
||||
record_size = Z_LVAL_P(tmp);
|
||||
}
|
||||
}
|
||||
|
||||
if (record_size != 0) {
|
||||
zend_update_property_long(metadata_ce,
|
||||
PROP_OBJ(object),
|
||||
"nodeByteSize",
|
||||
sizeof("nodeByteSize") - 1,
|
||||
record_size / 4);
|
||||
}
|
||||
|
||||
if ((tmp = zend_hash_str_find(HASH_OF(metadata_array),
|
||||
"node_count",
|
||||
sizeof("node_count") - 1))) {
|
||||
zend_update_property(metadata_ce,
|
||||
PROP_OBJ(object),
|
||||
"nodeCount",
|
||||
sizeof("nodeCount") - 1,
|
||||
tmp);
|
||||
if (Z_TYPE_P(tmp) == IS_LONG) {
|
||||
node_count = Z_LVAL_P(tmp);
|
||||
}
|
||||
}
|
||||
|
||||
if (record_size != 0) {
|
||||
zend_update_property_long(metadata_ce,
|
||||
PROP_OBJ(object),
|
||||
"searchTreeSize",
|
||||
sizeof("searchTreeSize") - 1,
|
||||
record_size * node_count / 4);
|
||||
}
|
||||
}
|
||||
|
||||
// clang-format off
|
||||
static zend_function_entry metadata_methods[] = {
|
||||
PHP_ME(MaxMind_Db_Reader_Metadata, __construct, arginfo_metadata_construct, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR)
|
||||
{NULL, NULL, NULL}
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
PHP_MINIT_FUNCTION(maxminddb) {
|
||||
zend_class_entry ce;
|
||||
|
||||
INIT_CLASS_ENTRY(ce, PHP_MAXMINDDB_READER_EX_NS, NULL);
|
||||
maxminddb_exception_ce =
|
||||
zend_register_internal_class_ex(&ce, zend_ce_exception);
|
||||
|
||||
INIT_CLASS_ENTRY(ce, PHP_MAXMINDDB_READER_NS, maxminddb_methods);
|
||||
maxminddb_ce = zend_register_internal_class(&ce TSRMLS_CC);
|
||||
maxminddb_ce->create_object = maxminddb_create_handler;
|
||||
|
||||
INIT_CLASS_ENTRY(ce, PHP_MAXMINDDB_METADATA_NS, metadata_methods);
|
||||
metadata_ce = zend_register_internal_class(&ce TSRMLS_CC);
|
||||
zend_declare_property_null(metadata_ce,
|
||||
"binaryFormatMajorVersion",
|
||||
sizeof("binaryFormatMajorVersion") - 1,
|
||||
ZEND_ACC_PUBLIC);
|
||||
zend_declare_property_null(metadata_ce,
|
||||
"binaryFormatMinorVersion",
|
||||
sizeof("binaryFormatMinorVersion") - 1,
|
||||
ZEND_ACC_PUBLIC);
|
||||
zend_declare_property_null(
|
||||
metadata_ce, "buildEpoch", sizeof("buildEpoch") - 1, ZEND_ACC_PUBLIC);
|
||||
zend_declare_property_null(metadata_ce,
|
||||
"databaseType",
|
||||
sizeof("databaseType") - 1,
|
||||
ZEND_ACC_PUBLIC);
|
||||
zend_declare_property_null(
|
||||
metadata_ce, "description", sizeof("description") - 1, ZEND_ACC_PUBLIC);
|
||||
zend_declare_property_null(
|
||||
metadata_ce, "ipVersion", sizeof("ipVersion") - 1, ZEND_ACC_PUBLIC);
|
||||
zend_declare_property_null(
|
||||
metadata_ce, "languages", sizeof("languages") - 1, ZEND_ACC_PUBLIC);
|
||||
zend_declare_property_null(metadata_ce,
|
||||
"nodeByteSize",
|
||||
sizeof("nodeByteSize") - 1,
|
||||
ZEND_ACC_PUBLIC);
|
||||
zend_declare_property_null(
|
||||
metadata_ce, "nodeCount", sizeof("nodeCount") - 1, ZEND_ACC_PUBLIC);
|
||||
zend_declare_property_null(
|
||||
metadata_ce, "recordSize", sizeof("recordSize") - 1, ZEND_ACC_PUBLIC);
|
||||
zend_declare_property_null(metadata_ce,
|
||||
"searchTreeSize",
|
||||
sizeof("searchTreeSize") - 1,
|
||||
ZEND_ACC_PUBLIC);
|
||||
|
||||
memcpy(&maxminddb_obj_handlers,
|
||||
zend_get_std_object_handlers(),
|
||||
sizeof(zend_object_handlers));
|
||||
maxminddb_obj_handlers.clone_obj = NULL;
|
||||
maxminddb_obj_handlers.offset = XtOffsetOf(maxminddb_obj, std);
|
||||
maxminddb_obj_handlers.free_obj = maxminddb_free_storage;
|
||||
zend_declare_class_constant_string(maxminddb_ce,
|
||||
"MMDB_LIB_VERSION",
|
||||
sizeof("MMDB_LIB_VERSION") - 1,
|
||||
MMDB_lib_version() TSRMLS_CC);
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
static PHP_MINFO_FUNCTION(maxminddb) {
|
||||
php_info_print_table_start();
|
||||
|
||||
php_info_print_table_row(2, "MaxMind DB Reader", "enabled");
|
||||
php_info_print_table_row(
|
||||
2, "maxminddb extension version", PHP_MAXMINDDB_VERSION);
|
||||
php_info_print_table_row(
|
||||
2, "libmaxminddb library version", MMDB_lib_version());
|
||||
|
||||
php_info_print_table_end();
|
||||
}
|
||||
|
||||
zend_module_entry maxminddb_module_entry = {STANDARD_MODULE_HEADER,
|
||||
PHP_MAXMINDDB_EXTNAME,
|
||||
NULL,
|
||||
PHP_MINIT(maxminddb),
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
PHP_MINFO(maxminddb),
|
||||
PHP_MAXMINDDB_VERSION,
|
||||
STANDARD_MODULE_PROPERTIES};
|
||||
|
||||
#ifdef COMPILE_DL_MAXMINDDB
|
||||
ZEND_GET_MODULE(maxminddb)
|
||||
#endif
|
||||
24
plugins/system/tgeoip/vendor/maxmind-db/reader/ext/php_maxminddb.h
vendored
Normal file
24
plugins/system/tgeoip/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.10.1"
|
||||
#define PHP_MAXMINDDB_EXTNAME "maxminddb"
|
||||
|
||||
extern zend_module_entry maxminddb_module_entry;
|
||||
#define phpext_maxminddb_ptr &maxminddb_module_entry
|
||||
|
||||
#endif
|
||||
63
plugins/system/tgeoip/vendor/maxmind-db/reader/package.xml
vendored
Normal file
63
plugins/system/tgeoip/vendor/maxmind-db/reader/package.xml
vendored
Normal file
@ -0,0 +1,63 @@
|
||||
<?xml version="1.0"?>
|
||||
<package version="2.0" xmlns="http://pear.php.net/dtd/package-2.0"
|
||||
xmlns:tasks="http://pear.php.net/dtd/tasks-1.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://pear.php.net/dtd/tasks-1.0 http://pear.php.net/dtd/tasks-1.0.xsd http://pear.php.net/dtd/package-2.0 http://pear.php.net/dtd/package-2.0.xsd">
|
||||
|
||||
<name>maxminddb</name>
|
||||
<channel>pecl.php.net</channel>
|
||||
<summary>Reader for the MaxMind DB file format</summary>
|
||||
<description>This is the PHP extension for reading MaxMind DB files. MaxMind DB is a binary file format that stores data indexed by IP address subnets (IPv4 or IPv6).</description>
|
||||
<lead>
|
||||
<name>Greg Oschwald</name>
|
||||
<user>oschwald</user>
|
||||
<email>goschwald@maxmind.com</email>
|
||||
<active>yes</active>
|
||||
</lead>
|
||||
<date>2021-04-14</date>
|
||||
<version>
|
||||
<release>1.10.1</release>
|
||||
<api>1.10.1</api>
|
||||
</version>
|
||||
<stability>
|
||||
<release>stable</release>
|
||||
<api>stable</api>
|
||||
</stability>
|
||||
<license uri="https://github.com/maxmind/MaxMind-DB-Reader-php/blob/main/LICENSE">Apache License 2.0</license>
|
||||
<notes>* Fix a `TypeError` exception in the pure PHP reader when using large
|
||||
databases on 32-bit PHP builds with the `bcmath` extension. Reported
|
||||
by dodo1708. GitHub #124.</notes>
|
||||
<contents>
|
||||
<dir name="/">
|
||||
<file role="doc" name="LICENSE"/>
|
||||
<file role="doc" name="CHANGELOG.md"/>
|
||||
<file role="doc" name="README.md"/>
|
||||
|
||||
<dir name="ext">
|
||||
<file role="src" name="config.m4"/>
|
||||
<file role="src" name="config.w32"/>
|
||||
|
||||
<file role="src" name="maxminddb.c"/>
|
||||
<file role="src" name="php_maxminddb.h"/>
|
||||
|
||||
<dir name="tests">
|
||||
<file role="test" name="001-load.phpt"/>
|
||||
<file role="test" name="002-final.phpt"/>
|
||||
<file role="test" name="003-open-basedir.phpt"/>
|
||||
</dir>
|
||||
</dir>
|
||||
</dir>
|
||||
</contents>
|
||||
<dependencies>
|
||||
<required>
|
||||
<php>
|
||||
<min>7.2.0</min>
|
||||
</php>
|
||||
<pearinstaller>
|
||||
<min>1.10.0</min>
|
||||
</pearinstaller>
|
||||
</required>
|
||||
</dependencies>
|
||||
<providesextension>maxminddb</providesextension>
|
||||
<extsrcrelease />
|
||||
</package>
|
||||
287
plugins/system/tgeoip/vendor/maxmind-db/reader/src/MaxMind/Db/Reader.php
vendored
Normal file
287
plugins/system/tgeoip/vendor/maxmind-db/reader/src/MaxMind/Db/Reader.php
vendored
Normal file
@ -0,0 +1,287 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace Tassos\Vendor\MaxMind\Db;
|
||||
|
||||
use ArgumentCountError;
|
||||
use BadMethodCallException;
|
||||
use Exception;
|
||||
use InvalidArgumentException;
|
||||
use Tassos\Vendor\MaxMind\Db\Reader\Decoder;
|
||||
use Tassos\Vendor\MaxMind\Db\Reader\InvalidDatabaseException;
|
||||
use Tassos\Vendor\MaxMind\Db\Reader\Metadata;
|
||||
use Tassos\Vendor\MaxMind\Db\Reader\Util;
|
||||
use UnexpectedValueException;
|
||||
/**
|
||||
* Instances of this class provide a reader for the MaxMind DB format. IP
|
||||
* addresses can be looked up using the get method.
|
||||
*/
|
||||
class Reader
|
||||
{
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private static $DATA_SECTION_SEPARATOR_SIZE = 16;
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private static $METADATA_START_MARKER = "\xab\xcd\xefMaxMind.com";
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private static $METADATA_START_MARKER_LENGTH = 14;
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private static $METADATA_MAX_SIZE = 131072;
|
||||
// 128 * 1024 = 128KiB
|
||||
/**
|
||||
* @var Decoder
|
||||
*/
|
||||
private $decoder;
|
||||
/**
|
||||
* @var resource
|
||||
*/
|
||||
private $fileHandle;
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private $fileSize;
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private $ipV4Start;
|
||||
/**
|
||||
* @var Metadata
|
||||
*/
|
||||
private $metadata;
|
||||
/**
|
||||
* Constructs a Reader for the MaxMind DB format. The file passed to it must
|
||||
* be a valid MaxMind DB file such as a GeoIp2 database file.
|
||||
*
|
||||
* @param string $database
|
||||
* the MaxMind DB file to use
|
||||
*
|
||||
* @throws InvalidArgumentException for invalid database path or unknown arguments
|
||||
* @throws InvalidDatabaseException
|
||||
* if the database is invalid or there is an error reading
|
||||
* from it
|
||||
*/
|
||||
public function __construct(string $database)
|
||||
{
|
||||
if (\func_num_args() !== 1) {
|
||||
throw new ArgumentCountError(\sprintf('%s() expects exactly 1 parameter, %d given', __METHOD__, \func_num_args()));
|
||||
}
|
||||
$fileHandle = @\fopen($database, 'rb');
|
||||
if ($fileHandle === \false) {
|
||||
throw new InvalidArgumentException("The file \"{$database}\" does not exist or is not readable.");
|
||||
}
|
||||
$this->fileHandle = $fileHandle;
|
||||
$fileSize = @\filesize($database);
|
||||
if ($fileSize === \false) {
|
||||
throw new UnexpectedValueException("Error determining the size of \"{$database}\".");
|
||||
}
|
||||
$this->fileSize = $fileSize;
|
||||
$start = $this->findMetadataStart($database);
|
||||
$metadataDecoder = new Decoder($this->fileHandle, $start);
|
||||
[$metadataArray] = $metadataDecoder->decode($start);
|
||||
$this->metadata = new Metadata($metadataArray);
|
||||
$this->decoder = new Decoder($this->fileHandle, $this->metadata->searchTreeSize + self::$DATA_SECTION_SEPARATOR_SIZE);
|
||||
$this->ipV4Start = $this->ipV4StartNode();
|
||||
}
|
||||
/**
|
||||
* Retrieves the record for the IP address.
|
||||
*
|
||||
* @param string $ipAddress
|
||||
* the IP address to look up
|
||||
*
|
||||
* @throws BadMethodCallException if this method is called on a closed database
|
||||
* @throws InvalidArgumentException if something other than a single IP address is passed to the method
|
||||
* @throws InvalidDatabaseException
|
||||
* if the database is invalid or there is an error reading
|
||||
* from it
|
||||
*
|
||||
* @return mixed the record for the IP address
|
||||
*/
|
||||
public function get(string $ipAddress)
|
||||
{
|
||||
if (\func_num_args() !== 1) {
|
||||
throw new ArgumentCountError(\sprintf('%s() expects exactly 1 parameter, %d given', __METHOD__, \func_num_args()));
|
||||
}
|
||||
[$record] = $this->getWithPrefixLen($ipAddress);
|
||||
return $record;
|
||||
}
|
||||
/**
|
||||
* Retrieves the record for the IP address and its associated network prefix length.
|
||||
*
|
||||
* @param string $ipAddress
|
||||
* the IP address to look up
|
||||
*
|
||||
* @throws BadMethodCallException if this method is called on a closed database
|
||||
* @throws InvalidArgumentException if something other than a single IP address is passed to the method
|
||||
* @throws InvalidDatabaseException
|
||||
* if the database is invalid or there is an error reading
|
||||
* from it
|
||||
*
|
||||
* @return array an array where the first element is the record and the
|
||||
* second the network prefix length for the record
|
||||
*/
|
||||
public function getWithPrefixLen(string $ipAddress) : array
|
||||
{
|
||||
if (\func_num_args() !== 1) {
|
||||
throw new ArgumentCountError(\sprintf('%s() expects exactly 1 parameter, %d given', __METHOD__, \func_num_args()));
|
||||
}
|
||||
if (!\is_resource($this->fileHandle)) {
|
||||
throw new BadMethodCallException('Attempt to read from a closed MaxMind DB.');
|
||||
}
|
||||
[$pointer, $prefixLen] = $this->findAddressInTree($ipAddress);
|
||||
if ($pointer === 0) {
|
||||
return [null, $prefixLen];
|
||||
}
|
||||
return [$this->resolveDataPointer($pointer), $prefixLen];
|
||||
}
|
||||
private function findAddressInTree(string $ipAddress) : array
|
||||
{
|
||||
$packedAddr = @\inet_pton($ipAddress);
|
||||
if ($packedAddr === \false) {
|
||||
throw new InvalidArgumentException("The value \"{$ipAddress}\" is not a valid IP address.");
|
||||
}
|
||||
$rawAddress = \unpack('C*', $packedAddr);
|
||||
$bitCount = \count($rawAddress) * 8;
|
||||
// The first node of the tree is always node 0, at the beginning of the
|
||||
// value
|
||||
$node = 0;
|
||||
$metadata = $this->metadata;
|
||||
// Check if we are looking up an IPv4 address in an IPv6 tree. If this
|
||||
// is the case, we can skip over the first 96 nodes.
|
||||
if ($metadata->ipVersion === 6) {
|
||||
if ($bitCount === 32) {
|
||||
$node = $this->ipV4Start;
|
||||
}
|
||||
} elseif ($metadata->ipVersion === 4 && $bitCount === 128) {
|
||||
throw new InvalidArgumentException("Error looking up {$ipAddress}. You attempted to look up an" . ' IPv6 address in an IPv4-only database.');
|
||||
}
|
||||
$nodeCount = $metadata->nodeCount;
|
||||
for ($i = 0; $i < $bitCount && $node < $nodeCount; ++$i) {
|
||||
$tempBit = 0xff & $rawAddress[($i >> 3) + 1];
|
||||
$bit = 1 & $tempBit >> 7 - $i % 8;
|
||||
$node = $this->readNode($node, $bit);
|
||||
}
|
||||
if ($node === $nodeCount) {
|
||||
// Record is empty
|
||||
return [0, $i];
|
||||
}
|
||||
if ($node > $nodeCount) {
|
||||
// Record is a data pointer
|
||||
return [$node, $i];
|
||||
}
|
||||
throw new InvalidDatabaseException('Invalid or corrupt database. Maximum search depth reached without finding a leaf node');
|
||||
}
|
||||
private function ipV4StartNode() : int
|
||||
{
|
||||
// If we have an IPv4 database, the start node is the first node
|
||||
if ($this->metadata->ipVersion === 4) {
|
||||
return 0;
|
||||
}
|
||||
$node = 0;
|
||||
for ($i = 0; $i < 96 && $node < $this->metadata->nodeCount; ++$i) {
|
||||
$node = $this->readNode($node, 0);
|
||||
}
|
||||
return $node;
|
||||
}
|
||||
private function readNode(int $nodeNumber, int $index) : int
|
||||
{
|
||||
$baseOffset = $nodeNumber * $this->metadata->nodeByteSize;
|
||||
switch ($this->metadata->recordSize) {
|
||||
case 24:
|
||||
$bytes = Util::read($this->fileHandle, $baseOffset + $index * 3, 3);
|
||||
[, $node] = \unpack('N', "\x00" . $bytes);
|
||||
return $node;
|
||||
case 28:
|
||||
$bytes = Util::read($this->fileHandle, $baseOffset + 3 * $index, 4);
|
||||
if ($index === 0) {
|
||||
$middle = (0xf0 & \ord($bytes[3])) >> 4;
|
||||
} else {
|
||||
$middle = 0xf & \ord($bytes[0]);
|
||||
}
|
||||
[, $node] = \unpack('N', \chr($middle) . \substr($bytes, $index, 3));
|
||||
return $node;
|
||||
case 32:
|
||||
$bytes = Util::read($this->fileHandle, $baseOffset + $index * 4, 4);
|
||||
[, $node] = \unpack('N', $bytes);
|
||||
return $node;
|
||||
default:
|
||||
throw new InvalidDatabaseException('Unknown record size: ' . $this->metadata->recordSize);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
private function resolveDataPointer(int $pointer)
|
||||
{
|
||||
$resolved = $pointer - $this->metadata->nodeCount + $this->metadata->searchTreeSize;
|
||||
if ($resolved >= $this->fileSize) {
|
||||
throw new InvalidDatabaseException("The MaxMind DB file's search tree is corrupt");
|
||||
}
|
||||
[$data] = $this->decoder->decode($resolved);
|
||||
return $data;
|
||||
}
|
||||
/*
|
||||
* This is an extremely naive but reasonably readable implementation. There
|
||||
* are much faster algorithms (e.g., Boyer-Moore) for this if speed is ever
|
||||
* an issue, but I suspect it won't be.
|
||||
*/
|
||||
private function findMetadataStart(string $filename) : int
|
||||
{
|
||||
$handle = $this->fileHandle;
|
||||
$fstat = \fstat($handle);
|
||||
$fileSize = $fstat['size'];
|
||||
$marker = self::$METADATA_START_MARKER;
|
||||
$markerLength = self::$METADATA_START_MARKER_LENGTH;
|
||||
$minStart = $fileSize - \min(self::$METADATA_MAX_SIZE, $fileSize);
|
||||
for ($offset = $fileSize - $markerLength; $offset >= $minStart; --$offset) {
|
||||
if (\fseek($handle, $offset) !== 0) {
|
||||
break;
|
||||
}
|
||||
$value = \fread($handle, $markerLength);
|
||||
if ($value === $marker) {
|
||||
return $offset + $markerLength;
|
||||
}
|
||||
}
|
||||
throw new InvalidDatabaseException("Error opening database file ({$filename}). " . 'Is this a valid MaxMind DB file?');
|
||||
}
|
||||
/**
|
||||
* @throws InvalidArgumentException if arguments are passed to the method
|
||||
* @throws BadMethodCallException if the database has been closed
|
||||
*
|
||||
* @return Metadata object for the database
|
||||
*/
|
||||
public function metadata() : Metadata
|
||||
{
|
||||
if (\func_num_args()) {
|
||||
throw new ArgumentCountError(\sprintf('%s() expects exactly 0 parameters, %d given', __METHOD__, \func_num_args()));
|
||||
}
|
||||
// Not technically required, but this makes it consistent with
|
||||
// C extension and it allows us to change our implementation later.
|
||||
if (!\is_resource($this->fileHandle)) {
|
||||
throw new BadMethodCallException('Attempt to read from a closed MaxMind DB.');
|
||||
}
|
||||
return clone $this->metadata;
|
||||
}
|
||||
/**
|
||||
* Closes the MaxMind DB and returns resources to the system.
|
||||
*
|
||||
* @throws Exception
|
||||
* if an I/O error occurs
|
||||
*/
|
||||
public function close() : void
|
||||
{
|
||||
if (\func_num_args()) {
|
||||
throw new ArgumentCountError(\sprintf('%s() expects exactly 0 parameters, %d given', __METHOD__, \func_num_args()));
|
||||
}
|
||||
if (!\is_resource($this->fileHandle)) {
|
||||
throw new BadMethodCallException('Attempt to close a closed MaxMind DB.');
|
||||
}
|
||||
\fclose($this->fileHandle);
|
||||
}
|
||||
}
|
||||
275
plugins/system/tgeoip/vendor/maxmind-db/reader/src/MaxMind/Db/Reader/Decoder.php
vendored
Normal file
275
plugins/system/tgeoip/vendor/maxmind-db/reader/src/MaxMind/Db/Reader/Decoder.php
vendored
Normal file
@ -0,0 +1,275 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace Tassos\Vendor\MaxMind\Db\Reader;
|
||||
|
||||
// @codingStandardsIgnoreLine
|
||||
use RuntimeException;
|
||||
class Decoder
|
||||
{
|
||||
/**
|
||||
* @var resource
|
||||
*/
|
||||
private $fileStream;
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private $pointerBase;
|
||||
/**
|
||||
* @var float
|
||||
*/
|
||||
private $pointerBaseByteSize;
|
||||
/**
|
||||
* This is only used for unit testing.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
private $pointerTestHack;
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
private $switchByteOrder;
|
||||
private const _EXTENDED = 0;
|
||||
private const _POINTER = 1;
|
||||
private const _UTF8_STRING = 2;
|
||||
private const _DOUBLE = 3;
|
||||
private const _BYTES = 4;
|
||||
private const _UINT16 = 5;
|
||||
private const _UINT32 = 6;
|
||||
private const _MAP = 7;
|
||||
private const _INT32 = 8;
|
||||
private const _UINT64 = 9;
|
||||
private const _UINT128 = 10;
|
||||
private const _ARRAY = 11;
|
||||
private const _CONTAINER = 12;
|
||||
private const _END_MARKER = 13;
|
||||
private const _BOOLEAN = 14;
|
||||
private const _FLOAT = 15;
|
||||
/**
|
||||
* @param resource $fileStream
|
||||
*/
|
||||
public function __construct($fileStream, int $pointerBase = 0, bool $pointerTestHack = \false)
|
||||
{
|
||||
$this->fileStream = $fileStream;
|
||||
$this->pointerBase = $pointerBase;
|
||||
$this->pointerBaseByteSize = $pointerBase > 0 ? \log($pointerBase, 2) / 8 : 0;
|
||||
$this->pointerTestHack = $pointerTestHack;
|
||||
$this->switchByteOrder = $this->isPlatformLittleEndian();
|
||||
}
|
||||
public function decode(int $offset) : array
|
||||
{
|
||||
$ctrlByte = \ord(Util::read($this->fileStream, $offset, 1));
|
||||
++$offset;
|
||||
$type = $ctrlByte >> 5;
|
||||
// Pointers are a special case, we don't read the next $size bytes, we
|
||||
// use the size to determine the length of the pointer and then follow
|
||||
// it.
|
||||
if ($type === self::_POINTER) {
|
||||
[$pointer, $offset] = $this->decodePointer($ctrlByte, $offset);
|
||||
// for unit testing
|
||||
if ($this->pointerTestHack) {
|
||||
return [$pointer];
|
||||
}
|
||||
[$result] = $this->decode($pointer);
|
||||
return [$result, $offset];
|
||||
}
|
||||
if ($type === self::_EXTENDED) {
|
||||
$nextByte = \ord(Util::read($this->fileStream, $offset, 1));
|
||||
$type = $nextByte + 7;
|
||||
if ($type < 8) {
|
||||
throw new InvalidDatabaseException('Something went horribly wrong in the decoder. An extended type ' . 'resolved to a type number < 8 (' . $type . ')');
|
||||
}
|
||||
++$offset;
|
||||
}
|
||||
[$size, $offset] = $this->sizeFromCtrlByte($ctrlByte, $offset);
|
||||
return $this->decodeByType($type, $offset, $size);
|
||||
}
|
||||
private function decodeByType(int $type, int $offset, int $size) : array
|
||||
{
|
||||
switch ($type) {
|
||||
case self::_MAP:
|
||||
return $this->decodeMap($size, $offset);
|
||||
case self::_ARRAY:
|
||||
return $this->decodeArray($size, $offset);
|
||||
case self::_BOOLEAN:
|
||||
return [$this->decodeBoolean($size), $offset];
|
||||
}
|
||||
$newOffset = $offset + $size;
|
||||
$bytes = Util::read($this->fileStream, $offset, $size);
|
||||
switch ($type) {
|
||||
case self::_BYTES:
|
||||
case self::_UTF8_STRING:
|
||||
return [$bytes, $newOffset];
|
||||
case self::_DOUBLE:
|
||||
$this->verifySize(8, $size);
|
||||
return [$this->decodeDouble($bytes), $newOffset];
|
||||
case self::_FLOAT:
|
||||
$this->verifySize(4, $size);
|
||||
return [$this->decodeFloat($bytes), $newOffset];
|
||||
case self::_INT32:
|
||||
return [$this->decodeInt32($bytes, $size), $newOffset];
|
||||
case self::_UINT16:
|
||||
case self::_UINT32:
|
||||
case self::_UINT64:
|
||||
case self::_UINT128:
|
||||
return [$this->decodeUint($bytes, $size), $newOffset];
|
||||
default:
|
||||
throw new InvalidDatabaseException('Unknown or unexpected type: ' . $type);
|
||||
}
|
||||
}
|
||||
private function verifySize(int $expected, int $actual) : void
|
||||
{
|
||||
if ($expected !== $actual) {
|
||||
throw new InvalidDatabaseException("The MaxMind DB file's data section contains bad data (unknown data type or corrupt data)");
|
||||
}
|
||||
}
|
||||
private function decodeArray(int $size, int $offset) : array
|
||||
{
|
||||
$array = [];
|
||||
for ($i = 0; $i < $size; ++$i) {
|
||||
[$value, $offset] = $this->decode($offset);
|
||||
$array[] = $value;
|
||||
}
|
||||
return [$array, $offset];
|
||||
}
|
||||
private function decodeBoolean(int $size) : bool
|
||||
{
|
||||
return $size !== 0;
|
||||
}
|
||||
private function decodeDouble(string $bytes) : float
|
||||
{
|
||||
// This assumes IEEE 754 doubles, but most (all?) modern platforms
|
||||
// use them.
|
||||
[, $double] = \unpack('E', $bytes);
|
||||
return $double;
|
||||
}
|
||||
private function decodeFloat(string $bytes) : float
|
||||
{
|
||||
// This assumes IEEE 754 floats, but most (all?) modern platforms
|
||||
// use them.
|
||||
[, $float] = \unpack('G', $bytes);
|
||||
return $float;
|
||||
}
|
||||
private function decodeInt32(string $bytes, int $size) : int
|
||||
{
|
||||
switch ($size) {
|
||||
case 0:
|
||||
return 0;
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
$bytes = \str_pad($bytes, 4, "\x00", \STR_PAD_LEFT);
|
||||
break;
|
||||
case 4:
|
||||
break;
|
||||
default:
|
||||
throw new InvalidDatabaseException("The MaxMind DB file's data section contains bad data (unknown data type or corrupt data)");
|
||||
}
|
||||
[, $int] = \unpack('l', $this->maybeSwitchByteOrder($bytes));
|
||||
return $int;
|
||||
}
|
||||
private function decodeMap(int $size, int $offset) : array
|
||||
{
|
||||
$map = [];
|
||||
for ($i = 0; $i < $size; ++$i) {
|
||||
[$key, $offset] = $this->decode($offset);
|
||||
[$value, $offset] = $this->decode($offset);
|
||||
$map[$key] = $value;
|
||||
}
|
||||
return [$map, $offset];
|
||||
}
|
||||
private function decodePointer(int $ctrlByte, int $offset) : array
|
||||
{
|
||||
$pointerSize = ($ctrlByte >> 3 & 0x3) + 1;
|
||||
$buffer = Util::read($this->fileStream, $offset, $pointerSize);
|
||||
$offset = $offset + $pointerSize;
|
||||
switch ($pointerSize) {
|
||||
case 1:
|
||||
$packed = \chr($ctrlByte & 0x7) . $buffer;
|
||||
[, $pointer] = \unpack('n', $packed);
|
||||
$pointer += $this->pointerBase;
|
||||
break;
|
||||
case 2:
|
||||
$packed = "\x00" . \chr($ctrlByte & 0x7) . $buffer;
|
||||
[, $pointer] = \unpack('N', $packed);
|
||||
$pointer += $this->pointerBase + 2048;
|
||||
break;
|
||||
case 3:
|
||||
$packed = \chr($ctrlByte & 0x7) . $buffer;
|
||||
// It is safe to use 'N' here, even on 32 bit machines as the
|
||||
// first bit is 0.
|
||||
[, $pointer] = \unpack('N', $packed);
|
||||
$pointer += $this->pointerBase + 526336;
|
||||
break;
|
||||
case 4:
|
||||
// We cannot use unpack here as we might overflow on 32 bit
|
||||
// machines
|
||||
$pointerOffset = $this->decodeUint($buffer, $pointerSize);
|
||||
$pointerBase = $this->pointerBase;
|
||||
if (\PHP_INT_MAX - $pointerBase >= $pointerOffset) {
|
||||
$pointer = $pointerOffset + $pointerBase;
|
||||
} else {
|
||||
throw new RuntimeException('The database offset is too large to be represented on your platform.');
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new InvalidDatabaseException('Unexpected pointer size ' . $pointerSize);
|
||||
}
|
||||
return [$pointer, $offset];
|
||||
}
|
||||
// @phpstan-ignore-next-line
|
||||
private function decodeUint(string $bytes, int $byteLength)
|
||||
{
|
||||
if ($byteLength === 0) {
|
||||
return 0;
|
||||
}
|
||||
$integer = 0;
|
||||
// PHP integers are signed. PHP_INT_SIZE - 1 is the number of
|
||||
// complete bytes that can be converted to an integer. However,
|
||||
// we can convert another byte if the leading bit is zero.
|
||||
$useRealInts = $byteLength <= \PHP_INT_SIZE - 1 || $byteLength === \PHP_INT_SIZE && (\ord($bytes[0]) & 0x80) === 0;
|
||||
for ($i = 0; $i < $byteLength; ++$i) {
|
||||
$part = \ord($bytes[$i]);
|
||||
// We only use gmp or bcmath if the final value is too big
|
||||
if ($useRealInts) {
|
||||
$integer = ($integer << 8) + $part;
|
||||
} elseif (\extension_loaded('gmp')) {
|
||||
$integer = \gmp_strval(\gmp_add(\gmp_mul((string) $integer, '256'), $part));
|
||||
} elseif (\extension_loaded('bcmath')) {
|
||||
$integer = \bcadd(\bcmul((string) $integer, '256'), (string) $part);
|
||||
} else {
|
||||
throw new RuntimeException('The gmp or bcmath extension must be installed to read this database.');
|
||||
}
|
||||
}
|
||||
return $integer;
|
||||
}
|
||||
private function sizeFromCtrlByte(int $ctrlByte, int $offset) : array
|
||||
{
|
||||
$size = $ctrlByte & 0x1f;
|
||||
if ($size < 29) {
|
||||
return [$size, $offset];
|
||||
}
|
||||
$bytesToRead = $size - 28;
|
||||
$bytes = Util::read($this->fileStream, $offset, $bytesToRead);
|
||||
if ($size === 29) {
|
||||
$size = 29 + \ord($bytes);
|
||||
} elseif ($size === 30) {
|
||||
[, $adjust] = \unpack('n', $bytes);
|
||||
$size = 285 + $adjust;
|
||||
} else {
|
||||
[, $adjust] = \unpack('N', "\x00" . $bytes);
|
||||
$size = $adjust + 65821;
|
||||
}
|
||||
return [$size, $offset + $bytesToRead];
|
||||
}
|
||||
private function maybeSwitchByteOrder(string $bytes) : string
|
||||
{
|
||||
return $this->switchByteOrder ? \strrev($bytes) : $bytes;
|
||||
}
|
||||
private function isPlatformLittleEndian() : bool
|
||||
{
|
||||
$testint = 0xff;
|
||||
$packed = \pack('S', $testint);
|
||||
return $testint === \current(\unpack('v', $packed));
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,12 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace Tassos\Vendor\MaxMind\Db\Reader;
|
||||
|
||||
use Exception;
|
||||
/**
|
||||
* This class should be thrown when unexpected data is found in the database.
|
||||
*/
|
||||
class InvalidDatabaseException extends Exception
|
||||
{
|
||||
}
|
||||
104
plugins/system/tgeoip/vendor/maxmind-db/reader/src/MaxMind/Db/Reader/Metadata.php
vendored
Normal file
104
plugins/system/tgeoip/vendor/maxmind-db/reader/src/MaxMind/Db/Reader/Metadata.php
vendored
Normal file
@ -0,0 +1,104 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace Tassos\Vendor\MaxMind\Db\Reader;
|
||||
|
||||
use ArgumentCountError;
|
||||
/**
|
||||
* This class provides the metadata for the MaxMind DB file.
|
||||
*/
|
||||
class Metadata
|
||||
{
|
||||
/**
|
||||
* This is an unsigned 16-bit integer indicating the major version number
|
||||
* for the database's binary format.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $binaryFormatMajorVersion;
|
||||
/**
|
||||
* This is an unsigned 16-bit integer indicating the minor version number
|
||||
* for the database's binary format.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $binaryFormatMinorVersion;
|
||||
/**
|
||||
* This is an unsigned 64-bit integer that contains the database build
|
||||
* timestamp as a Unix epoch value.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $buildEpoch;
|
||||
/**
|
||||
* This is a string that indicates the structure of each data record
|
||||
* associated with an IP address. The actual definition of these
|
||||
* structures is left up to the database creator.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $databaseType;
|
||||
/**
|
||||
* This key will always point to a map (associative array). The keys of
|
||||
* that map will be language codes, and the values will be a description
|
||||
* in that language as a UTF-8 string. May be undefined for some
|
||||
* databases.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $description;
|
||||
/**
|
||||
* This is an unsigned 16-bit integer which is always 4 or 6. It indicates
|
||||
* whether the database contains IPv4 or IPv6 address data.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $ipVersion;
|
||||
/**
|
||||
* An array of strings, each of which is a language code. A given record
|
||||
* may contain data items that have been localized to some or all of
|
||||
* these languages. This may be undefined.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $languages;
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
public $nodeByteSize;
|
||||
/**
|
||||
* This is an unsigned 32-bit integer indicating the number of nodes in
|
||||
* the search tree.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $nodeCount;
|
||||
/**
|
||||
* This is an unsigned 16-bit integer. It indicates the number of bits in a
|
||||
* record in the search tree. Note that each node consists of two records.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $recordSize;
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
public $searchTreeSize;
|
||||
public function __construct(array $metadata)
|
||||
{
|
||||
if (\func_num_args() !== 1) {
|
||||
throw new ArgumentCountError(\sprintf('%s() expects exactly 1 parameter, %d given', __METHOD__, \func_num_args()));
|
||||
}
|
||||
$this->binaryFormatMajorVersion = $metadata['binary_format_major_version'];
|
||||
$this->binaryFormatMinorVersion = $metadata['binary_format_minor_version'];
|
||||
$this->buildEpoch = $metadata['build_epoch'];
|
||||
$this->databaseType = $metadata['database_type'];
|
||||
$this->languages = $metadata['languages'];
|
||||
$this->description = $metadata['description'];
|
||||
$this->ipVersion = $metadata['ip_version'];
|
||||
$this->nodeCount = $metadata['node_count'];
|
||||
$this->recordSize = $metadata['record_size'];
|
||||
$this->nodeByteSize = $this->recordSize / 4;
|
||||
$this->searchTreeSize = $this->nodeCount * $this->nodeByteSize;
|
||||
}
|
||||
}
|
||||
27
plugins/system/tgeoip/vendor/maxmind-db/reader/src/MaxMind/Db/Reader/Util.php
vendored
Normal file
27
plugins/system/tgeoip/vendor/maxmind-db/reader/src/MaxMind/Db/Reader/Util.php
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace Tassos\Vendor\MaxMind\Db\Reader;
|
||||
|
||||
class Util
|
||||
{
|
||||
/**
|
||||
* @param resource $stream
|
||||
*/
|
||||
public static function read($stream, int $offset, int $numberOfBytes) : string
|
||||
{
|
||||
if ($numberOfBytes === 0) {
|
||||
return '';
|
||||
}
|
||||
if (\fseek($stream, $offset) === 0) {
|
||||
$value = \fread($stream, $numberOfBytes);
|
||||
// We check that the number of bytes read is equal to the number
|
||||
// asked for. We use ftell as getting the length of $value is
|
||||
// much slower.
|
||||
if ($value !== \false && \ftell($stream) - $offset === $numberOfBytes) {
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
throw new InvalidDatabaseException('The MaxMind DB file contains bad data');
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user