一、本地纯真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 ;
}
[/code]
使用例子
[code lang="php"]
$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");
}
[/code]
方法二
使用腾迅的api接口(挂掉了)
可使用新浪API接口
接口地址:http://int.dpool.sina.com.cn/iplookup/iplookup.php
备淘宝API接口:http://ip.taobao.com/service/getIpInfo.php?ip=101.229.118.140
[code lang="php"]
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{
//否则,恩,你懂得
}
[/code]
2012.11.05新增一种根据用户IP来实现跳转
新浪IP接口:
http://int.dpool.sina.com.cn/iplookup/iplookup.php?format=js&ip=IP地址
[code lang="js"]
<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
怎么把gbk的dat转换成utf8的?谢谢