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 相关文章推荐
php sprintf()函数让你的sql操作更安全
Jul 23 PHP
PHP中替换换行符的几种方法小结
Oct 15 PHP
php分页代码学习示例分享
Feb 20 PHP
php格式化时间戳显示友好的时间实现思路及代码
Oct 23 PHP
PHP 二维数组和三维数组的过滤
Mar 16 PHP
Zend Framework教程之Zend_Db_Table_Row用法实例分析
Mar 21 PHP
php的socket编程详解
Nov 20 PHP
PHP完全二叉树定义与实现方法示例
Oct 09 PHP
Laravel5.5以下版本中如何自定义日志行为详解
Aug 01 PHP
Discuz不使用插件实现简单的打赏功能
Mar 21 PHP
laravel框架模型中非静态方法也能静态调用的原理分析
Nov 23 PHP
PHP 实现base64编码文件上传出现问题详解
Sep 01 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+mysql扎实个人基本功
2008/03/27 PHP
PHP如何将log信息写入服务器中的log文件
2015/07/29 PHP
AJAX PHP无刷新form表单提交的简单实现(推荐)
2016/09/09 PHP
php中this关键字用法分析
2016/12/07 PHP
PHP延迟静态绑定使用方法实例解析
2020/09/05 PHP
判断控件是否已加载完成的代码
2010/02/24 Javascript
JavaScript操作XML实例代码(获取新闻标题并分页,并分页)
2010/05/25 Javascript
js捕获鼠标右键菜单中的粘帖事件实现代码
2013/04/01 Javascript
javascript常用的正则表达式实例
2014/05/15 Javascript
jQuery添加/改变/移除CSS类及判断是否已经存在CSS
2014/08/20 Javascript
node.js中的emitter.on方法使用说明
2014/12/10 Javascript
使用PBFunc在Powerbuilder中支付宝当面付款功能
2016/10/01 Javascript
js事件冒泡与事件捕获详解
2017/02/20 Javascript
使用AngularJS对表单提交内容进行验证的操作方法
2017/07/12 Javascript
开发Vue树形组件的示例代码
2017/12/21 Javascript
微信小程序视图容器(swiper)组件创建轮播图
2020/06/19 Javascript
详解promise.then,process.nextTick, setTimeout 以及 setImmediate的执行顺序
2018/11/21 Javascript
微信小程序实现点击空白隐藏的方法示例
2019/08/13 Javascript
详解JavaScript 事件流
2020/09/02 Javascript
[48:27]EG vs Liquid 2018国际邀请赛淘汰赛BO3 第二场 8.25
2018/08/29 DOTA
[01:08:43]DOTA2-DPC中国联赛定级赛 Phoenix vs DLG BO3第一场 1月9日
2021/03/11 DOTA
深入讨论Python函数的参数的默认值所引发的问题的原因
2015/03/30 Python
Python数据结构之翻转链表
2017/02/25 Python
Python从list类型、range()序列简单认识类(class)【可迭代】
2019/05/31 Python
CSS3的column-fill属性对齐列内容高度的用法详解
2016/07/01 HTML / CSS
HTML5 Canvas 起步(1) - 基本概念
2009/05/12 HTML / CSS
会计专业大学生职业生涯规划范文
2014/01/11 职场文书
服装采购员岗位职责
2014/03/15 职场文书
五年级学生评语
2014/04/22 职场文书
志愿者活动总结范文
2014/04/26 职场文书
生产助理岗位职责
2014/06/18 职场文书
2014年房产经纪人工作总结
2014/12/08 职场文书
幼儿园教师考核评语
2014/12/31 职场文书
2015年酒店客房部工作总结
2015/04/25 职场文书
2015年物业管理员工工作总结
2015/10/15 职场文书
解决flex布局中子项目尺寸不受flex-shrink限制
2022/05/11 HTML / CSS