根据用户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 ;  
}   

使用例子

 $Clientip=$_SERVER["REMOTE_ADDR"];  

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");  
}  

方法二
使用腾迅的api接口(挂掉了)
可使用新浪API接口
接口地址:http://int.dpool.sina.com.cn/iplookup/iplookup.php
备淘宝API接口:http://ip.taobao.com/service/getIpInfo.php?ip=101.229.118.140

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[1],0,-2);
$b=explode(",",$a);
return $b;
}
$ips=get_ip_place();

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

2012.11.05新增一种根据用户IP来实现跳转
新浪IP接口:

http://int.dpool.sina.com.cn/iplookup/iplookup.php?format=js&ip=IP地址

<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)