根据访客所在城市ip地址自动跳转到分站的php代码

作者: 金沙澳门官网  发布:2019-09-26

第一拜谒QQWry.Data文件的内容结构 ,以及解读格局 。

<?
//php教程获取ip的算法
$user_IP = ($_SERVER["HTTP_VIA"]) ? $_SERVER["HTTP_X_FORWARDED_FOR"] : $_SERVER["REMOTE_ADDR"];
$user_IP = ($user_IP) ? $user_IP : $_SERVER["REMOTE_ADDR"];
//echo $user_IP;
//===================================
//
// 功效:IP地址获取真实地址函数
// 参数:$ip - IP地址
// 作者:[Discuz!] (C) Comsenz Inc.
//
//===================================
function convertip($ip) {
    //IP数据文件路线,请根据事态自行修改
    $dat_path = 'QQWry.dat';
    //检查IP地址
    if(!ereg("^([0-9]{1,3}.){3}[0-9]{1,3}$", $ip)){
        return 'IP Address Error';
    }
    //张开IP数据文件
    if(!$fd = @fopen($dat_path, 'rb')){
        return 'IP date file not exists or access denied';
    }
    //分解IP实行演算,得出整形数
    $ip = explode('.', $ip);
    $ipNum = $ip[0] * 16777216 + $ip[1] * 65536 + $ip[2] * 256 + $ip[3];
    //获取IP数据索引开首和结束位置
    $DataBegin = fread($fd, 4);
    $DataEnd = fread($fd, 4);
    $ipbegin = implode('', unpack('L', $DataBegin));
    if($ipbegin < 0) $ipbegin += pow(2, 32);
    $ipend = implode('', unpack('L', $DataEnd));
    if($ipend < 0) $ipend += pow(2, 32);
    $ipAllNum = ($ipend - $ipbegin) / 7 + 1;
    $BeginNum = 0;
    $EndNum = $ipAllNum;
    //使用二分查找法从索引记录中查找相称的IP记录
    while($ip1num>$ipNum || $ip2num<$ipNum) {
        $Middle= intval(($EndNum + $BeginNum) / 2);
        //偏移指针到目录地点读取4个字节
        fseek($fd, $ipbegin + 7 * $Middle);
        $ipData1 = fread($fd, 4);
        if(strlen($ipData1) < 4) {
            fclose($fd);
            return 'System Error';
        }
        //提抽取来的多寡调换来长整形,即使数量是负数则增进2的31遍幂
        $ip1num = implode('', unpack('L', $ipData1));
        if($ip1num < 0) $ip1num += pow(2, 32);
        //提取的长整型数大于大家IP地址则修改实现地点实行下一遍巡回
        if($ip1num > $ipNum) {
            $EndNum = $Middle;
            continue;
        }
        //取完上一个索引后取下五个目录
        $DataSeek = fread($fd, 3);
        if(strlen($DataSeek) < 3) {
            fclose($fd);
            return 'System Error';
        }
        $DataSeek = implode('', unpack('L', $DataSeek.chr(0)));
        fseek($fd, $DataSeek);
        $ipData2 = fread($fd, 4);
        if(strlen($ipData2) < 4) {
            fclose($fd);
            return 'System Error';
        }
        $ip2num = implode('', unpack('L', $ipData2));
        if($ip2num < 0) $ip2num += pow(2, 32);
        //没找到提醒未知
        if($ip2num < $ipNum) {
            if($Middle == $BeginNum) {
                fclose($fd);
                return 'Unknown';
            }
            $BeginNum = $Middle;
        }
    }
    //上边包车型地铁代码读晕了,没读理解,有乐趣的逐年读
    $ipFlag = fread($fd, 1);
    if($ipFlag == chr(1)) {
        $ipSeek = fread($fd, 3);
        if(strlen($ipSeek) < 3) {
            fclose($fd);
            return 'System Error';
        }
        $ipSeek = implode('', unpack('L', $ipSeek.chr(0)));
        fseek($fd, $ipSeek);
        $ipFlag = fread($fd, 1);
    }
    if($ipFlag == chr(2)) {
        $AddrSeek = fread($fd, 3);
        if(strlen($AddrSeek) < 3) {
            fclose($fd);
            return 'System Error';
        }
        $ipFlag = fread($fd, 1);
        if($ipFlag == chr(2)) {
            $AddrSeek2 = fread($fd, 3);
            if(strlen($AddrSeek2) < 3) {
                fclose($fd);
                return 'System Error';
            }
            $AddrSeek2 = implode('', unpack('L', $AddrSeek2.chr(0)));
            fseek($fd, $AddrSeek2);
        } else {
            fseek($fd, -1, SEEK_CUR);
        }
        while(($char = fread($fd, 1)) != chr(0))
            $ipAddr2 .= $char;
        $AddrSeek = implode('', unpack('L', $AddrSeek.chr(0)));
        fseek($fd, $AddrSeek);
        while(($char = fread($fd, 1)) != chr(0))
            $ipAddr1 .= $char;
    } else {
        fseek($fd, -1, SEEK_CUR);
        while(($char = fread($fd, 1)) != chr(0))
            $ipAddr1 .= $char;
        $ipFlag = fread($fd, 1);
        if($ipFlag == chr(2)) {
            $AddrSeek2 = fread($fd, 3);
            if(strlen($AddrSeek2) < 3) {
                fclose($fd);
                return 'System Error';
            }
            $AddrSeek2 = implode('', unpack('L', $AddrSeek2.chr(0)));
            fseek($fd, $AddrSeek2);
        } else {
            fseek($fd, -1, SEEK_CUR);
        }
        while(($char = fread($fd, 1)) != chr(0)){
            $ipAddr2 .= $char;
        }
    }
    fclose($fd);
    //最后做相应的轮换操作后回来结果
    if(preg_match('/http/i', $ipAddr2)) {
        $ipAddr2 = '';
    }
    $ipaddr = "$ipAddr1 $ipAddr2";
    $ipaddr = preg_replace('/CZ88.Net/is', '', $ipaddr);
    $ipaddr = preg_replace('/^s*/is', '', $ipaddr);
    $ipaddr = preg_replace('/s*$/is', '', $ipaddr);
    if(preg_match('/http/i', $ipaddr) || $ipaddr == '') {
        $ipaddr = 'Unknown';
    }
    return $ipaddr;
}
?>
<script language="javascript教程">
var sf='<?echo convertip($user_IP);?>';
if(sf.indexOf("香港")>=0){
        window.location.href="";
}
else if(sf.indexOf("广东省")>=0){
        window.location.href="";
}
else if(sf.indexOf("北京")>=0){
        window.location.href="";
}
else{
        window.location.href="";
}
</script>

