- 论坛徽章:
- 0
|
本帖最后由 hoojar 于 2010-04-29 16:58 编辑
最新IP地址库与匹配高效算法(PHP版)
本人写了个小程序,专门用来定位IP所对应的真实区域地址,在PHP当中一秒钟匹配4000次以上,如有需要可以与我联系QQ:37894354 Email:hoojar@163.com
/**
* 根据IP获取对应的数据(高效)
*
* @param string $ip IP地址
* @param string $filename IP库路径
* @return array 未找到返回false,找到返回array(sIp=>开始IP数字 eIp=>结束IP数字 pId=>省份编号 cId=>城市编号)
*/
function get_ip_address($ip, $filename = './ip-db.dat')
{
/**
* IP转数字并判断是否为合法IP地址
*/
$ip = ip2long($ip);//将IP转换成数字
if ($ip === false){return false;}//ip转数字无效返回false
$ip = sprintf('%u', $ip);//将转换成数字的IP再次转换成无符号的长整形
/**
* 打开IP数据库文件并静态文件指针与下标数
*/
static $fp = null, $count = null;
if ($fp === null)
{
$fp = @fopen($filename, 'rb');
if ($fp === false){exit("{$filename} file not exists .");}
$res = unpack('Nhig', fread($fp, 4));//高位
$count = $res['hig']; unset($res);
}
/**
* 初始化二分查找参照数据
*/
$seek = 12;//一条记录占几个字节
$top = $middle = 0;//低位//下标
$bottom = $count;//底(记录总数)
/**
* 二分查找对应的数据
*/
while ($top <= $bottom)
{
$middle = floor(($top + $bottom) / 2);
fseek($fp, 4 + $middle * $seek);
$data = unpack('NsIp/NeIp/SpId/ScId', fread($fp, $seek));
$data['sIp'] = sprintf('%u', $data['sIp']);
$data['eIp'] = sprintf('%u', $data['eIp']);
if ($ip < $data['sIp'])
{
$bottom = $middle - 1;
}
elseif($ip > $data['eIp'])
{
$top = $middle + 1;
}
else
{
return $data;//找到了
}
}
return false;//未找到
}
出售最新IP地址库与匹配高效算法(MYSQL函数FUNCTION版)
DELIMITER $$
DROP FUNCTION IF EXISTS get_ip_address$$
CREATE FUNCTION get_ip_address($IP VARCHAR(20), $detail TINYINT(1)) RETURNS varchar(250) CHARSET utf8 COMMENT '根据IP获取对应的地址'
BEGIN
DECLARE $intip INT UNSIGNED DEFAULT INET_ATON($IP); # 将IP转换成数字
DECLARE $gk INT UNSIGNED DEFAULT LEFT($intip, 4); -- 截取IP数字前4位作为查询分组标准
DECLARE $address VARCHAR(250) DEFAULT ''; -- 返回的数据
CASE $detail
WHEN 0 THEN -- 获取自动编号、开始IP数字、结束IP数字、省份编号、城市编号
SELECT CONCAT('id=', AID, '&s=', StartIP, '&e=', EndIP, '&p=', ProvinceID, '&c=', CityID) INTO $address
FROM mem_ip WHERE GroupKey = $gk AND ($intip >= StartIP AND $intip <= EndIP);
WHEN 1 THEN # 获取详细地址
SELECT CONCAT(S.AddrBig, S.AddrSmall) INTO $address FROM mem_ip M INNER JOIN sys_ip S
ON S.AID = M.AID WHERE M.GroupKey = $gk AND ($intip >= M.StartIP AND $intip <= M.EndIP);
WHEN 2 THEN /*获取自动编号、开始IP数字、结束IP数字、省份编号、城市编号、详细地址*/
SELECT CONCAT('id=', M.AID, '&s=', M.StartIP, '&e=', M.EndIP, '&p=', M.ProvinceID, '&c=', M.CityID, '&a=', S.AddrBig, S.AddrSmall)
INTO $address FROM mem_ip M INNER JOIN sys_ip S ON S.AID = M.AID WHERE M.GroupKey = $gk AND ($intip >= M.StartIP AND $intip <= M.EndIP);
ELSE /*获取自动编号、开始IP数字、结束IP数字、省份编号、城市编号、详细地址、IP地址*/
SELECT CONCAT('id=', M.AID, '&s=', M.StartIP, '&e=', M.EndIP, '&p=', M.ProvinceID, '&c=', M.CityID, '&a=', S.AddrBig, S.AddrSmall, '&ip=', $IP)
INTO $address FROM mem_ip M INNER JOIN sys_ip S ON S.AID = M.AID WHERE M.GroupKey = $gk AND ($intip >= M.StartIP AND $intip <= M.EndIP);
END CASE;
RETURN $address;
END$$
DELIMITER ; |
|