php查询ip所在地的方法


Posted in PHP onDecember 05, 2014

本文实例讲述了php查询ip所在地的方法。分享给大家供大家参考。

具体实现方法如下:

<?php 

/** 

*@ date         2010.12.21 

注:文件头 [第一条索引的偏移量 (4byte)] + [最后一条索引的偏移地址 (4byte)]     8字节 

记录区 [结束ip (4byte)] + [地区1] + [地区2]                                4字节+不定长 

索引区 [开始ip (4byte)] + [指向记录区的偏移地址 (3byte)]                   7字节 

*/ 

class iplocation{ 

var $fp; 

var $firstip;  //第一条ip索引的偏移地址 

var $lastip;   //最后一条ip索引的偏移地址 

var $totalip;  //总ip数 

/* 

|---------------------------------------------------------------------------- 

| 构造函数,初始化一些变量 

|---------------------------------------------------------------------------- 

| 

*/ 

function iplocation($datfile = "qqwry.dat"){ 

$this->fp=fopen($datfile,'rb')or die("qqwry.dat不存在,请去网上 <a href='https://3water.com/softs/10529.html'>下载纯真ip数据 库</a>, 'qqwry.dat' 放到当前目录下");   //二制方式打开 

$this->firstip = $this->get4b(); //第一条ip索引的绝对偏移地址 

$this->lastip = $this->get4b();  //最后一条ip索引的绝对偏移地址 

$this->totalip =($this->lastip - $this->firstip)/7 ; //ip总数 索引区是定长的7个字节,在此要除以7, 

register_shutdown_function(array($this,"closefp"));  //为了兼容php5以下版本,本类没有用析构函数,自动关闭ip库. 

} 

/* 

|---------------------------------------------------------------------------- 

| 关闭ip库 

|---------------------------------------------------------------------------- 

| 

*/ 

function closefp(){ 

fclose($this->fp); 

} 

/* 

|---------------------------------------------------------------------------- 

| 读取4个字节并将解压成long的长模式 

|---------------------------------------------------------------------------- 

| 

*/ 

function get4b(){ 

$str=unpack("v",fread($this->fp,4)); 

return $str[1]; 

} 

/* 

|---------------------------------------------------------------------------- 

| 读取重定向了的偏移地址 

|---------------------------------------------------------------------------- 

| 

*/ 

function getoffset(){ 

$str=unpack("v",fread($this->fp,3).chr(0)); 

return $str[1]; 

} 

/* 

|---------------------------------------------------------------------------- 

| 读取ip的详细地址信息 

|---------------------------------------------------------------------------- 

| 

*/ 

function getstr(){ 

$split=fread($this->fp,1); 

while (ord($split)!=0) { 

$str .=$split; 

$split=fread($this->fp,1); 

} 

return $str; 

} 

/* 

|---------------------------------------------------------------------------- 

| 将ip通过ip2long转成ipv4的互联网地址,再将他压缩成big-endian字节序 ,用来和索引区内的ip地址做比较 

|---------------------------------------------------------------------------- 

| 

*/ 

function iptoint($ip){ 

return pack("n",intval(ip2long($ip))); 

} 

/* 

|---------------------------------------------------------------------------- 

| 获取地址信息 

|---------------------------------------------------------------------------- 

| 

*/ 

function readaddress(){ 

$now_offset=ftell($this->fp); //得到当前的指针位址 

$flag=$this->getflag(); 

switch (ord($flag)){ 

case 0: 

$address=""; 

break; 

case 1: 

case 2: 

fseek($this->fp,$this->getoffset()); 

$address=$this->getstr(); 

break; 

default: 

fseek($this->fp,$now_offset); 

$address=$this->getstr(); 

break; 

} 

return $address; 

} 

/* 

|---------------------------------------------------------------------------- 

| 获取标志1或2   用来确定地址是否重定向了 

|---------------------------------------------------------------------------- 

| 

*/ 

function getflag(){ 

return fread($this->fp,1); 

} 

/* 

|---------------------------------------------------------------------------- 

| 用二分查找法在索引区内搜索ip 

|---------------------------------------------------------------------------- 

| 

*/ 

function searchip($ip){ 

$ip=gethostbyname($ip);     //将域名转成ip 

$ip_offset["ip"]=$ip; 

$ip=$this->iptoint($ip);    //将ip转换成长整型 

$firstip=0;                 //搜索的上边界 

$lastip=$this->totalip;     //搜索的下边界 

$ipoffset=$this->lastip;    //初始化为最后一条ip地址的偏移地址 

while ($firstip <= $lastip){ 

$i=floor(($firstip + $lastip) / 2);          //计算近似中间记录 floor函数记算给定浮点数小的最大整数,说白了就是四舍五也舍 

fseek($this->fp,$this->firstip + $i * 7);    //定位指针到中间记录 

$startip=strrev(fread($this->fp,4));         //读取当前索引区内的开始ip地址,并将其little-endian的字节序转换成big-endian的字节序 

if ($ip < $startip) { 

$lastip=$i - 1; 

} 

else { 

fseek($this->fp,$this->getoffset()); 

$endip=strrev(fread($this->fp,4)); 

if ($ip > $endip){ 

$firstip=$i + 1; 

} 

else { 

$ip_offset["offset"]=$this->firstip + $i * 7; 

break; 

} 

} 

} 

return $ip_offset; 

} 

/* 

|---------------------------------------------------------------------------- 

| 获取ip地址详细信息 

|---------------------------------------------------------------------------- 

| 

*/ 

function getaddress($ip){ 

$ip_offset=$this->searchip($ip);  //获取ip 在索引区内的绝对编移地址 

$ipoffset=$ip_offset["offset"]; 

$address["ip"]=$ip_offset["ip"]; 

fseek($this->fp,$ipoffset);      //定位到索引区 

$address["startip"]=long2ip($this->get4b()); //索引区内的开始ip 地址 

$address_offset=$this->getoffset();            //获取索引区内ip在ip记录区内的偏移地址 

fseek($this->fp,$address_offset);            //定位到记录区内 

$address["endip"]=long2ip($this->get4b());   //记录区内的结束ip 地址 

$flag=$this->getflag();                      //读取标志字节 

switch (ord($flag)) { 

case 1:  //地区1地区2都重定向 

$address_offset=$this->getoffset();   //读取重定向地址 

fseek($this->fp,$address_offset);     //定位指针到重定向的地址 

$flag=$this->getflag();               //读取标志字节 

switch (ord($flag)) { 

case 2:  //地区1又一次重定向, 

fseek($this->fp,$this->getoffset()); 

$address["area1"]=$this->getstr(); 

fseek($this->fp,$address_offset+4);      //跳4个字节 

$address["area2"]=$this->readaddress();  //地区2有可能重定向,有可能没有 

break; 

default: //地区1,地区2都没有重定向 

fseek($this->fp,$address_offset);        //定位指针到重定向的地址 

$address["area1"]=$this->getstr(); 

$address["area2"]=$this->readaddress(); 

break; 

} 

break; 

case 2: //地区1重定向 地区2没有重定向 

$address1_offset=$this->getoffset();   //读取重定向地址 

fseek($this->fp,$address1_offset);   

$address["area1"]=$this->getstr(); 

fseek($this->fp,$address_offset+8); 

$address["area2"]=$this->readaddress(); 

break; 

default: //地区1地区2都没有重定向 

fseek($this->fp,$address_offset+4); 

$address["area1"]=$this->getstr(); 

$address["area2"]=$this->readaddress(); 

break; 

} 

//*过滤一些无用数据 

if (strpos($address["area1"],"cz88.net")!=false){ 

$address["area1"]="未知"; 

} 

if (strpos($address["area2"],"cz88.net")!=false){ 

$address["area2"]=" "; 

} 

return $address; 

} 

} 

 

