@@ -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