Merged in feature/280-dev-dev01 (pull request #21)
auto-patch 280-dev-dev01-2024-01-19T16_41_58 * auto-patch 280-dev-dev01-2024-01-19T16_41_58
This commit is contained in:
@@ -35,7 +35,7 @@ function mmdb_autoload($class): void
|
||||
$path = str_replace('\\', '/', $path);
|
||||
|
||||
// and finally, add the PHP file extension to the result.
|
||||
$path = $path . '.php';
|
||||
$path .= '.php';
|
||||
|
||||
// $path should now contain the path to a PHP file defining $class
|
||||
if (file_exists($path)) {
|
||||
|
||||
@@ -3,7 +3,7 @@ PHP_ARG_WITH(maxminddb,
|
||||
[ --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)
|
||||
[ --enable-maxminddb-debug Enable MaxMind DB debug support], no, no)
|
||||
|
||||
if test $PHP_MAXMINDDB != "no"; then
|
||||
|
||||
|
||||
@@ -143,7 +143,7 @@ PHP_METHOD(MaxMind_Db_Reader, __construct) {
|
||||
}
|
||||
|
||||
MMDB_s *mmdb = (MMDB_s *)ecalloc(1, sizeof(MMDB_s));
|
||||
uint16_t status = MMDB_open(db_file, MMDB_MODE_MMAP, mmdb);
|
||||
int const status = MMDB_open(db_file, MMDB_MODE_MMAP, mmdb);
|
||||
|
||||
if (MMDB_SUCCESS != status) {
|
||||
zend_throw_exception_ex(
|
||||
@@ -388,12 +388,12 @@ handle_entry_data_list(const MMDB_entry_data_list_s *entry_data_list,
|
||||
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.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,
|
||||
(char const *)entry_data_list->entry_data.bytes,
|
||||
entry_data_list->entry_data.data_size);
|
||||
break;
|
||||
case MMDB_DATA_TYPE_DOUBLE:
|
||||
@@ -440,7 +440,7 @@ handle_map(const MMDB_entry_data_list_s *entry_data_list,
|
||||
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,
|
||||
char *key = estrndup(entry_data_list->entry_data.utf8_string,
|
||||
entry_data_list->entry_data.data_size);
|
||||
if (NULL == key) {
|
||||
zend_throw_exception_ex(maxminddb_exception_ce,
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
|
||||
#ifndef PHP_MAXMINDDB_H
|
||||
#define PHP_MAXMINDDB_H 1
|
||||
#define PHP_MAXMINDDB_VERSION "1.10.1"
|
||||
#define PHP_MAXMINDDB_VERSION "1.11.1"
|
||||
#define PHP_MAXMINDDB_EXTNAME "maxminddb"
|
||||
|
||||
extern zend_module_entry maxminddb_module_entry;
|
||||
|
||||
@@ -14,19 +14,19 @@
|
||||
<email>goschwald@maxmind.com</email>
|
||||
<active>yes</active>
|
||||
</lead>
|
||||
<date>2021-04-14</date>
|
||||
<date>2023-12-01</date>
|
||||
<version>
|
||||
<release>1.10.1</release>
|
||||
<api>1.10.1</api>
|
||||
<release>1.11.1</release>
|
||||
<api>1.11.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>
|
||||
<notes>* Resolve warnings when compiling the C extension.
|
||||
* Fix various type issues detected by PHPStan level. Pull request by
|
||||
LauraTaylorUK. GitHub #160.</notes>
|
||||
<contents>
|
||||
<dir name="/">
|
||||
<file role="doc" name="LICENSE"/>
|
||||
|
||||
@@ -4,15 +4,10 @@ declare(strict_types=1);
|
||||
|
||||
namespace MaxMind\Db;
|
||||
|
||||
use ArgumentCountError;
|
||||
use BadMethodCallException;
|
||||
use Exception;
|
||||
use InvalidArgumentException;
|
||||
use MaxMind\Db\Reader\Decoder;
|
||||
use MaxMind\Db\Reader\InvalidDatabaseException;
|
||||
use MaxMind\Db\Reader\Metadata;
|
||||
use MaxMind\Db\Reader\Util;
|
||||
use UnexpectedValueException;
|
||||
|
||||
/**
|
||||
* Instances of this class provide a reader for the MaxMind DB format. IP
|
||||
@@ -24,14 +19,17 @@ class Reader
|
||||
* @var int
|
||||
*/
|
||||
private static $DATA_SECTION_SEPARATOR_SIZE = 16;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private static $METADATA_START_MARKER = "\xAB\xCD\xEFMaxMind.com";
|
||||
|
||||
/**
|
||||
* @var int
|
||||
* @var int<0, max>
|
||||
*/
|
||||
private static $METADATA_START_MARKER_LENGTH = 14;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
@@ -41,18 +39,22 @@ class Reader
|
||||
* @var Decoder
|
||||
*/
|
||||
private $decoder;
|
||||
|
||||
/**
|
||||
* @var resource
|
||||
*/
|
||||
private $fileHandle;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private $fileSize;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private $ipV4Start;
|
||||
|
||||
/**
|
||||
* @var Metadata
|
||||
*/
|
||||
@@ -65,22 +67,22 @@ class Reader
|
||||
* @param string $database
|
||||
* the MaxMind DB file to use
|
||||
*
|
||||
* @throws InvalidArgumentException for invalid database path or unknown arguments
|
||||
* @throws \InvalidArgumentException for invalid database path or unknown arguments
|
||||
* @throws InvalidDatabaseException
|
||||
* if the database is invalid or there is an error reading
|
||||
* from it
|
||||
* 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(
|
||||
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(
|
||||
throw new \InvalidArgumentException(
|
||||
"The file \"$database\" does not exist or is not readable."
|
||||
);
|
||||
}
|
||||
@@ -88,7 +90,7 @@ class Reader
|
||||
|
||||
$fileSize = @filesize($database);
|
||||
if ($fileSize === false) {
|
||||
throw new UnexpectedValueException(
|
||||
throw new \UnexpectedValueException(
|
||||
"Error determining the size of \"$database\"."
|
||||
);
|
||||
}
|
||||
@@ -111,18 +113,18 @@ class Reader
|
||||
* @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 \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
|
||||
* 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(
|
||||
throw new \ArgumentCountError(
|
||||
sprintf('%s() expects exactly 1 parameter, %d given', __METHOD__, \func_num_args())
|
||||
);
|
||||
}
|
||||
@@ -137,11 +139,11 @@ class Reader
|
||||
* @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 \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
|
||||
* 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
|
||||
@@ -149,13 +151,13 @@ class Reader
|
||||
public function getWithPrefixLen(string $ipAddress): array
|
||||
{
|
||||
if (\func_num_args() !== 1) {
|
||||
throw new ArgumentCountError(
|
||||
throw new \ArgumentCountError(
|
||||
sprintf('%s() expects exactly 1 parameter, %d given', __METHOD__, \func_num_args())
|
||||
);
|
||||
}
|
||||
|
||||
if (!\is_resource($this->fileHandle)) {
|
||||
throw new BadMethodCallException(
|
||||
throw new \BadMethodCallException(
|
||||
'Attempt to read from a closed MaxMind DB.'
|
||||
);
|
||||
}
|
||||
@@ -172,12 +174,17 @@ class Reader
|
||||
{
|
||||
$packedAddr = @inet_pton($ipAddress);
|
||||
if ($packedAddr === false) {
|
||||
throw new InvalidArgumentException(
|
||||
throw new \InvalidArgumentException(
|
||||
"The value \"$ipAddress\" is not a valid IP address."
|
||||
);
|
||||
}
|
||||
|
||||
$rawAddress = unpack('C*', $packedAddr);
|
||||
if ($rawAddress === false) {
|
||||
throw new InvalidDatabaseException(
|
||||
'Could not unpack the unsigned char of the packed in_addr representation.'
|
||||
);
|
||||
}
|
||||
|
||||
$bitCount = \count($rawAddress) * 8;
|
||||
|
||||
@@ -194,7 +201,7 @@ class Reader
|
||||
$node = $this->ipV4Start;
|
||||
}
|
||||
} elseif ($metadata->ipVersion === 4 && $bitCount === 128) {
|
||||
throw new InvalidArgumentException(
|
||||
throw new \InvalidArgumentException(
|
||||
"Error looking up $ipAddress. You attempted to look up an"
|
||||
. ' IPv6 address in an IPv4-only database.'
|
||||
);
|
||||
@@ -245,7 +252,13 @@ class Reader
|
||||
switch ($this->metadata->recordSize) {
|
||||
case 24:
|
||||
$bytes = Util::read($this->fileHandle, $baseOffset + $index * 3, 3);
|
||||
[, $node] = unpack('N', "\x00" . $bytes);
|
||||
$rc = unpack('N', "\x00" . $bytes);
|
||||
if ($rc === false) {
|
||||
throw new InvalidDatabaseException(
|
||||
'Could not unpack the unsigned long of the node.'
|
||||
);
|
||||
}
|
||||
[, $node] = $rc;
|
||||
|
||||
return $node;
|
||||
|
||||
@@ -256,13 +269,25 @@ class Reader
|
||||
} else {
|
||||
$middle = 0x0F & \ord($bytes[0]);
|
||||
}
|
||||
[, $node] = unpack('N', \chr($middle) . substr($bytes, $index, 3));
|
||||
$rc = unpack('N', \chr($middle) . substr($bytes, $index, 3));
|
||||
if ($rc === false) {
|
||||
throw new InvalidDatabaseException(
|
||||
'Could not unpack the unsigned long of the node.'
|
||||
);
|
||||
}
|
||||
[, $node] = $rc;
|
||||
|
||||
return $node;
|
||||
|
||||
case 32:
|
||||
$bytes = Util::read($this->fileHandle, $baseOffset + $index * 4, 4);
|
||||
[, $node] = unpack('N', $bytes);
|
||||
$rc = unpack('N', $bytes);
|
||||
if ($rc === false) {
|
||||
throw new InvalidDatabaseException(
|
||||
'Could not unpack the unsigned long of the node.'
|
||||
);
|
||||
}
|
||||
[, $node] = $rc;
|
||||
|
||||
return $node;
|
||||
|
||||
@@ -301,6 +326,11 @@ class Reader
|
||||
{
|
||||
$handle = $this->fileHandle;
|
||||
$fstat = fstat($handle);
|
||||
if ($fstat === false) {
|
||||
throw new InvalidDatabaseException(
|
||||
"Error getting file information ($filename)."
|
||||
);
|
||||
}
|
||||
$fileSize = $fstat['size'];
|
||||
$marker = self::$METADATA_START_MARKER;
|
||||
$markerLength = self::$METADATA_START_MARKER_LENGTH;
|
||||
@@ -325,15 +355,15 @@ class Reader
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws InvalidArgumentException if arguments are passed to the method
|
||||
* @throws BadMethodCallException if the database has been closed
|
||||
* @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(
|
||||
throw new \ArgumentCountError(
|
||||
sprintf('%s() expects exactly 0 parameters, %d given', __METHOD__, \func_num_args())
|
||||
);
|
||||
}
|
||||
@@ -341,7 +371,7 @@ class Reader
|
||||
// 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(
|
||||
throw new \BadMethodCallException(
|
||||
'Attempt to read from a closed MaxMind DB.'
|
||||
);
|
||||
}
|
||||
@@ -352,19 +382,19 @@ class Reader
|
||||
/**
|
||||
* Closes the MaxMind DB and returns resources to the system.
|
||||
*
|
||||
* @throws Exception
|
||||
* if an I/O error occurs
|
||||
* @throws \Exception
|
||||
* if an I/O error occurs
|
||||
*/
|
||||
public function close(): void
|
||||
{
|
||||
if (\func_num_args()) {
|
||||
throw new ArgumentCountError(
|
||||
throw new \ArgumentCountError(
|
||||
sprintf('%s() expects exactly 0 parameters, %d given', __METHOD__, \func_num_args())
|
||||
);
|
||||
}
|
||||
|
||||
if (!\is_resource($this->fileHandle)) {
|
||||
throw new BadMethodCallException(
|
||||
throw new \BadMethodCallException(
|
||||
'Attempt to close a closed MaxMind DB.'
|
||||
);
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@ declare(strict_types=1);
|
||||
namespace MaxMind\Db\Reader;
|
||||
|
||||
// @codingStandardsIgnoreLine
|
||||
use RuntimeException;
|
||||
|
||||
class Decoder
|
||||
{
|
||||
@@ -13,20 +12,19 @@ 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
|
||||
*/
|
||||
@@ -44,8 +42,8 @@ class Decoder
|
||||
private const _UINT64 = 9;
|
||||
private const _UINT128 = 10;
|
||||
private const _ARRAY = 11;
|
||||
private const _CONTAINER = 12;
|
||||
private const _END_MARKER = 13;
|
||||
// 12 is the container type
|
||||
// 13 is the end marker type
|
||||
private const _BOOLEAN = 14;
|
||||
private const _FLOAT = 15;
|
||||
|
||||
@@ -60,7 +58,6 @@ class Decoder
|
||||
$this->fileStream = $fileStream;
|
||||
$this->pointerBase = $pointerBase;
|
||||
|
||||
$this->pointerBaseByteSize = $pointerBase > 0 ? log($pointerBase, 2) / 8 : 0;
|
||||
$this->pointerTestHack = $pointerTestHack;
|
||||
|
||||
$this->switchByteOrder = $this->isPlatformLittleEndian();
|
||||
@@ -111,6 +108,9 @@ class Decoder
|
||||
return $this->decodeByType($type, $offset, $size);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int<0, max> $size
|
||||
*/
|
||||
private function decodeByType(int $type, int $offset, int $size): array
|
||||
{
|
||||
switch ($type) {
|
||||
@@ -188,7 +188,13 @@ class Decoder
|
||||
{
|
||||
// This assumes IEEE 754 doubles, but most (all?) modern platforms
|
||||
// use them.
|
||||
[, $double] = unpack('E', $bytes);
|
||||
$rc = unpack('E', $bytes);
|
||||
if ($rc === false) {
|
||||
throw new InvalidDatabaseException(
|
||||
'Could not unpack a double value from the given bytes.'
|
||||
);
|
||||
}
|
||||
[, $double] = $rc;
|
||||
|
||||
return $double;
|
||||
}
|
||||
@@ -197,7 +203,13 @@ class Decoder
|
||||
{
|
||||
// This assumes IEEE 754 floats, but most (all?) modern platforms
|
||||
// use them.
|
||||
[, $float] = unpack('G', $bytes);
|
||||
$rc = unpack('G', $bytes);
|
||||
if ($rc === false) {
|
||||
throw new InvalidDatabaseException(
|
||||
'Could not unpack a float value from the given bytes.'
|
||||
);
|
||||
}
|
||||
[, $float] = $rc;
|
||||
|
||||
return $float;
|
||||
}
|
||||
@@ -224,7 +236,13 @@ class Decoder
|
||||
);
|
||||
}
|
||||
|
||||
[, $int] = unpack('l', $this->maybeSwitchByteOrder($bytes));
|
||||
$rc = unpack('l', $this->maybeSwitchByteOrder($bytes));
|
||||
if ($rc === false) {
|
||||
throw new InvalidDatabaseException(
|
||||
'Could not unpack a 32bit integer value from the given bytes.'
|
||||
);
|
||||
}
|
||||
[, $int] = $rc;
|
||||
|
||||
return $int;
|
||||
}
|
||||
@@ -247,19 +265,31 @@ class Decoder
|
||||
$pointerSize = (($ctrlByte >> 3) & 0x3) + 1;
|
||||
|
||||
$buffer = Util::read($this->fileStream, $offset, $pointerSize);
|
||||
$offset = $offset + $pointerSize;
|
||||
$offset += $pointerSize;
|
||||
|
||||
switch ($pointerSize) {
|
||||
case 1:
|
||||
$packed = \chr($ctrlByte & 0x7) . $buffer;
|
||||
[, $pointer] = unpack('n', $packed);
|
||||
$rc = unpack('n', $packed);
|
||||
if ($rc === false) {
|
||||
throw new InvalidDatabaseException(
|
||||
'Could not unpack an unsigned short value from the given bytes (pointerSize is 1).'
|
||||
);
|
||||
}
|
||||
[, $pointer] = $rc;
|
||||
$pointer += $this->pointerBase;
|
||||
|
||||
break;
|
||||
|
||||
case 2:
|
||||
$packed = "\x00" . \chr($ctrlByte & 0x7) . $buffer;
|
||||
[, $pointer] = unpack('N', $packed);
|
||||
$rc = unpack('N', $packed);
|
||||
if ($rc === false) {
|
||||
throw new InvalidDatabaseException(
|
||||
'Could not unpack an unsigned long value from the given bytes (pointerSize is 2).'
|
||||
);
|
||||
}
|
||||
[, $pointer] = $rc;
|
||||
$pointer += $this->pointerBase + 2048;
|
||||
|
||||
break;
|
||||
@@ -269,7 +299,13 @@ class Decoder
|
||||
|
||||
// It is safe to use 'N' here, even on 32 bit machines as the
|
||||
// first bit is 0.
|
||||
[, $pointer] = unpack('N', $packed);
|
||||
$rc = unpack('N', $packed);
|
||||
if ($rc === false) {
|
||||
throw new InvalidDatabaseException(
|
||||
'Could not unpack an unsigned long value from the given bytes (pointerSize is 3).'
|
||||
);
|
||||
}
|
||||
[, $pointer] = $rc;
|
||||
$pointer += $this->pointerBase + 526336;
|
||||
|
||||
break;
|
||||
@@ -284,7 +320,7 @@ class Decoder
|
||||
if (\PHP_INT_MAX - $pointerBase >= $pointerOffset) {
|
||||
$pointer = $pointerOffset + $pointerBase;
|
||||
} else {
|
||||
throw new RuntimeException(
|
||||
throw new \RuntimeException(
|
||||
'The database offset is too large to be represented on your platform.'
|
||||
);
|
||||
}
|
||||
@@ -307,32 +343,39 @@ class Decoder
|
||||
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);
|
||||
|
||||
if ($useRealInts) {
|
||||
$integer = 0;
|
||||
for ($i = 0; $i < $byteLength; ++$i) {
|
||||
$part = \ord($bytes[$i]);
|
||||
$integer = ($integer << 8) + $part;
|
||||
}
|
||||
|
||||
return $integer;
|
||||
}
|
||||
|
||||
// We only use gmp or bcmath if the final value is too big
|
||||
$integerAsString = '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));
|
||||
if (\extension_loaded('gmp')) {
|
||||
$integerAsString = gmp_strval(gmp_add(gmp_mul($integerAsString, '256'), $part));
|
||||
} elseif (\extension_loaded('bcmath')) {
|
||||
$integer = bcadd(bcmul((string) $integer, '256'), (string) $part);
|
||||
$integerAsString = bcadd(bcmul($integerAsString, '256'), (string) $part);
|
||||
} else {
|
||||
throw new RuntimeException(
|
||||
throw new \RuntimeException(
|
||||
'The gmp or bcmath extension must be installed to read this database.'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return $integer;
|
||||
return $integerAsString;
|
||||
}
|
||||
|
||||
private function sizeFromCtrlByte(int $ctrlByte, int $offset): array
|
||||
@@ -349,10 +392,22 @@ class Decoder
|
||||
if ($size === 29) {
|
||||
$size = 29 + \ord($bytes);
|
||||
} elseif ($size === 30) {
|
||||
[, $adjust] = unpack('n', $bytes);
|
||||
$rc = unpack('n', $bytes);
|
||||
if ($rc === false) {
|
||||
throw new InvalidDatabaseException(
|
||||
'Could not unpack an unsigned short value from the given bytes.'
|
||||
);
|
||||
}
|
||||
[, $adjust] = $rc;
|
||||
$size = 285 + $adjust;
|
||||
} else {
|
||||
[, $adjust] = unpack('N', "\x00" . $bytes);
|
||||
$rc = unpack('N', "\x00" . $bytes);
|
||||
if ($rc === false) {
|
||||
throw new InvalidDatabaseException(
|
||||
'Could not unpack an unsigned long value from the given bytes.'
|
||||
);
|
||||
}
|
||||
[, $adjust] = $rc;
|
||||
$size = $adjust + 65821;
|
||||
}
|
||||
|
||||
@@ -368,7 +423,13 @@ class Decoder
|
||||
{
|
||||
$testint = 0x00FF;
|
||||
$packed = pack('S', $testint);
|
||||
$rc = unpack('v', $packed);
|
||||
if ($rc === false) {
|
||||
throw new InvalidDatabaseException(
|
||||
'Could not unpack an unsigned short value from the given bytes.'
|
||||
);
|
||||
}
|
||||
|
||||
return $testint === current(unpack('v', $packed));
|
||||
return $testint === current($rc);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,11 +4,8 @@ declare(strict_types=1);
|
||||
|
||||
namespace MaxMind\Db\Reader;
|
||||
|
||||
use Exception;
|
||||
|
||||
/**
|
||||
* This class should be thrown when unexpected data is found in the database.
|
||||
*/
|
||||
class InvalidDatabaseException extends Exception
|
||||
{
|
||||
}
|
||||
// phpcs:disable
|
||||
class InvalidDatabaseException extends \Exception {}
|
||||
|
||||
@@ -4,8 +4,6 @@ declare(strict_types=1);
|
||||
|
||||
namespace MaxMind\Db\Reader;
|
||||
|
||||
use ArgumentCountError;
|
||||
|
||||
/**
|
||||
* This class provides the metadata for the MaxMind DB file.
|
||||
*/
|
||||
@@ -18,6 +16,7 @@ class Metadata
|
||||
* @var int
|
||||
*/
|
||||
public $binaryFormatMajorVersion;
|
||||
|
||||
/**
|
||||
* This is an unsigned 16-bit integer indicating the minor version number
|
||||
* for the database's binary format.
|
||||
@@ -25,6 +24,7 @@ class Metadata
|
||||
* @var int
|
||||
*/
|
||||
public $binaryFormatMinorVersion;
|
||||
|
||||
/**
|
||||
* This is an unsigned 64-bit integer that contains the database build
|
||||
* timestamp as a Unix epoch value.
|
||||
@@ -32,6 +32,7 @@ class Metadata
|
||||
* @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
|
||||
@@ -40,6 +41,7 @@ class Metadata
|
||||
* @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
|
||||
@@ -49,6 +51,7 @@ class Metadata
|
||||
* @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.
|
||||
@@ -56,6 +59,7 @@ class Metadata
|
||||
* @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
|
||||
@@ -64,10 +68,12 @@ class Metadata
|
||||
* @var array
|
||||
*/
|
||||
public $languages;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
public $nodeByteSize;
|
||||
|
||||
/**
|
||||
* This is an unsigned 32-bit integer indicating the number of nodes in
|
||||
* the search tree.
|
||||
@@ -75,6 +81,7 @@ class Metadata
|
||||
* @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.
|
||||
@@ -82,6 +89,7 @@ class Metadata
|
||||
* @var int
|
||||
*/
|
||||
public $recordSize;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
@@ -90,7 +98,7 @@ class Metadata
|
||||
public function __construct(array $metadata)
|
||||
{
|
||||
if (\func_num_args() !== 1) {
|
||||
throw new ArgumentCountError(
|
||||
throw new \ArgumentCountError(
|
||||
sprintf('%s() expects exactly 1 parameter, %d given', __METHOD__, \func_num_args())
|
||||
);
|
||||
}
|
||||
|
||||
@@ -7,7 +7,8 @@ namespace MaxMind\Db\Reader;
|
||||
class Util
|
||||
{
|
||||
/**
|
||||
* @param resource $stream
|
||||
* @param resource $stream
|
||||
* @param int<0, max> $numberOfBytes
|
||||
*/
|
||||
public static function read($stream, int $offset, int $numberOfBytes): string
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user