PHP根據IP獲取所在地區

<?phpphp

class IpLocation {數據庫

 

    var $fp;安全

 

    var $firstip;  //第一條ip索引的偏移地址服務器

 

    var $lastip;   //最後一條ip索引的偏移地址函數

 

    var $totalip;  //總ip數this

 

    /*代理

     *構造函數,初始化一些變量指針

     *$datfile 的值爲純真IP數據庫的名子,可自行修改.索引

     */ip

    function ipLocation($datfile = "wry.Dat")

    {

      $this->fp = fopen($datfile, 'rb') or die("wry.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()

    {

        $str="";

        $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"] = " ";

      }

 

      return $address;

     }

}

 

$IpLocation = new IpLocation();

$data = $IpLocation->getaddress('61.182.253.174');

 

print_r($data);

?>

相關文章
相關標籤/搜索