diff --git a/binding/php/ReadMe.md b/binding/php/ReadMe.md index 0c42ea9..c00a073 100644 --- a/binding/php/ReadMe.md +++ b/binding/php/ReadMe.md @@ -2,30 +2,57 @@ # 使用方式 -第三方 composer 地址: +第三方 composer 地址 (请自行确认仓库对 IPv6 的支持): 1. [https://github.com/zoujingli/ip2region](https://github.com/zoujingli/ip2region) 2. [https://github.com/chinayin/ip2region-core-php](https://github.com/chinayin/ip2region-core-php) + +### 关于 IPv4 和 IPv6 +该 xdb 查询客户端实现同时支持对 IPv4 和 IPv6 的查询,使用方式如下: +```php +use \ip2region\xdb\{IPv4, IPv6}; + +// 如果是 IPv4: 设置 xdb 路径为 v4 的 xdb 文件,IP版本指定为 IPv4 +$dbFile = "../../data/ip2region_v4.xdb"; // 或者你的 ipv4 xdb 的路径 +$version = IPv4::default(); + +// 如果是 IPv6: 设置 xdb 路径为 v6 的 xdb 文件,IP版本指定为 IPv6 +$dbFile = "../../data/ip2region_v6.xdb"; // 或者你的 ipv6 xdb 路径 +$version = IPv6::default(); + +// dbPath 指定的 xdb 的 IP 版本必须和 version 指定的一致,不然查询执行的时候会报错 +// 备注:以下演示直接使用 $dbFile 和 $version 变量 +``` + ### 完全基于文件的查询 ```php -$dbFile = "ip2region.xdb file path"; +// require or autoload the xdb\Searcher +require 'xdb\Searcher.php'; +use \ip2region\xdb\Util; +use \ip2region\xdb\Searcher; + +// 1, 使用上述的 $version 和 $dbFile 创建 Searcher 对象 try { - $searcher = XdbSearcher::newWithFileOnly($dbFile); + $searcher = Searcher::newWithFileOnly($version, $dbFile); } catch (Exception $e) { - printf("failed to create searcher with '%s': %s\n", $dbFile, $e); + printf("failed to create searcher with '%s': %s\n", $dbFile, $e->getMessage()); return; } -$ip = '1.2.3.4'; -$sTime = XdbSearcher::now(); -$region = $searcher->search($ip); -if ($region === null) { - // something is wrong - printf("failed search(%s)\n", $ip); - return; +// 2, 查询,IPv4 或者 IPv6 的地址都支持 +try { + $ip = '1.2.3.4'; + // $ip = "2001:4:112:ffff:ffff:ffff:ffff:ffff"; // IPv6 + $sTime = Util::now(); + $region = $searcher->search($ip); + $costMs = Util::now() - $sTime; + printf("{region: %s, took: %.5f ms}\n", $region, $costMs); +} catch (Exception $e) { + printf("failed to search(%s): %s", $ip, $e->getMessage()); } -printf("{region: %s, took: %.5f ms}\n", $region, XdbSearcher::now() - $sTime); +// 3,关闭资源 +$searcher->close(); // 备注:并发使用,每个线程或者协程需要创建一个独立的 searcher 对象。 ``` @@ -34,62 +61,84 @@ printf("{region: %s, took: %.5f ms}\n", $region, XdbSearcher::now() - $sTime); 如果你的 php 母环境支持,可以预先加载 vectorIndex 缓存,然后做成全局变量,每次创建 Searcher 的时候使用全局的 vectorIndex,可以减少一次固定的 IO 操作从而加速查询,减少 io 压力。 ```php -// 1、从 dbPath 加载 VectorIndex 缓存,把下述的 vIndex 变量缓存到内存里面。 -$vIndex = XdbSearcher::loadVectorIndexFromFile($dbPath); +// require or autoload the xdb\Searcher +require 'xdb\Searcher.php'; +use \ip2region\xdb\Util; +use \ip2region\xdb\Searcher; + + +// 1、从 $dbFile 加载 VectorIndex 缓存,把下述的 vIndex 变量缓存到内存里面。 +$vIndex = Util::loadVectorIndexFromFile($dbFile); if ($vIndex === null) { - printf("failed to load vector index from '%s'\n", $dbPath); + printf("failed to load vector index from '%s'\n", $dbFile); return; } // 2、使用全局的 vIndex 创建带 VectorIndex 缓存的查询对象。 try { - $searcher = XdbSearcher::newWithVectorIndex($dbFile, $vIndex); + $searcher = Searcher::newWithVectorIndex($version, $dbFile, $vIndex); } catch (Exception $e) { - printf("failed to create vectorIndex cached searcher with '%s': %s\n", $dbFile, $e); + printf("failed to create vectorIndex searcher with '%s': %s\n", $dbFile, $e->getMessage()); return; } -// 3、查询 -$sTime = XdbSearcher::now(); -$region = $searcher->search('1.2.3.4'); -if ($region === null) { - printf("failed search(1.2.3.4)\n"); - return; +// 3、查询,IPv4 或者 IPv6 都支持 +try { + $ip = '1.2.3.4'; + // $ip = "2001:4:112:ffff:ffff:ffff:ffff:ffff"; // IPv6 + $sTime = Util::now(); + $region = $searcher->search($ip); + $costMs = Util::now() - $sTime; + printf("{region: %s, took: %.5f ms}\n", $region, $costMs); +} catch (Exception $e) { + printf("failed to search(%s): %s", $ip, $e->getMessage()); } -printf("{region: %s, took: %.5f ms}\n", $region, XdbSearcher::now() - $sTime); +// 4, 关闭资源 +$searcher->close(); -// 备注:并发使用,每个线程或者协程需要创建一个独立的 searcher 对象,但是都共享统一的只读 vectorIndex。 +// 备注:并发使用,每个线程或者协程需要创建一个独立的 searcher 对象,但是都共享统一的只读全局 vectorIndex。。 ``` ### 缓存整个 `xdb` 数据 如果你的 PHP 母环境支持,可以预先加载整个 `xdb` 的数据到内存,这样可以实现完全基于内存的查询,类似之前的 memory search 查询。 ```php -// 1、从 dbPath 加载整个 xdb 到内存。 -$cBuff = XdbSearcher::loadContentFromFile($dbPath); +// require or autoload the xdb\Searcher +require 'xdb\Searcher.php'; +use \ip2region\xdb\Util; +use \ip2region\xdb\Searcher; + +// 1、从 $dbFile 加载整个 xdb 到内存。 +$cBuff = Util::loadContentFromFile($dbFile); if ($cBuff === null) { - printf("failed to load content buffer from '%s'\n", $dbPath); + printf("failed to load content buffer from '%s'\n", $dbFile); return; } // 2、使用全局的 cBuff 创建带完全基于内存的查询对象。 try { - $searcher = XdbSearcher::newWithBuffer($cBuff); + $searcher = Searcher::newWithBuffer($version, $cBuff); } catch (Exception $e) { - printf("failed to create buffer cached searcher: %s\n", $dbFile, $e); + printf("failed to create buffer cached searcher: %s\n", $dbFile, $e->getMessage()); return; } -// 3、查询 -$sTime = XdbSearcher::now(); -$region = $searcher->search('1.2.3.4'); -if ($region === null) { - printf("failed search(1.2.3.4)\n"); - return; +// 3、查询,IPv4 或者 IPv6 都支持 +try { + $ip = '1.2.3.4'; + // $ip = "2001:4:112:ffff:ffff:ffff:ffff:ffff"; // IPv6 + $sTime = Util::now(); + $region = $searcher->search($ip); + $costMs = Util::now() - $sTime; + printf("{region: %s, took: %.5f ms}\n", $region, $costMs); +} catch (Exception $e) { + printf("failed to search(%s): %s", $ip, $e->getMessage()); } -printf("{region: %s, took: %.5f ms}\n", $region, XdbSearcher::now() - $sTime); +// 4,关闭资源 +// 该 searcher 对象可以安全的用于并发,等整个服务都关闭的时候再关闭 searcher +// $searcher->close(); // 备注:并发使用,用整个 xdb 缓存创建的 searcher 对象可以安全用于并发。 ``` @@ -98,21 +147,33 @@ printf("{region: %s, took: %.5f ms}\n", $region, XdbSearcher::now() - $sTime); 通过 `search_test.php` 脚本来进行查询测试: ```bash -➜ php git:(v2.0_xdb) ✗ php ./search_test.php -php ./search_test.php [command options] -options: +➜ php git:(fr_php_ipv6) ✗ php search_test.php +php search_test.php [command options] +options: --db string ip2region binary xdb file path --cache-policy string cache policy: file/vectorIndex/content ``` -例如:使用默认的 data/ip2region.xdb 进行查询测试: +例如:使用默认的 data/ip2region_v4.xdb 进行 IPv4 的查询测试: ```bash -➜ php git:(v2.0_xdb) ✗ php ./search_test.php --db=../../data/ip2region.xdb --cache-policy=vectorIndex -ip2region xdb searcher test program, cachePolicy: vectorIndex +➜ php git:(fr_php_ipv6) ✗ php search_test.php --db=../../data/ip2region_v4.xdb +ip2region xdb searcher test program +source xdb file: ../../data/ip2region_v4.xdb (IPv4, vectorIndex) type 'quit' to exit -ip2region>> 1.2.3.4 -{region: 美国|0|华盛顿|0|谷歌, ioCount: 7, took: 0.04492 ms} -ip2region>> +ip2region>> 120.229.45.2 +{region: 中国|广东省|深圳市|移动, ioCount: 3, took: 0.02783 ms} +``` + +例如:使用默认的 data/ip2region_v6.xdb 进行 IPv6 的查询测试: +```bash +➜ php git:(fr_php_ipv6) ✗ php search_test.php --db=../../data/ip2region_v6.xdb +ip2region xdb searcher test program +source xdb file: ../../data/ip2region_v6.xdb (IPv6, vectorIndex) +type 'quit' to exit +ip2region>> :: +{region: |||, ioCount: 2, took: 0.06982 ms} +ip2region>> 2604:bc80:8001:11a4:ffff:ffff:ffff:ffff +{region: 中国|广东省|深圳市|数据中心, ioCount: 13, took: 0.19409 ms} ``` 输入 ip 即可进行查询测试。也可以分别设置 `cache-policy` 为 file/vectorIndex/content 来测试三种不同缓存实现的效率。 @@ -121,18 +182,22 @@ ip2region>> 通过 `bench_test.php` 脚本来进行自动 bench 测试,一方面确保 `xdb` 文件没有错误,另一方面通过大量的查询测试平均查询性能: ```bash -➜ php git:(v2.0_xdb) ✗ php ./bench_test.php -php ./bench_test.php [command options] -options: +➜ php git:(fr_php_ipv6) ✗ php bench_test.php +php bench_test.php [command options] +options: --db string ip2region binary xdb file path --src string source ip text file path --cache-policy string cache policy: file/vectorIndex/content ``` -例如:通过默认的 data/ip2region.xdb 和 data/ip.merge.txt 来进行 bench 测试: +例如:通过默认的 data/ip2region_v4.xdb 和 data/ipv4_source.txt 文件进行 IPv4 的 bench 测试: ```bash -➜ php git:(v2.0_xdb) ✗ php ./bench_test.php --db=../../data/ip2region.xdb --src=../../data/ip.merge.txt --cache-policy=vectorIndex -Bench finished, {cachePolicy: vectorIndex, total: 3417955, took: 15s, cost: 0.005 ms/op} +php bench_test.php --db=../../data/ip2region_v4.xdb --src=../../data/ipv4_source.txt +``` + +例如:通过默认的 data/ip2region_v6.xdb 和 data/ipv6_source.txt 文件进行 IPv6 的 bench 测试: +```bash +php bench_test.php --db=../../data/ip2region_v6.xdb --src=../../data/ipv6_source.txt ``` 可以通过设置 `cache-policy` 参数来分别测试 file/vectorIndex/content 三种不同的缓存实现的的性能。 diff --git a/binding/php/batch_test.php b/binding/php/batch_test.php index 14ecd37..85e61bc 100644 --- a/binding/php/batch_test.php +++ b/binding/php/batch_test.php @@ -6,7 +6,11 @@ // @Author Lion // @Date 2022/06/22 -require dirname(__FILE__) . '/XdbSearcher.class.php'; +require dirname(__FILE__) . '/xdb/Searcher.class.php'; + +use \ip2region\xdb\Util; +use \ip2region\xdb\{IPv4, IPv6}; +use \ip2region\xdb\Searcher; function printHelp($argv) { printf("php %s [command options]\n", $argv[0]); @@ -60,39 +64,60 @@ if (strlen($dbFile) < 1 || strlen($srcFile) < 1) { } // printf("debug: dbFile: %s, cachePolicy: %s\n", $dbFile, $cachePolicy); +$handle = fopen($dbFile, 'r'); +if ($handle === false) { + printf("failed to open the xdb file `{$dbFile}`\n"); + return; +} + +// load header +$header = Util::loadHeader($handle); +if ($header == null) { + printf("failed to load the header\n"); + return; +} + +// get the version number from the xdb header +try { + $version = Util::versionFromHeader($header); +} catch (Exception $e) { + printf("failed to detect version from header: {$e->getMessage()}\n"); + return; +} + // create the xdb searcher by the cache-policy switch ( $cachePolicy ) { case 'file': try { - $searcher = XdbSearcher::newWithFileOnly($dbFile); + $searcher = Searcher::newWithFileOnly($version, $dbFile); } catch (Exception $e) { printf("failed to create searcher with '%s': %s\n", $dbFile, $e); return; } break; case 'vectorIndex': - $vIndex = XdbSearcher::loadVectorIndexFromFile($dbFile); + $vIndex = Util::loadVectorIndex($handle); if ($vIndex == null) { printf("failed to load vector index from '%s'\n", $dbFile); return; } try { - $searcher = XdbSearcher::newWithVectorIndex($dbFile, $vIndex); + $searcher = Searcher::newWithVectorIndex($version, $dbFile, $vIndex); } catch (Exception $e) { printf("failed to create vector index cached searcher with '%s': %s\n", $dbFile, $e); return; } break; case 'content': - $cBuff = XdbSearcher::loadContentFromFile($dbFile); + $cBuff = Util::loadContent($handle); if ($cBuff == null) { printf("failed to load xdb content from '%s'\n", $dbFile); return; } try { - $searcher = XdbSearcher::newWithBuffer($cBuff); + $searcher = Searcher::newWithBuffer($version, $cBuff); } catch (Exception $e) { printf("failed to create content cached searcher: %s", $e); return; @@ -119,21 +144,18 @@ while (!feof($handle)) { continue; } - $ip = XdbSearcher::ip2long($line); - if ($ip === null) { - printf("invalid ip `%s`\n", $line); - return; + try { + $ipBytes = Util::parseIP($line); + } catch (Exception $e) { + printf("failed to parse ip `%s`: %s\n", $line, $e->getMessage()); + continue; } $count++; - $region = $searcher->search($ip); + $region = $searcher->searchByBytes($ipBytes); $ss = explode('|', $region); - if (strlen($ss[3]) > 1) { - $qx_count++; - } echo $line, ",", str_replace('|', ',', $region), "\n"; } fclose($handle); -echo "qx_count: {$qx_count}"; echo "Done, with {$count} IPs\n"; diff --git a/binding/php/bench_test.php b/binding/php/bench_test.php index 6ea7d4d..75fa111 100644 --- a/binding/php/bench_test.php +++ b/binding/php/bench_test.php @@ -64,7 +64,26 @@ if (strlen($dbFile) < 1 || strlen($srcFile) < 1) { } // printf("debug: dbFile: %s, cachePolicy: %s\n", $dbFile, $cachePolicy); -$version = IPv4::default(); +$handle = fopen($dbFile, 'r'); +if ($handle === false) { + printf("failed to open the xdb file `{$dbFile}`\n"); + return; +} + +// load header +$header = Util::loadHeader($handle); +if ($header == null) { + printf("failed to load the header\n"); + return; +} + +// get the version number from the xdb header +try { + $version = Util::versionFromHeader($header); +} catch (Exception $e) { + printf("failed to detect version from header: {$e->getMessage()}\n"); + return; +} // create the xdb searcher by the cache-policy switch ( $cachePolicy ) { @@ -77,7 +96,7 @@ switch ( $cachePolicy ) { } break; case 'vectorIndex': - $vIndex = Util::loadVectorIndexFromFile($dbFile); + $vIndex = Util::loadVectorIndex($handle); if ($vIndex == null) { printf("failed to load vector index from '%s'\n", $dbFile); return; @@ -91,7 +110,7 @@ switch ( $cachePolicy ) { } break; case 'content': - $cBuff = Util::loadContentFromFile($dbFile); + $cBuff = Util::loadContent($handle); if ($cBuff == null) { printf("failed to load xdb content from '%s'\n", $dbFile); return; @@ -126,6 +145,11 @@ while (!feof($handle)) { continue; } + // ignore the comment + if ($line[0] == '#') { + continue; + } + $ps = explode('|', $line, 3); if (count($ps) != 3) { printf("invalid ip segment line `${line}`\n"); diff --git a/binding/php/search_test.php b/binding/php/search_test.php index cb62d60..6874af8 100644 --- a/binding/php/search_test.php +++ b/binding/php/search_test.php @@ -60,7 +60,26 @@ if (strlen($dbFile) < 1) { } // printf("debug: dbFile: %s, cachePolicy: %s\n", $dbFile, $cachePolicy); -$version = IPv4::default(); +$handle = fopen($dbFile, 'r'); +if ($handle === false) { + printf("failed to open the xdb file `{$dbFile}`\n"); + return; +} + +// load header +$header = Util::loadHeader($handle); +if ($header == null) { + printf("failed to load the header\n"); + return; +} + +// get the version number from the xdb header +try { + $version = Util::versionFromHeader($header); +} catch (Exception $e) { + printf("failed to detect version from header: {$e->getMessage()}\n"); + return; +} // create the xdb searcher by the cache-policy switch ( $cachePolicy ) { @@ -73,7 +92,7 @@ case 'file': } break; case 'vectorIndex': - $vIndex = Util::loadVectorIndexFromFile($dbFile); + $vIndex = Util::loadVectorIndex($handle); if ($vIndex == null) { printf("failed to load vector index from '%s'\n", $dbFile); return; @@ -87,7 +106,7 @@ case 'vectorIndex': } break; case 'content': - $cBuff = Util::loadContentFromFile($dbFile); + $cBuff = Util::loadContent($handle); if ($cBuff == null) { printf("failed to load xdb content from '%s'\n", $dbFile); return; @@ -105,7 +124,11 @@ default: return; } -printf("ip2region xdb searcher test program, cachePolicy: ${cachePolicy}\ntype 'quit' to exit\n"); +printf(<<name}, ${cachePolicy}) +type 'quit' to exit\n +EOF); while ( true ) { echo "ip2region>> "; $line = trim(fgets(STDIN)); diff --git a/binding/php/xdb/Searcher.class.php b/binding/php/xdb/Searcher.class.php index fcc7033..24c7ac5 100644 --- a/binding/php/xdb/Searcher.class.php +++ b/binding/php/xdb/Searcher.class.php @@ -42,7 +42,9 @@ class Util { // compare two ip bytes (packed string return by parsedIP) // returns: -1 if ip1 < ip2, 0 if ip1 == ip2 or 1 if ip1 > ip2 public static function ipSubCompare($ip1, $buff, $offset) { - $r = substr_compare($ip1, $buff, $offset, strlen($ip1)); + // $r = substr_compare($ip1, $buff, $offset, strlen($ip1)); + // @Note: substr_compare is not working, use the substr + strcmp instead + $r = strcmp($ip1, substr($buff, $offset, strlen($ip1))); if ($r < 0) { return -1; } else if ($r > 0) { @@ -64,6 +66,48 @@ class Util { } } + // version parse + public static function versionFromName($ver_name) { + $name = strtoupper($ver_name); + if ($name == "V4" || $name == "IPv4") { + return IPv4::default(); + } else if ($name == "V6" || $name == "IPv6") { + return IPv6::default(); + } else { + throw new Exception("invalid verstion name `{$ver_name}`"); + } + } + + // version parse from header + public static function versionFromHeader($header) { + // Old structure 2.0 with IPv4 supports ONLY + if ($header['version'] == Structure_20) { + return IPv4::default(); + } + + // structure 3.0 after IPv6 supporting + if ($header['version'] != Structure_30) { + throw new Exception("invalid xdb structure version `{$header['version']}`"); + } + + if ($header['ipVersion'] == IPv4VersionNo) { + return IPv4::default(); + } else if ($header['ipVersion'] == IPv6VersionNo) { + return IPv6::default(); + } else { + throw new Exception("invalid ip version number `{$header['ipVersion']}`"); + } + } + + // binary string chars implode with space + public static function bytesToString($buff, $offset, $length) { + $sb = []; + for ($i = 0; $i < $length; $i++) { + $sb[] = ord($buff[$offset+$i]) & 0xFF; + } + return '['.implode(' ', $sb).']'; + } + // decode a 4bytes long with Little endian byte order from a byte buffer public static function le_getUint32($b, $idx) { $val = (ord($b[$idx])) | (ord($b[$idx+1]) << 8) @@ -203,10 +247,14 @@ class IPv4 { public $name; public $bytes; public $segmentIndexSize; - + + private static $C = null; public static function default() { - // 14 = 4 + 4 + 2 + 4 - return new self(IPv4VersionNo, 'IPv4', 4, 14); + if (self::$C == null) { + // 14 = 4 + 4 + 2 + 4 + self::$C = new self(IPv4VersionNo, 'IPv4', 4, 14); + } + return self::$C; } public function __construct($id, $name, $bytes, $segmentIndexSize) { @@ -220,24 +268,23 @@ class IPv4 { public function ipSubCompare($ip1, $buff, $offset) { // ip1: Little endian byte order encoded long from searcher. // ip2: Little endian byte order read from xdb index. - // @Note: to compatible with the old Litten endian index encode implementation. - $ip2 = ( - (ord($buff[$offset ]) << 24) | - (ord($buff[$offset+1]) << 16) | - (ord($buff[$offset+2]) << 8) | ord($buff[$offset+3]) - ); - - $r = $ip1 - $ip2; - if ($r > 0) { - return 1; - } else if ($r < 0) { - return -1; - } else { - return 0; + $len = strlen($ip1); + $eIdx = $offset + $len; + for ($i = 0, $j = $eIdx - 1; $i < $len; $i++, $j--) { + $i1 = ord($ip1[$i]) & 0xFF; + $i2 = ord($buff[$j]) & 0xFF; + // printf("i:%d, j:%d, i1:%d, i2:%d\n", $i, $j, $i1, $i2); + if ($i1 > $i2) { + return 1; + } else if ($i1 < $i2) { + return -1; + } } + + return 0; } - public function toString() { + public function __toString() { return sprintf( "{id:%d, name:%s, bytes:%d, segmentIndexSize:%d}", $this->id, $this->name, $this->bytes, $this->segmentIndexSize @@ -251,9 +298,14 @@ class IPv6 { public $bytes; public $segmentIndexSize; + private static $C = null; public static function default() { - // 38 = 16 + 16 + 2 + 4 - return new self(IPv6VersionNo, 'IPv6', 16, 38); + if (self::$C == null) { + // 38 = 16 + 16 + 2 + 4 + self::$C = new self(IPv6VersionNo, 'IPv6', 16, 38); + } + + return self::$C; } public function __construct($id, $name, $bytes, $segmentIndexSize) { @@ -264,10 +316,11 @@ class IPv6 { } public function ipSubCompare($ip, $buff, $offset) { + // return Util::ipCompare($ip, substr($buff, $offset, strlen($ip))); return Util::ipSubCompare($ip, $buff, $offset); } - public function toString() { + public function __toString() { return sprintf( "{id:%d, name:%s, bytes:%d, segmentIndexSize:%d}", $this->id, $this->name, $this->bytes, $this->segmentIndexSize @@ -281,8 +334,7 @@ class Searcher { private $version; // xdb file handle - private $handle = null; - + private $handle = null; private $ioCount = 0; // vector index in binary string. @@ -406,15 +458,6 @@ class Searcher { // printf("sPtr: %d, ePtr: %d\n", $sPtr, $ePtr); [$bytes, $dBytes] = [strlen($ipBytes), strlen($ipBytes) << 1]; - if ($bytes == 4) { - // encode the IPv4 bytes to an long with Litten endian byte order - // to avoid the repeated calcs in the binary search loop. - $ipBytes = ( - (ord($ipBytes[3]) << 24) | - (ord($ipBytes[2]) << 24) | - (ord($ipBytes[1]) << 24) | (ord($ipBytes[0])) - ); - } // binary search the segment index to get the region info $idxSize = $this->version->segmentIndexSize; @@ -430,6 +473,11 @@ class Searcher { throw new Exception("failed to read segment index with ptr={$p}"); } + // printf("l=%d, h=%d, sip=%s, eip=%s\n", + // $l, $h, + // Util::ipToString(strrev(substr($buff, 0, 4))), + // Util::ipToString(strrev(substr($buff, 4, 4))) + // ); if ($this->version->ipSubCompare($ipBytes, $buff, 0) < 0) { $h = $m - 1; } else if ($this->version->ipSubCompare($ipBytes, $buff, $bytes) > 0) { diff --git a/binding/php/xdb/util_test.php b/binding/php/xdb/util_test.php index d5baf9c..1103381 100644 --- a/binding/php/xdb/util_test.php +++ b/binding/php/xdb/util_test.php @@ -6,7 +6,7 @@ // @Author Lion // @Date 2022/06/22 -require dirname(__FILE__) . '/Searcher.class.php'; +require 'Searcher.class.php'; use \ip2region\xdb\Util; use \ip2region\xdb\Searcher; use \ip2region\xdb\IPv4; @@ -20,9 +20,11 @@ if($argc < 2) { $func_name = trim($argv[1]); } +$basePath = dirname(dirname(dirname(dirname(__FILE__)))); function testLoadHeader() { - $header = Util::loadHeaderFromFile('../../data/ip2region_v4.xdb'); + global $basePath; + $header = Util::loadHeaderFromFile("{$basePath}/data/ip2region_v4.xdb"); if ($header == null) { printf("failed to load header from file\n"); return; @@ -33,7 +35,8 @@ function testLoadHeader() { } function testLoadVectorIndex() { - $vIndex = Util::loadVectorIndexFromFile('../../data/ip2region_v4.xdb'); + global $basePath; + $vIndex = Util::loadVectorIndexFromFile("{$basePath}/data/ip2region_v4.xdb"); if ($vIndex == null) { printf("failed to load vector index from file\n"); return; @@ -43,7 +46,8 @@ function testLoadVectorIndex() { } function testLoadContent() { - $cBuff = Util::loadContentFromFile('../../data/ip2region_v4.xdb'); + global $basePath; + $cBuff = Util::loadContentFromFile("{$basePath}/data/ip2region_v4.xdb"); if ($cBuff == null) { printf("failed to load content from file\n"); return; @@ -87,6 +91,8 @@ function testIPCompare() { ["1.0.0.0", "1.0.0.1"], ["192.168.1.101", "192.168.1.90"], ["219.133.111.87", "114.114.114.114"], + ["1.0.4.0", "1.0.1.0"], + ["1.0.4.0", "1.0.3.255"], ["2000::", "2000:ffff:ffff:ffff:ffff:ffff:ffff:ffff"], ["2001:4:112::", "2001:4:112:ffff:ffff:ffff:ffff:ffff"], ["ffff::", "2001:4:ffff:ffff:ffff:ffff:ffff:ffff"] @@ -102,8 +108,8 @@ function testIPCompare() { function testAttributes() { printf("IPv4VersioNo: %d\n", \ip2region\xdb\IPv4VersionNo); printf("IPv6VersioNo: %d\n", \ip2region\xdb\IPv6VersionNo); - printf("IPv4 Object: %s\n", IPv4::default()->toString()); - printf("IPv6 Object: %s\n", IPv6::default()->toString()); + printf("IPv4 Object: %s\n", IPv4::default()); + printf("IPv6 Object: %s\n", IPv6::default()); }