假如业务流程中需要验证用户的ip地址,随着数据库中保存的授权ip不停的增加,如何快速便捷的查询到对应的ip显得至关紧要,本文利用ip转为对应的整数,然后利用二分法查询,实现业务需求(好记性不如烂笔头)
author:he
qq:760863706
date:2018-9-28
具体代码示例
<?php
//待验证ip
$ip='58.33.179.25';
//业务中数据库保存类似的数据结构,业务目标是查找ip是否在这些城市中
$example = ['beijing'=>'47.154.0.0-47.154.255.255@58.31.104.0-58.31.104.255@58.117.128.0-58.117.129.255',
'shanghai'=>'58.32.20.0-58.32.39.255@58.33.33.0-58.33.39.255@58.33.160.0-58.33.179.255',
'guangzhou'=>'219.137.148.0-219.137.150.255@219.136.38.0-219.136.38.255@219.136.0.0-219.136.6.255'];
$arr = [];
foreach ($example as $k => $v) {
$arr1 = explode('@', $v);
foreach ($arr1 as $k1 => $v1) {
$arr2 = explode('-', $v1);
//ip地址转整数
$start = sprintf("%u",ip2long($arr2[0]));
$end = sprintf("%u",ip2long($arr2[1]));
//ip及对应整数,形成新的数组
$arr[$start] = ['name'=>$k,'from'=>$arr2[0],'to'=>$arr2[1],'start'=>$start,'end'=>$end];
}
}
//二维数组以键名升序排列
ksort($arr);
$ipArr = [];
foreach ($arr as $k => $v) {
$ipArr[] = $v;
}
//二分法查找匹配ip
$low = 0;
$top = count($ipArr)-1;
$isFind = 0;
$target = sprintf("%u",ip2long($ip));
while ($low <= $top) {
//取中间值
$mid = intval(($top+$low)/2);
if ($target >= $ipArr[$mid]['start'] && $target <= $ipArr[$mid]['end']) {
//有效范围内
$isFind = 1;
break;
}elseif ($target > $ipArr[$mid]['start']) {
//右半部分
$low = $mid+1;
}else{
//左半部分
$top = $mid-1;
}
}
if ($isFind) {
//匹配到ip,打印结果
var_dump($ipArr[$mid]);
}