一、本地纯真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的?谢谢