Skip to content

Commit e18e537

Browse files
committed
Fixed unpack casting issue in PHP 8.
1 parent d7af5b7 commit e18e537

File tree

2 files changed

+66
-32
lines changed

2 files changed

+66
-32
lines changed

docs/source/conf.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@
99
copyright = '2025, IP2Location'
1010
author = 'IP2Location'
1111

12-
release = '9.8.0'
13-
version = '9.8.0'
12+
release = '9.8.1'
13+
version = '9.8.1'
1414

1515
# -- General configuration
1616

src/Database.php

Lines changed: 64 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ class Database
1212
*
1313
* @var string
1414
*/
15-
public const VERSION = '9.8.0';
15+
public const VERSION = '9.8.1';
1616

1717
/**
1818
* Unsupported field message.
@@ -1611,36 +1611,38 @@ private function getShmKey($filename)
16111611
/**
16121612
* Determine whether the given IP number of the given version lies between the given bounds.
16131613
*
1614-
* This function will return 0 if the given ip number falls within the given bounds
1615-
* for the given version, -1 if it falls below, and 1 if it falls above.
1616-
*
16171614
* @param int $version IP version to use (either 4 or 6)
1618-
* @param int|string $ip IP number to check (int for IPv4, string for IPv6)
1619-
* @param int|string $low Lower bound (int for IPv4, string for IPv6)
1620-
* @param int|string $high Uppoer bound (int for IPv4, string for IPv6)
1615+
* @param int|string $ip IP number to check
1616+
* @param int|string $low Lower bound
1617+
* @param int|string $high Upper bound
16211618
*
16221619
* @return int
16231620
*/
16241621
private function ipBetween($version, $ip, $low, $high)
16251622
{
16261623
if ($version === 4) {
1627-
// Use normal PHP ints
1624+
// Cast unpack results to unsigned integer strings for safe comparison
1625+
if ($low < 0) {
1626+
$low = sprintf('%u', $low);
1627+
}
1628+
if ($high < 0) {
1629+
$high = sprintf('%u', $high);
1630+
}
1631+
16281632
if ($low <= $ip) {
16291633
if ($ip < $high) {
16301634
return 0;
16311635
}
1632-
16331636
return 1;
16341637
}
1635-
16361638
return -1;
16371639
}
1638-
// Use BCMath
1640+
1641+
// IPv6
16391642
if (bccomp($low, $ip, 0) <= 0) {
16401643
if (bccomp($ip, $high, 0) <= -1) {
16411644
return 0;
16421645
}
1643-
16441646
return 1;
16451647
}
16461648

@@ -1703,8 +1705,8 @@ private function ipVersionAndNumber($ip)
17031705
*/
17041706
private function bcBin2Dec($data)
17051707
{
1706-
if (!$data) {
1707-
return;
1708+
if (strlen($data) < 16) {
1709+
return '0';
17081710
}
17091711

17101712
$parts = [
@@ -1716,11 +1718,22 @@ private function bcBin2Dec($data)
17161718

17171719
foreach ($parts as &$part) {
17181720
if ($part[1] < 0) {
1719-
$part[1] += 4294967296;
1721+
$part[1] = bcadd((string)$part[1], '4294967296');
17201722
}
17211723
}
17221724

1723-
$result = bcadd(bcadd(bcmul($parts[0][1], bcpow(4294967296, 3)), bcmul($parts[1][1], bcpow(4294967296, 2))), bcadd(bcmul($parts[2][1], 4294967296), $parts[3][1]));
1725+
$base = '4294967296';
1726+
1727+
$result = bcadd(
1728+
bcadd(
1729+
bcmul((string)$parts[0][1], bcpow($base, '3')),
1730+
bcmul((string)$parts[1][1], bcpow($base, '2'))
1731+
),
1732+
bcadd(
1733+
bcmul((string)$parts[2][1], $base),
1734+
(string)$parts[3][1]
1735+
)
1736+
);
17241737

17251738
return $result;
17261739
}
@@ -1749,18 +1762,16 @@ private function expand($ipv6)
17491762
*/
17501763
private function read($pos, $len)
17511764
{
1752-
switch ($this->mode) {
1753-
case self::SHARED_MEMORY:
1754-
return shmop_read($this->resource, $pos, $len);
1755-
1756-
case self::MEMORY_CACHE:
1757-
return $data = substr($this->buffer[$this->resource], $pos, $len);
1758-
1759-
default:
1760-
fseek($this->resource, $pos, SEEK_SET);
1765+
if ($this->mode === self::MEMORY_CACHE) {
1766+
return (string) substr($this->buffer[$this->resource], $pos, $len);
1767+
}
17611768

1762-
return fread($this->resource, $len);
1769+
if ($this->mode === self::SHARED_MEMORY) {
1770+
return shmop_read($this->resource, $pos, $len);
17631771
}
1772+
1773+
fseek($this->resource, $pos, SEEK_SET);
1774+
return fread($this->resource, $len);
17641775
}
17651776

17661777
/**
@@ -2282,15 +2293,38 @@ private function readAsCidr($pointer)
22822293
*/
22832294
private function getIpBoundary($ipVersion, $position, $width)
22842295
{
2285-
// Read 128 bits from the position
2286-
$section = $this->read($position, 128);
2296+
$readLength = $width + ($ipVersion === 4 ? 4 : 16);
2297+
2298+
// Read the exact chunk needed
2299+
$section = $this->read($position, $readLength);
22872300

22882301
switch ($ipVersion) {
22892302
case 4:
2290-
return [unpack('V', substr($section, 0, 4))[1], unpack('V', substr($section, $width, 4))[1]];
2303+
// Check if substring extraction works
2304+
$first = substr($section, 0, 4);
2305+
$second = substr($section, $width, 4);
2306+
2307+
if ($first === false || $second === false) {
2308+
return [false, false];
2309+
}
2310+
2311+
return [
2312+
unpack('V', $first)[1],
2313+
unpack('V', $second)[1]
2314+
];
22912315

22922316
case 6:
2293-
return [$this->bcBin2Dec(substr($section, 0, 16)), $this->bcBin2Dec(substr($section, $width, 16))];
2317+
$first = substr($section, 0, 16);
2318+
$second = substr($section, $width, 16);
2319+
2320+
if ($first === false || $second === false || strlen($second) < 16) {
2321+
return [false, false];
2322+
}
2323+
2324+
return [
2325+
$this->bcBin2Dec($first),
2326+
$this->bcBin2Dec($second)
2327+
];
22942328
}
22952329

22962330
return [false, false];

0 commit comments

Comments
 (0)