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 相关文章推荐
使用MaxMind 根据IP地址对访问者定位
Oct 09 PHP
实现php加速的eAccelerator dll支持文件打包下载
Sep 30 PHP
Windows Apache2.2.11及Php5.2.9-1的安装与配置方法
Jun 08 PHP
比较简单的百度网盘文件直链PHP代码
Mar 24 PHP
php setcookie函数的参数说明及其用法
Apr 20 PHP
PHP实现使用优酷土豆视频地址获取swf播放器分享地址
Jun 05 PHP
jQuery获取json后使用zy_tmpl生成下拉菜单
Mar 27 PHP
PHP5多态性与动态绑定介绍
Apr 03 PHP
Symfony2在Nginx下的配置方法图文教程
Feb 04 PHP
PHP中STDCLASS用法实例分析
Nov 11 PHP
PHP简单实现循环链表功能示例
Nov 10 PHP
解决Laravel5.2 Auth认证退出失效的问题
Oct 14 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
无法载入 mcrypt 扩展,请检查 PHP 配置终极解决方案
2011/07/18 PHP
解析php addslashes()与addclashes()函数的区别和比较
2013/06/24 PHP
php上传图片到指定位置路径保存到数据库的具体实现
2013/12/30 PHP
ThinkPHP模板之变量输出、自定义函数与判断语句用法
2014/11/01 PHP
解析WordPress中的post_class与get_post_class函数
2016/01/04 PHP
基于jQueryUI和Corethink实现百度的搜索提示功能
2016/11/09 PHP
静态图片的十一种滤镜效果--不支持Ie7及非IE浏览器。
2007/03/06 Javascript
javascript 操作Word和Excel的实现代码
2009/10/26 Javascript
理解Javascript_01_理解内存分配原理分析
2010/10/11 Javascript
Javascript 运动中Offset的bug解决方案
2014/12/24 Javascript
JavaScript中的object转换成number或string规则介绍
2014/12/31 Javascript
浅谈angularJS 作用域
2015/07/05 Javascript
javascript实现动态标签云
2015/10/16 Javascript
jQuery Mobile开发中日期插件Mobiscroll使用说明
2016/03/02 Javascript
jquery自定义插件开发之window的实现过程
2016/05/06 Javascript
jQuery Validate验证表单时多个name相同的元素只验证第一个的解决方法
2016/12/24 Javascript
javascript cookie的基本操作(添加和删除)
2017/07/24 Javascript
微信小程序实现天气预报功能
2018/07/18 Javascript
python列表与元组详解实例
2013/11/01 Python
Python计算已经过去多少个周末的方法
2015/07/25 Python
pandas string转dataframe的方法
2018/04/11 Python
python监控文件并且发送告警邮件
2018/06/21 Python
Python基于OpenCV实现人脸检测并保存
2019/07/23 Python
django中url映射规则和服务端响应顺序的实现
2020/04/02 Python
船餐厅和泰晤士河餐饮游轮:Bateaux London
2018/03/19 全球购物
美国手机支架公司:PopSockets
2019/11/27 全球购物
C/C++程序员常见面试题一
2012/12/08 面试题
法制宣传日活动总结
2014/04/29 职场文书
副处级干部考察材料
2014/05/17 职场文书
企业消防安全责任书
2014/07/23 职场文书
绿色环保家庭事迹材料
2014/08/31 职场文书
暑假生活随笔
2015/08/15 职场文书
2017寒假社会实践心得体会范文
2016/01/14 职场文书
python实现三次密码验证的示例
2021/04/29 Python
浅析Django接口版本控制
2021/06/26 Python
MySQL中几种插入和批量语句实例详解
2021/09/14 MySQL