说实话,除非你的CIDR范围很大并且在同一进程中检查了许多IP,否则你可能不会看到太多性能提升。然而,如果这是你要考虑的情况,那么你可以尝试通过预处理你的范围和IP来挤出一些性能,(执行一次ip2long()调用并将分离的掩码/子网存储以供比较)。
例如,我假设这是你目前的做法:
<?php
$ranges = array(
"192.168.0.1/32",
"192.168.0.1/26",
"192.168.0.1/24",
"192.168.0.1/16",
"127.0.0.1/24",
"10.0.0.1/32",
"10.0.0.1/24"
);
$start = microtime(true);
find_cidr("10.0.0.42", $ranges);
find_cidr("192.168.0.12", $ranges);
find_cidr("10.0.0.1", $ranges);
$end = microtime(true);
echo "Ran 3 find routines in " . ($end - $start) . " seconds!\n";
function find_cidr($ip, $ranges)
{
foreach($ranges as $range)
{
if(cidr_match($ip, $range))
{
echo "IP {$ip} found in range {$range}!\n";
break;
}
}
}
function cidr_match($ip, $range){
list ($subnet, $bits) = explode('/', $range);
$ip = ip2long($ip);
$subnet = ip2long($subnet);
$mask = -1 << (32 - $bits);
$subnet &= $mask;
return ($ip & $mask) == $subnet;
}
在我的电脑上,检查三个IP地址与少量范围匹配大约需要0.0005-0.001秒的时间。
如果我编写了一些预处理范围的代码:
<?php
$ranges = array(
"192.168.0.1/32",
"192.168.0.1/26",
"192.168.0.1/24",
"192.168.0.1/16",
"127.0.0.1/24",
"10.0.0.1/32",
"10.0.0.1/24"
);
$matcher = new BulkCIDRMatch($ranges);
$start = microtime(true);
$matcher->FindCIDR("10.0.0.42");
$matcher->FindCIDR("192.168.0.12");
$matcher->FindCIDR("10.0.0.1");
$end = microtime(true);
echo "Ran 3 find routines in " . ($end - $start) . " seconds!\n";
class BulkCIDRMatch
{
private $_preparedRanges = array();
public function __construct($ranges)
{
foreach($ranges as $range)
{
list ($subnet, $bits) = explode('/', $range);
$subnet = ip2long($subnet);
$mask = -1 << (32 - $bits);
$subnet &= $mask;
$this->_preparedRanges[$range] = array($mask,$subnet);
}
}
public function FindCIDR($ip)
{
$result = $this->_FindCIDR(ip2long($ip));
if($result !== null)
{
echo "IP {$ip} found in range {$result}!\n";
}
return $result;
}
private function _FindCIDR($iplong)
{
foreach($this->_preparedRanges as $range => $details)
{
if(($iplong & $details[0]) == $details[1])
{
return $range;
}
}
return null;
}
}
然后我看到快速的CHECKING,但是在类初始化时有稍微更多的开销,因为它会处理和存储所有的范围。所以如果我只用3个IP地址对一些范围进行整体运行时间测试,那么“优化”的方式实际上会慢一点。但是如果我使用1,000个IP地址对10,000个CIDR进行测试,“优化”的方式将比原始方式有更明显的改进(代价是使用额外的内存来存储预处理的范围数据)。
所以这完全取决于数量和你想要做什么。
话虽如此,如果你担心0.001秒的性能太慢,那么PHP可能不是用于检查的正确语言。或者至少你可能需要考虑编写一个自定义扩展,这样更多的处理就可以在C中完成。
编辑:为了回答关于在任何形式转换之前找到“可能”的范围的原始问题,这可能不是一个非常可靠的尝试。范围可以跨越其初始八位字节,因此如果您开始比较这些值(例如,“我正在查看192.168.1.0,因此我只会查看从192开始的范围”),您不仅会在每个条目上产生字符串比较的性能开销(这会减慢整体查找速度),而且您可能会错过一个有效的范围。