/*用法如下:*/ 

$ip=new iplocation("qqwry.dat"); 

$address=$ip->getaddress("61.129.51.27"); 

//$address=$ip->getaddress(3water.com); 

echo '<pre>'; 

print_r($address); 

?>

希望本文所述对大家的PHP程序设计有所帮助。

PHP 相关文章推荐
非常不错的MySQL优化的8条经验
Mar 24 PHP
php 代码优化的42条建议 推荐
Sep 25 PHP
《PHP编程最快明白》第七讲:php图片验证码与缩略图
Nov 01 PHP
php中使用parse_url()对网址进行解析的实现代码(parse_url详解)
Jan 03 PHP
PHP实现数字补零功能的2个函数介绍
May 12 PHP
ThinkPHP空模块和空操作详解
Jun 30 PHP
PHP 反射(Reflection)使用实例
May 12 PHP
php连接oracle数据库的核心步骤
May 26 PHP
php  PATH_SEPARATOR判断当前服务器系统类型实例
Oct 28 PHP
PHP 7.1中AES加解密方法mcrypt_module_open()的替换方案
Oct 17 PHP
PHP实现的ID混淆算法类与用法示例
Aug 10 PHP
实例化php类时传参的方法分析
Jun 05 PHP
smarty实现多级分类的方法
Dec 05 #PHP
Codeigniter框架实现获取分页数据和总条数的方法
Dec 05 #PHP
常见php数据文件缓存类汇总
Dec 05 #PHP
Thinkphp搜索时首页分页和搜索页保持条件分页的方法
Dec 05 #PHP
ThinkPHP模版引擎之变量输出详解
Dec 05 #PHP
ThinkPHP添加更新标签的方法
Dec 05 #PHP
彻底删除thinkphp3.1案例blog标签的方法
Dec 05 #PHP
You might like
PHP 转义使用详解
2013/07/15 PHP
ThinkPHP3.1查询语言详解
2014/06/19 PHP
PHP中if和or运行效率对比
2014/12/12 PHP
php准确计算复活节日期的方法
2015/04/18 PHP
php外部执行命令函数用法小结
2016/10/11 PHP
js批量设置样式的三种方法不推荐使用with
2013/02/25 Javascript
自己使用js/jquery写的一个定制对话框控件
2014/05/02 Javascript
jQuery设置和获取HTML、文本和值示例
2014/07/08 Javascript
Js为表单动态添加节点内容的方法
2015/02/10 Javascript
JS给Textarea文本框添加行号的方法
2015/08/20 Javascript
JavaScript操作URL的相关内容集锦
2015/10/29 Javascript
JavaScript实现图片滑动切换的代码示例分享
2016/03/06 Javascript
基于jquery实现轮播特效
2016/04/22 Javascript
解决vue2.x中数据渲染以及vuex缓存的问题
2017/07/13 Javascript
Vue Router的懒加载路径的解决方法
2018/06/21 Javascript
微信小程序开发之路由切换页面重定向问题
2018/09/18 Javascript
JavaScript学习笔记之基于定时器实现图片无缝滚动功能详解
2019/01/09 Javascript
nodejs分离html文件里面的js和css的方法
2019/04/09 NodeJs
借助云开发实现小程序短信验证码的发送
2020/01/06 Javascript
Ant-design-vue Table组件customRow属性的使用说明
2020/10/28 Javascript
python抓取文件夹的所有文件
2018/02/27 Python
对numpy和pandas中数组的合并和拆分详解
2018/04/11 Python
python中验证码连通域分割的方法详解
2018/06/04 Python
python实现输入数字的连续加减方法
2018/06/22 Python
python调用opencv实现猫脸检测功能
2019/01/15 Python
解决Python3.8用pip安装turtle-0.0.2出现错误问题
2020/02/11 Python
html5触摸事件判断滑动方向的实现
2018/06/05 HTML / CSS
html5各种页面切换效果和模态对话框用法总结
2014/12/15 HTML / CSS
美国汽配连锁巨头Pep Boys官网:轮胎更换、汽车维修服务和汽车零部件
2017/01/14 全球购物
教学器材管理制度
2014/01/26 职场文书
《莫泊桑拜师》教学反思
2014/04/23 职场文书
用电申请报告范文
2015/05/18 职场文书
钱学森观后感
2015/06/04 职场文书
python获取淘宝服务器时间的代码示例
2021/04/22 Python
手写Spirit防抖函数underscore和节流函数lodash
2022/03/22 Javascript
GoFrame基于性能测试得知grpool使用场景
2022/06/21 Golang