一、文件结构
文件重大分八个协会
1、文件头,8个字节;
2、数据记录区,不定长度;
3、索引区,长度为 7 的大背头倍;

二、文件头
文本头的8个字节分两片段,每种部分4个字节,分别钦点了索引区的最初地址和得了地址。所以能够因此八个地点的差值 除 7 后 加 1 能够测算出总的记录数。

二、记录区
记录区的数目必要经过索引区的数目来获得各样数据的胚胎地点;本区数据记录了IP地址的竣事地址和地域字符串;全部地点字符串都是0×00 为甘休。

三、索引区
搜索IP对应的地面,关键正是找到IP开端地址对应的目录内容。一个IP索引数据包涵7个字节,前4个字节是IP地址开端值,后3个字节是相应的IP数据 记录在文件内的舞狮地址;IP数据记录中,前 4 个字节是IP甘休地址;紧跟的数码有三种情势: 0×01 格局 和 0×02 格局。

0×01格局,即在IP数据的第5个字节是 0×01,则在后头的 3 个字节是国家地区数据的撼动地址;国家位置数据包蕴国家和所在那多个字符串。即
—————————————————————
4字节 | 3字节 重定向 0x NN NN NN -> 国家地区数据的文书偏移地址
—————————————————————

0×02形式,即在IP数据的第5个字节是 0×02,则在末端的 3 个字节是国家数据的偏移地址,地区数据是再以往的字符串,以 0×00 甘休。即
—————————————————————————–
4字节 | 3字节 重定向 0x NN NN NN -> 国家数据的文件偏移地址 | 地区字符串 | 0×00
—————————————————————————–

对此 0×01 方式所收获的 国家地点数据中,它或者又富含二个重定向结构,即
————————————–
国家字符串 | 0×00 | 地区字符串 | 0×00
————————————–

————————————————————————-
江山字符串 | 0×00 | 0×02 | 3字节 0x NN NN NN -> 地区字符串的文件偏移地址
————————————————————————-

