zoukankan      html  css  js  c++  java
  • 纯真IP根据IP地址获得地址

    <?php
    
    /**
     * 纯真IP根据IP地址获得地址
     */
    
    class ipLocation {
    
        public $fp;
    
        public $firstip;  //第一条ip索引的偏移地址
    
        public $lastip;   //最后一条ip索引的偏移地址
    
        public $totalip;  //总ip数
    
    
    
    //
    
    //*
    
    //构造函数,初始化一些变量
    
    //$datfile 的值为纯真IP数据库的名子,可自行修改.
    
    //*
    
    
    
        function __construct($datfile = "CoralWry.dat") {
    
            $filepath = APP_CLASS . 'Public/CoralWry.dat';
    
            $this->fp = fopen($filepath, '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);
    
            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"] = " ";
    
            }
    
            $address['area1'] = Fun::gbkToutf8($address['area1']);
    
            $address['area2'] = Fun::gbkToutf8($address['area2']);
    
            $address['loc'] = $address['area1'] . ' ' . $address['area2'];
    
            return $address;
    
        }
    
    
    
    }
    
    
    
    ?>
  • 相关阅读:
    BZOJ2243: [SDOI2011]染色(树链剖分/LCT)
    BZOJ2157: 旅游(LCT)
    BZOJ3510首都(LCT)
    BZOJ4530 [BJOI2014]大融合(LCT)
    BZOJ2631: tree(LCT)
    BZOJ2002: [Hnoi2010]Bounce 弹飞绵羊(LCT)
    BZOJ3282: Tree (LCT模板)
    [NOI2008]假面舞会(DFS)
    斜率优化dp练习
    BZOJ2049[Sdoi2008]Cave 洞穴勘测(LCT模板)
  • 原文地址:https://www.cnblogs.com/ahwu/p/3520684.html
Copyright © 2011-2022 走看看