根据用户IP段跳转到所在城市页面(2种)

一、本地纯真IP库,首先下载纯真IP库,文件名为qqwry.dat

1、纯真本地IP库 类文件1.php代码如下

/**
 * 2011-05-11
 * 纯真IP库更新日期 2011-05-17
 * by hkshadow
 * 文件头 [第一条索引的偏移量 (4byte)] + [最后一条索引的偏移地址 (4byte)]     8字节
 * 记录区 [结束ip (4byte)] + [地区1] + [地区2]                                4字节+不定长
 * 索引区 [开始ip (4byte)] + [指向记录区的偏移地址 (3byte)]                   7字节
 * 注意:使用之前请去网上下载纯真IP数据库,并改名为 "qqwry.dat" 放到当前目录下即可.
*/
class IpLocation {
    var $fp;
    var $firstip; //第一条ip索引的偏移地址
    var $lastip; //最后一条ip索引的偏移地址
    var $totalip; //总ip数
    //*
    //构造函数,初始化一些变量
    //$datfile 的值为纯真IP数据库的名子,可自行修改.
    //*
    function ipLocation($datfile = "qqwry.dat") {
        $this->fp = fopen ( $datfile, 'rb' ) or die ( "QQWry.Dat不存在,请去网上下载纯真IP数据库, 'QQWry.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() {
        $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;
    }

}

输出页面2.php代码如下

include "1.php";
header ( "Content-type: text/html; charset=utf-8" );
$local_ip = $_SERVER ['REMOTE_ADDR'];  //内网IP,暂未测试
//返回格式
$format = "text"; //默认text,json,xml,js
//返回编码
$charset = "utf8"; //默认utf-8,gbk或gb2312
#实例化(必须)

/**
 * 正则获取外网IP
 * by hkshadow
 * Enter description here ...
 */
function get_onlineip() {
    $ch = curl_init ( 'http://tool.chinaz.com/IP/?IP=www.baidu.com' );
    curl_setopt ( $ch, CURLOPT_RETURNTRANSFER, true );
    $a = curl_exec ( $ch );
    preg_match ( '/\[(.*)\]/', $a, $ip );
    $ip [1] = strip_tags ( $ip [1] ); //去除加粗
    return $ip [1];
}
//$b = explode ( '.', $a );
$ip_l = new ipLocation (); //实例化
$address = $ip_l->getaddress ( get_onlineip () );

//例一
if((strpos($address['area1'],'武汉') === false)) {
// 如果是的,则从此处进入网站
//  header('HTTP/1.1 301 Moved Permanently');     
//  header("Location: /");
}else{
//否则,恩,你懂得
}

2、本地纯真IP库函数和使用方法

     header("Content-type: text/html; charset=utf-8");

//返回当前IP的城市字符串  
function convertip($ip) {  
    //IP数据文件路径  
    $dat_path = 'qqwry.dat';  

    //检查IP地址  
    if(!preg_match("/^(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])$/", $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的32次幂  
        $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;  
}  

//查找字符串  
function findstr($str, $substr)  
{  
         $m = strlen($str);  
        $n = strlen($substr );  
        if ($m < $n) return false ;  
        for ($i=0; $i <=($m-$n+1); $i ++){  
                $sub = substr( $str, $i, $n);  
                if ( strcmp($sub, $substr) == 0) return true;  
        }  
        return false ;  
}   
&#91;/code&#93;

使用例子

&#91;code lang="php"&#93;
 $Clientip=$_SERVER&#91;"REMOTE_ADDR"&#93;;  

echo $ClientCity=convertip($Clientip);  //获得所在城市字符串

 $ClientCity = iconv("gb2312","utf-8",$ClientCity); //将城市字符串由gb2312转化成utf-8编码,用于解决utf-8页面中文乱码

if (findstr($ClientCity,"南昌")){  
//    Header("Location: http://www.baidu.com");  
//echo 2;
}else{  
// echo 1;   
//  Header("Location: http://google.com.hk");  
}  
&#91;/code&#93;

方法二
使用腾迅的api接口(挂掉了)
可使用新浪API接口
接口地址:http://int.dpool.sina.com.cn/iplookup/iplookup.php
备淘宝API接口:http://ip.taobao.com/service/getIpInfo.php?ip=101.229.118.140
&#91;code lang="php"&#93;
function get_ip_place(){
header ( "Content-type: text/html; charset=gbk" );
$ip=file_get_contents("http://fw.qq.com/ipaddress");
$ip=str_replace('"',' ',$ip);
$ip2=explode("(",$ip);
$a=substr($ip2&#91;1&#93;,0,-2);
$b=explode(",",$a);
return $b;
}
$ips=get_ip_place();

//例一
if((strpos($ips&#91;'3'&#93;,'武汉') === false)) {
// 如果是的,则从此处进入网站
//  header('HTTP/1.1 301 Moved Permanently');     
//  header("Location: /");
}else{
//否则,恩,你懂得
}
&#91;/code&#93;

2012.11.05新增一种根据用户IP来实现跳转
新浪IP接口:
http://int.dpool.sina.com.cn/iplookup/iplookup.php?format=js&ip=IP地址
&#91;code lang="js"&#93;
<script type=text/javascript src=http://int.dpool.sina.com.cn/iplookup/iplookup.php?format=js charset=gb2312></script>
<script type=text/javascript>
alert(remote_ip_info.city);
 </script>

结合PHP:

//直接获取到了一个JSON
$demo = file_get_contents("http://int.dpool.sina.com.cn/iplookup/iplookup.php?format=js&ip=122.12.154.1");
//剩下自由发挥吧

我改了2种编码的(gbk 和 utf-8)

下载地址 utf-8 http://help.mudbest.com/ip/qqwry.rar

gbk http://help.mudbest.com/ip/qqwry-gbk.rar

One Response to “根据用户IP段跳转到所在城市页面(2种)”

Leave a Reply

(will not be published)