IP查询的方法(PHP和C#)

来源:互联网 发布:蔡晓红淘宝 编辑:程序博客网 时间:2024/06/06 02:08

首先下载最新的:(纯真)qqwry.dat文件


C #中的使用方法:

class IPHelper    {        FileStream ipFile;        long ip;        string ipfilePath;        ///<summary>        /// 构造函数        ///</summary>        ///<param name="ipfilePath">纯真IP数据库路径</param>        public IPHelper(string ipfilePath)        {            this.ipfilePath = ipfilePath;        }        ///<summary>        /// 地理位置,包括国家和地区        ///</summary>        public struct IPLocation        {            public string country, area;        }        ///<summary>        /// 获取指定IP所在地理位置        ///</summary>        ///<param name="strIP">要查询的IP地址</param>        ///<returns></returns>        public IPLocation GetIPLocation(string strIP)        {            ip = IPToLong(strIP);            ipFile = new FileStream(ipfilePath, FileMode.Open, FileAccess.Read);            long[] ipArray = BlockToArray(ReadIPBlock());            long offset = SearchIP(ipArray, 0, ipArray.Length - 1) * 7 + 4;            ipFile.Position += offset;//跳过起始IP            ipFile.Position = ReadLongX(3) + 4;//跳过结束IP            IPLocation loc = new IPLocation();            int flag = ipFile.ReadByte();//读取标志            if (flag == 1)//表示国家和地区被转向            {                ipFile.Position = ReadLongX(3);                flag = ipFile.ReadByte();//再读标志            }            long countryOffset = ipFile.Position;            loc.country = ReadString(flag);            if (flag == 2)            {                ipFile.Position = countryOffset + 3;            }            flag = ipFile.ReadByte();            loc.area = ReadString(flag);            ipFile.Close();            ipFile = null;            return loc;        }        ///<summary>        /// 将字符串形式的IP转换位long        ///</summary>        ///<param name="strIP"></param>        ///<returns></returns>        public long IPToLong(string strIP)        {            byte[] ip_bytes = new byte[8];            string[] strArr = strIP.Split(new char[] { '.' });            for (int i = 0; i < 4; i++)            {                ip_bytes[i] = byte.Parse(strArr[3 - i]);            }            return BitConverter.ToInt64(ip_bytes, 0);        }        ///<summary>        /// 将索引区字节块中的起始IP转换成Long数组        ///</summary>        ///<param name="ipBlock"></param>        long[] BlockToArray(byte[] ipBlock)        {            long[] ipArray = new long[ipBlock.Length / 7];            int ipIndex = 0;            byte[] temp = new byte[8];            for (int i = 0; i < ipBlock.Length; i += 7)            {                Array.Copy(ipBlock, i, temp, 0, 4);                ipArray[ipIndex] = BitConverter.ToInt64(temp, 0);                ipIndex++;            }            return ipArray;        }        ///<summary>        /// 从IP数组中搜索指定IP并返回其索引        ///</summary>        ///<param name="ipArray">IP数组</param>        ///<param name="start">指定搜索的起始位置</param>        ///<param name="end">指定搜索的结束位置</param>        ///<returns></returns>        int SearchIP(long[] ipArray, int start, int end)        {            int middle = (start + end) / 2;            if (middle == start)                return middle;            else if (ip < ipArray[middle])                return SearchIP(ipArray, start, middle);            else                return SearchIP(ipArray, middle, end);        }        ///<summary>        /// 读取IP文件中索引区块        ///</summary>        ///<returns></returns>        byte[] ReadIPBlock()        {            long startPosition = ReadLongX(4);            long endPosition = ReadLongX(4);            long count = (endPosition - startPosition) / 7 + 1;//总记录数            ipFile.Position = startPosition;            byte[] ipBlock = new byte[count * 7];            ipFile.Read(ipBlock, 0, ipBlock.Length);            ipFile.Position = startPosition;            return ipBlock;        }        ///<summary>        /// 从IP文件中读取指定字节并转换位long        ///</summary>        ///<param name="bytesCount">需要转换的字节数,主意不要超过8字节</param>        ///<returns></returns>        long ReadLongX(int bytesCount)        {            byte[] _bytes = new byte[8];            ipFile.Read(_bytes, 0, bytesCount);            return BitConverter.ToInt64(_bytes, 0);        }        ///<summary>        /// 从IP文件中读取字符串        ///</summary>        ///<param name="flag">转向标志</param>        ///<returns></returns>        string ReadString(int flag)        {            if (flag == 1 || flag == 2)//转向标志                ipFile.Position = ReadLongX(3);            else                ipFile.Position -= 1;            List<byte> list = new List<byte>();            byte b = (byte)ipFile.ReadByte();            while (b > 0)            {                list.Add(b);                b = (byte)ipFile.ReadByte();            }            return Encoding.Default.GetString(list.ToArray());        }    }
调用如下:

static void Main(string[] args)        {            string ipfilePath = @"D:\qqwry.dat";            IPHelper IPHelper = new IPHelper(ipfilePath);            string ip = "72.51.27.51";            IPHelper.IPLocation loc = IPHelper.GetIPLocation(ip);            Console.WriteLine("你查的ip是:{0} 地理位置:{1} {2}", ip, loc.country, loc.area);            Console.ReadKey();        }

PHP中使用:

<?php header("content-type:text/html;charset=gb2312");//*//文件头 [第一条索引的偏移量 (4byte)] + [最后一条索引的偏移地址 (4byte)]     8字节//记录区 [结束ip (4byte)] + [地区1] + [地区2]                                4字节+不定长//索引区 [开始ip (4byte)] + [指向记录区的偏移地址 (3byte)]                   7字节//注意:使用之前请去网上下载纯真IP数据库,并改名为 "CoralWry.dat" 放到当前目录下即可.//by 查询吧 www.query8.com//*class ipLocation {var $fp;var $firstip;  //第一条ip索引的偏移地址var $lastip;   //最后一条ip索引的偏移地址var $totalip;  //总ip数//*//构造函数,初始化一些变量//$datfile 的值为纯真IP数据库的名子,可自行修改.//*function ipLocation($datfile = "qqwry.dat"){  $this->fp=fopen($datfile,'rb');   //二制方式打开  $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);  $str="";  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)));}//*//获取客户端ip地址//注意:如果你想要把ip记录到服务器上,请在写库时先检查一下ip的数据是否安全.//*function getIP() {        if (getenv('HTTP_CLIENT_IP')) {                                $ip = getenv('HTTP_CLIENT_IP');                 }                elseif (getenv('HTTP_X_FORWARDED_FOR')) { //获取客户端用代理服务器访问时的真实ip 地址                                $ip = getenv('HTTP_X_FORWARDED_FOR');                }                elseif (getenv('HTTP_X_FORWARDED')) {                                 $ip = getenv('HTTP_X_FORWARDED');                }                elseif (getenv('HTTP_FORWARDED_FOR')) {                                $ip = getenv('HTTP_FORWARDED_FOR');                 }                elseif (getenv('HTTP_FORWARDED')) {                                $ip = getenv('HTTP_FORWARDED');                }                else {                                 $ip = $_SERVER['REMOTE_ADDR'];                }                return $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; } }//测试一把$t = new ipLocation;$result = $t->getaddress('72.51.27.51');print_r($result);echo $result[' area1'];//*ipLocation class end?>