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开发文件系统实例讲解
Oct 09 PHP
做一个有下拉功能的留言版
Oct 09 PHP
mysql_fetch_assoc和mysql_fetch_row的功能加起来就是mysql_fetch_array
Jan 15 PHP
php图片加中文水印实现代码分享
Oct 31 PHP
php中使用preg_match_all匹配文章中的图片
Feb 06 PHP
奉献出一个封装的curl函数 便于调用(抓数据专用)
Jul 22 PHP
php实现与erlang的二进制通讯实例解析
Jul 23 PHP
php中字符集转换iconv函数使用总结
Oct 11 PHP
PHP中创建图像并绘制文字的例子
Nov 19 PHP
php+ajax实现无刷新动态加载数据技术
Apr 28 PHP
Thinkphp 框架扩展之驱动扩展实例分析
Apr 27 PHP
解决thinkphp6(tp6)在状态码500下不报错,或者显示错误“Malformed UTF-8 characters”的问题
Apr 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中数组的分组排序实例
2014/06/01 PHP
typecho插件编写教程(五):核心代码
2015/05/28 PHP
golang与php实现计算两个经纬度之间距离的方法
2016/07/22 PHP
如何使用PHP给图片加水印
2016/10/12 PHP
thinkPHP分页功能实例详解
2017/05/05 PHP
JS(jQuery)实现聊天接收到消息语言自动提醒功能详解【提示“您有新的消息请注意查收”】
2019/04/16 PHP
用javascript父窗口控制只弹出一个子窗口
2007/04/10 Javascript
asp.net下使用jquery 的ajax+WebService+json 实现无刷新取后台值的实现代码
2010/09/19 Javascript
jquery tab插件精简版分享
2011/09/10 Javascript
javascript游戏开发之《三国志曹操传》零部件开发(五)可移动地图的实现
2013/01/23 Javascript
Jquery的hide及toggle方法让超链接慢慢消失
2013/09/06 Javascript
动态加载dtree.js树treeview(示例代码)
2013/12/17 Javascript
JavaScript结合AJAX_stream实现流式显示
2015/01/08 Javascript
jQuery选择器querySelector的使用指南
2015/01/23 Javascript
jquery实现列表上下移动功能
2016/02/25 Javascript
canvas实现刮刮卡效果
2017/03/14 Javascript
微信小程序 获取二维码实例详解
2017/06/23 Javascript
微信小程序实现城市列表选择
2018/06/05 Javascript
JavaScript之实现一个简单的Vue示例
2019/01/17 Javascript
使用JavaScript保存文本文件到本地的两种方法
2019/01/22 Javascript
深入浅析vue中cross-env的使用
2019/09/12 Javascript
Python实现发送QQ邮件的封装
2017/07/14 Python
Python实现螺旋矩阵的填充算法示例
2017/12/28 Python
浅谈Python接口对json串的处理方法
2018/12/19 Python
PyQt5 加载图片和文本文件的实例
2019/06/14 Python
PythonPC客户端自动化实现原理(pywinauto)
2020/05/28 Python
next在python中返回迭代器的实例方法
2020/12/15 Python
FOREO斐珞尔官方旗舰店:LUNA露娜洁面仪
2018/03/11 全球购物
New Balance德国官方网站:购买鞋子和服装
2019/08/31 全球购物
幼儿园教师备课制度
2014/01/12 职场文书
聚美优品陈欧广告词
2014/03/14 职场文书
领导干部民主生活会自我剖析材料范文
2014/09/20 职场文书
英语感谢信范文
2015/01/20 职场文书
2015年秋季学校开学标语
2015/07/16 职场文书
商务信函英语问候语
2015/11/10 职场文书
公安忠诚教育心得体会
2016/01/23 职场文书