ShopEX后台查看用户IP对应地理位置

本文可以实现ShopEX在后台查看用户注册IP对应的地理位置信息,通过函数获取纯真IP数据库的信息并返回给模板,不需要写入数据库。获取纯真IP的函数修改自Discuz! 的源码。获取IP信息的代码稍加修改即可用作其它类型的网站,支持UTF-8及GBK编码。


修改前的效果:



(1)准备:

下载最新的纯真IP数据库 qqwry.dat

建立文件pure_get.php  代码如下:


<?php
//包含ShopEX根目录下的配置文件
include_once('../../../.././config/config.php');


//===================================
//
// 功能:通过用户id获取ip
// 参数:$mid 即是用户id
//
//===================================


function convertmid($mid){

	$ip_mid = $mid;

	//连接数据库通过id获取ip
	$ip_dbconn = mysql_connect(DB_HOST,DB_USER,DB_PASSWORD);

	if($ip_dbconn){
		$ip_dbsel = mysql_select_db(DB_NAME,$ip_dbconn);
		$ip_dbquery = 'SELECT reg_ip FROM `'.DB_PREFIX.'members` WHERE member_id='.$ip_mid;
		$ip_dbresult = mysql_query($ip_dbquery, $ip_dbconn);
		$ip_addr = mysql_result($ip_dbresult,0,0);

		if(!$ip_dbresult){
			return 'NULL';
		}

		return $ip_addr;

	}
	
	//关闭数据库
	mysql_close($ip_dbconn);
}



//===================================
//
// 功能:IP地址获取真实地址函数
// 参数:$ip - IP地址  $a1 - 是否为Linux系统  $a2 - 是否需要返回UTF-8编码
//
//===================================


function convertip($ip, $a1, $a2) {

//
$is_linux = $a1;
$is_utf   = $a2;


//纯真数据库文件绝对路径,linux下使用‘/’,windows下使用‘\’
if($is_linux){
	$dat_path = BASE_DIR.'/qqwry.dat'; 
}else{
	$dat_path = BASE_DIR.'\qqwry.dat';
}


//检查IP地址格式
if(!preg_match("/^\d{1,3}.\d{1,3}.\d{1,3}.\d{1,3}$/", $ip)){
	return 'IP 地址错误!';
}


//打开IP数据文件,如果提示'IP数据文件无法读取,请确保是正确的纯真IP库!',还有可能是文件位置的问题
//所以请尽量吧qqwry.dat放在网站的根目录(注意,不是服务器根目录!)
if(!$fd = @fopen($dat_path, 'rb')){
	return 'IP数据文件无法读取,请确保是正确的纯真IP库!';
} 

//分解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)); //unpack() 函数从二进制字符串对数据进行解包。unpack(format,data) L - unsigned long (always 32 bit, machine byte order)
#$ipbegin 值如:5386001
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记录
$ip1num=''; $ip2num=''; $ipAddr1=''; $ipAddr2='';
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';
} 

//如果需要UTF编码 则作出一些转换,否则返回GBK编码
if($is_utf){
	return iconv("gbk","utf-8",$ipaddr);
}else{
	return $ipaddr;
}

}



?>

(2)上传文件:

放置 qqwry.dat 到ShopEX根目录,放置 pure_get.php 到 “shopex\core\admin\controller\member” 目录


(3)修改代码:

打开 shopex\core\admin\controller\member\ctl.member.php 找到函数 function show_detail($nMId)

在函数内添加:

		// 修改:获取注册ip地址信息
		// 这里要注意函数 convertip 的参数一定要填对  不然会乱码
		include_once('pure_get.php');
		$ip_addr = convertmid($nMId); 
		$ip_location = convertip($ip_addr, 0, 1);
		$this->pagedata['ip_location'] = $ip_location;


打开模板 shopex\core\admin\view\member\member_items.html 找到 <{$mem.reg_ip}>

在后面添加:

<label><{$ip_location}></label>

注意,member_items.html中的 $ip_location 和 函数 show_detail 中的 pagedata[ip_location'] 相对应,可以先设置一些别的数值来测试显示结果。


(4)测试:

到后台查看效果


(5)说明:

pure_get.php 中的 function convertmid($mid) 用于用过用户 id 获取ShopEX 的注册ip 地址,这个函数其实不太安全,但目前对 ShopEX 的代码理解不够,暂时找不到好方法。这里没有直接用数据库的账号密码而是调用了config文件算是一种安全措施了吧。


如果能直接找到IP地址这个变量,就可以用 convertip($ip, $a1, $a2) 来访问纯真数据库并获得地址信息。记住要加上参数,否则会造成访问不到IP数据库或者返回乱码这两种错误。


===================================

本文来自:http://blog.csdn.net/zh405123507

tags:shopex IP 纯真数据库 qqwry


猜你喜欢

转载自blog.csdn.net/zh405123507/article/details/7424667