您的位置:首页 > 数据库

一个类似纯真IP数据库的存储和读取程序

2009-05-22 23:17 330 查看
一个类似纯真IP数据库的存储和读取程序  ,删除了国外的IP数据,国内只到省市一级 如:192.168.1.2  ,192.168.2.155 福建省 厦门市

 

 

write
<?php
error_reporting(E_ALL);
set_time_limit(0); //设置脚本运行时间,参数0为无限时
$link = mysql_connect('localhost','root','1');
mysql_select_db('ip',$link);
$fd = fopen("my.hb2008", "wb");
$datahead =pack('V',8);
$dataheadend =pack('V',465824);
fwrite($fd,$datahead);
fwrite($fd,$dataheadend);
$f=0;
$k =8;  //索引区偏移
$i = 465830;  ////记录区偏移
mysql_query("set names utf8");
$result = mysql_query("select * from wry order by fip ");
 while ($row =mysql_fetch_object($result)) {
  fseek($fd,$k);
  $begin = $row->fip;
    $endip = $row->eip;
    $country = $row->country;
    $area = $row->area;
  $v_address = $country.' '.$area;
  $length = strlen($v_address);

    $v_begin = pack('V',floatval($begin));
  $v_endip = pack('V',floatval($endip));
  $v_offset = pack('V',floatval($i));
  $v_length = pack('c',$length); //13字节

    fwrite($fd,$v_begin);
  fwrite($fd,$v_endip);
  fwrite($fd,$v_offset);
  fwrite($fd,$v_length);

    fseek($fd,$i);

  $f++;
    fwrite($fd,$v_address);
    $i = $i +$length;
  $k = $k +13;
 }
fclose($fd);
die('成功'.$f);
?>

 

 

 

read.php

 

 

<?php
/* $fp = fopen("a.hb2008", "r"); 
fseek($fp,80);
 $data1 = fread($fp,4);
 
$p_data1 = unpack('Vbegin',$data1);
 var_export($p_data1) ;
// $p_data2 = unpack('V',$data2);
//$count = ($p_data2 - $data1)/12;
//echo $count;
*/

function microtime_float()
{
    list($usec, $sec) = explode(" ", microtime());
    return ((float)$usec + (float)$sec);
}

$time_start = microtime_float();

class IpLocation {
    /**
     * QQWry.Dat文件指针
     *
     * @var resource
     */
    var $fp;

    /**
    * ip数据文件地址
    *
    *@var string
    */
    var $filename="IP/my.hb2008";
    /**
     * 第一条IP记录的偏移地址
     *
     * @var int
     */
    var $firstip;

    /**
     * 最后一条IP记录的偏移地址
     *
     * @var int
     */
    var $lastip;

    /**
     * IP记录的总条数(不包含版本信息记录)
     *
     * @var int
     */
    var $totalip;

    /**
     * 返回读取的长整型数
     *
     * @access private
     * @return int
     */
    public function getlong() {
        //将读取的little-endian编码的4个字节转化为长整型数
        $result = unpack('Vlong', fread($this->fp, 4));
        return $result['long'];
    }

    /**
     * 返回压缩后可进行比较的IP地址
     *
     * @access private
     * @param string $ip
     * @return string
     */
    public function packip($ip) {
        // 将IP地址转化为长整型数,如果在PHP5中,IP地址错误,则返回False,
        // 这时intval将Flase转化为整数-1,之后压缩成big-endian编码的字符串
        return pack('N', intval(ip2long($ip)));  //TCP/IP各层协议将字节序定义为Big-Endian
    }

   

   

    /**
     * 根据所给 IP 地址或域名返回所在地区信息
     *
     * @access public
     * @param string $ip
     * @return array
     */
    public function getlocation($ip) {
        if (!$this->fp) {
         return false;            // 如果数据文件没有被正确打开,则直接返回空
        }
        $location['ip'] = gethostbyname($ip);   // 将输入的域名转化为IP地址
        $ip = $this->packip($location['ip']);   // 将输入的IP地址转化为可比较的IP地址
                                       // 不合法的IP地址会被转化为255.255.255.255  big-endian
         $beginip_validate = strrev(fread($this->fp, 4)) ;                       
        if ($ip <$beginip_validate ) {
         return false;    
        }else {
         fseek($this->fp,$this->firstip);
        }
        // 二分查找法
        $begin = 0;                         // 搜索的上边界
        $end = $this->totalip;            // 搜索的下边界
      
        if (!($findip = $this->binary_classification($begin,$end,$ip))) {
         return false;
        }
        fseek($this->fp, $findip);
        $begin_ip_block  = $this->getlong();
        $end_ip_block = $this->getlong();
        $address =  $this->getlong();
        $pack_length = fread($this->fp,1);
        $length = unpack('c',$pack_length);
        fseek($this->fp,$address);
        $adr =fread($this->fp,$length[1]);
  
        //获取查找到的IP地址位置信息
        $location ['beginip'] = long2ip($begin_ip_block);
        $location ['endip'] = long2ip($end_ip_block);
        $location ['address'] = $adr;
       return $location;
      
    }

    /**
     * 构造函数,打开 文件并初始化类中的信息
     *
     * @param string $filename
     * @return IpLocation
     */
    public function __construct($file = null) {
        if($file) {
         $this->filename = $file;
        } else{
         $this->filename = dirname(__FILE__)."/".$this->filename;
        } 
        if (($this->fp = @fopen($this->filename, 'rb')) !== false) {
            $this->firstip = $this->getlong();
            $this->lastip = $this->getlong();
            $this->totalip = (($this->lastip - $this->firstip) / 13) ;          
        }
        else
        {
            echo "false";
        }
    }

    /**
     * 析构函数,用于在页面执行结束后自动关闭打开的文件。
     *
     */
    public function  __destruct () {
        if ($this->fp) {
            fclose($this->fp);
        }
        $this->fp = null;
    }
   
     /**
     * 二分法
     *
     */
    public function binary_classifica
ad88
tion ($begin,$end,$ip)
    {  
     $findip = null;     
     while ($begin <= $end) {                            // 当下边界小于上边界时,查找失败
            $middle = floor(($begin + $end) / 2);           // 计算近似中间记录
            fseek($this->fp, $this->firstip + ($middle-1) * 13);
            $beginip = strrev(fread($this->fp, 4));         // 获取中间记录的开始IP地址  =>变成大端  
            // strrev函数在这里的作用是将little-endian的压缩IP地址转化为big-endian的格式big-endian(大端) 以便用于比较,后面相同。
            if ($ip < $beginip) {                          // 用户的IP小于中间记录的开始IP地址时
            $end = $middle - 1;                            // 将搜索的下边界修改为中间记录减一 
            }else {      
                $endip = strrev(fread($this->fp, 4));       // 获取中间记录的结束IP地址 
                if ($ip > $endip) {                         // 用户的IP大于中间记录的结束IP地址时
                    $begin = $middle + 1;                   // 将搜索的上边界修改为中间记录加一
                }else {                                     // 用户的IP在中间记录的IP范围内时            
                    $findip = $this->firstip + $middle * 13;  //var_dump($findip);
                    return $findip;
                    break;                                 // 则表示找到结果,退出循环
                }
            }
        }
    }
         
}

var_dump( long2ip(974170117));;
$a = new IpLocation;
$b =$a->getlocation("58.16.168.5");
var_export($b);
$time_end = microtime_float();
$time = $time_end - $time_start;

echo "Did nothing in $time seconds/n";
?>
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