对于前一种情况,相比较轻松,直接读出多个字符串数据就足以了;对于后一种状态,要求再行重定向到所在字符串的偏移地址,然后读取到 0×00 为字符串结尾。

对于这种利用地址映射实际字符串值的法子,主要作用是幸免重复记录字符串值。在方方面面IP地址库文件中,有太多一致字符串记录了,采用3 字节的炫目地址要比重复记录字符串值节省太多空间了。

PHP代码读取操作QQWry.dat文件 :

 代码如下

function bin2ip($bin){
 $ip = '';
 $bd = str_split($bin, 1);
 for($i = 4; $i > 0; $i--){
  $ip .= "." . sprintf("%03d", implode('', unpack('s', $bd[$i-1] . chr(0))));
 }
 return substr($ip, 1);
}

//--------------------------------------------------
$f = fopen('QQWry.Dat', 'r');
$c = fread($f, 4);
$d = fread($f, 4);

$index_begin = implode('', unpack('L', $c));
$index_end  = implode('', unpack('L', $d));
if($index_begin < 0) $index_begin += pow(2, 32);
if($index_end < 0) $index_end += pow(2, 32);

$ip_num = ($index_end - $index_begin) / 7 + 1;

echo "index begin at: $index_beginn";
echo "index end at: $index_endn";
echo "ip data count : $ip_numn";

$output = '';

for($i = 0; $i < $ip_num; $i++){

 //文件指针指到每一种IP数据文件的目录获得索引数据(7字节)上
 fseek($f, $i * 7 + $index_begin);
 $ip4 = fread($f, 4); //IP开首地址
 if(strlen($ip4) < 4) exit('data file error');

 $ip3 = fread($f, 3); //IP记录偏移地址
 if(strlen($ip3) < 3) exit('data file error');

 $dataseek = implode('', unpack('L', $ip3 . chr(0)));
 if($dataseek < 0) $index_ip_record += pow(2, 32);

 //指向记录区 $dataseek 地点查找记录
 fseek($f, $dataseek);
 $ipdata = fread($f, 4); //IP停止地址
 if(strlen($ipdata) < 4) exit('data file error');

 $area = '';
 $country = '';

 //读贰个标志位
 $flag = fread($f, 1);
 if($flag == chr(1)){ //国家名偏移标志位 情势一 0x01
  $area1seek = fread($f, 3);
  if(strlen($area1seek) < 3) exit('data file error');
  $area1seek = implode('', unpack('L', $area1seek . chr(0)));
  fseek($f, $area1seek);
  $flag = fread($f, 1); //恐怕又是标识位
 }
 if($flag == chr(2)){ //国家地区 重定向
  $area1seek = fread($f, 3);
  if(strlen($area1seek) < 3) exit('data file error');
  $area1seek = implode('', unpack('L', $area1seek . chr(0)));
  $flag = fread($f, 1);
  if($flag == chr(2)){
   $area2seek = fread($f, 3);
   $area2seek = implode('', unpack('L', $area2seek . chr(0)));
   fseek($f, $area2seek);
  }else{
   fseek($f, -1, SEEK_CUR);
  }
  while(($c = fread($f, 1)) != chr(0)) $area .= $c;
  fseek($f, $area1seek);
  while(($c = fread($f, 1)) != chr(0)) $country .= $c;
 }else{
  fseek($f, -1, SEEK_CUR);
  while(($c = fread($f, 1)) != chr(0)) $country .= $c;

  $flag = fread($f, 1); //假若地区是重定向的
  if($flag == chr(2)){
   $area2seek = fread($f, 3);
   $area2seek = implode('', unpack('L', $area2seek . chr(0)));
   fseek($f, $area2seek);
  }else{
   fseek($f, -1, SEEK_CUR);
  }
  while(($c = fread($f, 1)) != chr(0)) $area .= $c;
 }
 $adata = trim($country) . trim($area); //$country是国家字符串 , $area 是地面字符串
}
fclose($f);

以此函数我们看出最多的正是文件操作相关函数如fopen,fseek,fread那么些,有需求的相爱的人能够看看。

本文由金沙澳门官网送注册58发布于金沙澳门官网,转载请注明出处:根据访客所在城市ip地址自动跳转到分站的php代码

关键词: