漂定

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::
<?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;

    }



}



?>

 

posted on 2014-01-15 14:01  漂定  阅读(234)  评论(0编辑  收藏  举报