完美解决DZ论坛整合2009-05-11 10:07说明:自己有网站(SNS),以下都用SNS代表自己网站,也有自己单独的会员系统,但想在自己网站上整合进DZ论坛时,遇到了注册、登陆、退出三要素的同步处理问题。
例如在我自己网站上登陆了,到了论坛却还要登陆一次,然后,两边的登陆名字也可能并不相同,正是因为此,所以才有了下面这篇文章。
资源:
UCenter_1.0.0_SC_UTF8 安装DZ论坛,必须先安装这个用户控制中心
Discuz_6.1.0_SC_UTF8 DZ论坛,注意与上面的UCenter字符编码要一致
安装:
UCenter 安装到网站根目录下面的 /ucenter 文件夹(这个可以随意改,但本文其后对应文件路径需注意同步修正)。
Discuz 安装到网站根目录下面的 /bbs 文件夹(同上,也可以随意改)
关键位置:
/bbs/register.php DZ论坛注册页面
/bbs/logging.php DZ论坛登陆页面
/bbs/uc_client/model/user.php UCenter的会员信息入库及其他(目前只需关心入库add_user())
SNS所需添加的函数:
/bbs/include/gloabl.func.php 文件中
formhash() 防恶意提交的机器加密函数,所需变量:$discuz_user, $discuz_uid, $discuz_pw, $timestamp, $discuz_auth_key
authcode() 登陆用户信息的加密函数,所需参数:$string, $operation = ‘DECODE’, $key = ”, $expiry = 0
dsetcookie() 设置cookie用的
修改代码:
1、有新人在论坛注册时,同时也注册SNS网站,在位置/bbs/uc_client/model/user.php的add_user()函数内部插入以下代码(至于在第几行插入,我想不用我说了吧)
$date = date(“Y-m-d H:i:s”,$this->base->time);
$ip = $this->base->onlineip;
mysql_query(“insert into t_member(member_id,nickname,email_address,password,salt,access_date,reg_date,last_login_ip) values(‘$uid’,’$username’,’$email’,’$password’,’$salt’,’$date’,’$date’,’$ip’)”);
2、有新人在SNS网站上注册时,同时也注册论坛,这个位置就由SNS站点定了,经过错综复杂的DZ注册流程及错综复杂的数据库关系研究,发现,最初级的注册时,只需修改以下
数据库,也就是说其他的DZ关系库,都是后期维护的时候,才会有修改
$db->query(“insert into uc_members(username,password,email,regip,regdate,salt) values(‘$nickname’,’$pa’,’$email_address’,’$ip’,’$timestamp’,’$salt’)”);
$uid = $db->insert_id();
$db->query(“insert into uc_memberfields(uid) values(‘$uid’)”);
$db->query(“INSERT INTO bbs_members (uid, username, password, groupid, regip, regdate, lastvisit, lastactivity, email, styleid, pmsound, showemail, newsletter, timeoffset) VALUES (‘$uid’, ‘$nickname’, ‘$pa’, ’10’, ‘$ip’, ‘$timestamp’, ‘$timestamp’, ‘$timestamp’, ‘$email_address’, ”, ‘1’, ‘1’, ‘1’, ‘9999’)”);
$db->query(“INSERT INTO bbs_memberfields (uid) VALUES (‘$uid’)”);
这里要注意一点,因为这个UID的特殊性,所以,最好是SNS站点与DZ站点的UID是一致的,所以,以上的插入代码应该优先SNS站点的插入代码,以便于取得UCenter的UID,
然后再将取得的UID以ID号的形式插入到SNS站点。举例如下(到这里已经看懂了,就不必看下面的例子了):
//注册到论坛
$db->query(“insert into uc_members(username,password,email,regip,regdate,salt) values(‘$nickname’,’$pa’,’$email_address’,’$ip’,’$timestamp’,’$salt’)”);
$uid = $db->insert_id();
$db->query(“insert into uc_memberfields(uid) values(‘$uid’)”);
$db->query(“INSERT INTO bbs_members (uid, username, password, groupid, regip, regdate, lastvisit, lastactivity, email, styleid, pmsound, showemail, newsletter, timeoffset) VALUES (‘$uid’, ‘$nickname’, ‘$pa’, ’10’, ‘$ip’, ‘$timestamp’, ‘$timestamp’, ‘$timestamp’, ‘$email_address’, ”, ‘1’, ‘1’, ‘1’, ‘9999’)”);
$db->query(“INSERT INTO bbs_memberfields (uid) VALUES (‘$uid’)”);
//注册到SNS
$query = $db->query(“insert into t_member(member_id,nickname,password,salt,email_address,sex,zj_address,privacy_set,access_date,reg_date,last_login_ip) values(‘$uid’,’$nickname’,’$pa’,’$salt’,’$email_address’,’$sex’,’$zj_address’,’$is_hidden’,’$save_time’,’$save_time’,’$ip’)”);
3、有人在论坛登陆时,同时也登陆SNS站点,这个简单,在位置/bbs/logging.php 中有 dsetcookie 字样的下面增加SNS站点的登陆即可,例如dsetcookie(“uid”,$discuz_uid,$cookietime);
4、有人在SNS站点登陆时,同时也登陆DZ论坛,这个有点复杂,需利用函数formhash()生成表单验证码,然后再根据邮箱名取得UCenter中的用户名,再用取得的用户名、
密码、表单验证码等模拟登陆DZ论坛,之所以要模拟登陆,是为了避开DZ论坛纷繁复杂的登陆验证系统,经几番尝试,要在SNS站点上实现论坛登陆,几乎是不可能,
除非从一开始SNS站点就是在一个完整的DZ上开发出来的。将下面这段代码放到登陆页的页头文件里去:
//获取当前登陆的用户ID号
$uid = $_COOKIE[‘uid’];
//应用DZ论坛算法,取得常量 FORMHASH , 只用作登陆
$discuz_pw = $discuz_pw ? $discuz_pw : ”;
$discuz_secques = $discuz_secques ? $discuz_secques : ”;
$discuz_uid = $discuz_uid ? $discuz_uid : 0;
if($uid){
if($arr = $db->fetch_first(“select username,password from uc_members where uid = ‘$uid'”)){
$discuz_uid = $uid;
$discuz_pw = $arr[‘password’];
$discuz_user = $arr[‘username’];
}
}
include_once ‘./bbs/forumdata/cache/cache_settings.php’;
@extract($_DCACHE[‘settings’]);
$discuz_auth_key = md5($_DCACHE[‘settings’][‘authkey’].$_SERVER[‘HTTP_USER_AGENT’]);
define(‘FORMHASH’, formhash());
$link_logout = ‘/bbs/logging.php?action=logout&formhash=’.FORMHASH;
将上面生成的常量FORMHASH,放到SNS站点登陆表单中<input type=”hidden” name=”formhash” id=”formhash” value=”{FORMHASH}” />
在这个登陆表单中再加入两个隐藏的参数,以用作DZ登陆
<input type=”hidden” name=”cookietime” id=”cookietime” value=”2592000″ />
<input type=”hidden” name=”loginfield” id=”loginfield” value=”username” />
然后当别人在点击登陆SNS站点时,用JS实现同步模拟DZ论坛登陆
<script>
function regsubmit(){
$.post(“ajax_jq.php?action=get_uc_username”,{email:$(“#username”).val()},function(xml){
$.post(“/bbs/logging.php?action=login&loginsubmit=true”,{formhash: $(“#formhash”).val(),cookietime:$(“#cookietime”).val(),loginfield:$(“#loginfield”).val(),username: $(“result”,xml).text(),password:$(“#password”).val(),ajax:true});
});
}
</script>
JS中的ajax_jq.php?action=get_uc_username的功能就是根据用户输入的邮箱名找到UCenter中的用户,并回传出来,如下:
if($action == “get_uc_username”){
$email = $_POST[’email’];
if(!isemail($email)){
ajax_show_xml(“你的登陆邮箱名输入不正确。”);exit;
}else{
if($arr = $db->fetch_first(“select username from uc_members where email = ‘$email'”)){
ajax_show_xml($arr[‘username’]);exit;
}
}
}
这里需要用到函数ajax_show_xml(),此函数可以在gloabal.func.php找到,功能是将传入的参数变成XML文件,以便于回传。
5、当退出DZ论坛时,同时也退出SNS站点,在位置/bbs/logging.php 中的页面上方,有$action == ‘logout’字样的下面,添加语句dsetcookie(“uid”,””,-864000*365);
6、当退出SNS站点时,同时也退出DZ论坛,这里DZ有一个非常复杂的退出验证及处理,大体是为了COOKIE与SESSION能同步处理成退出状态,为此,DZ设置了一个formhash,
此formhash其实与前面登陆时要用到的formhash的生成原理是一样的,但此函数所需的参数,却又模拟不出来,与登陆时一样,要真正解决此问题,除非从一开始SNS站
点就是在一个完整的DZ上开发出来的,但这是不太可能的。所以,这里我们只能再来模拟一次DZ论坛的退出。
其实就是访问一下这个链接/bbs/logging.php?action=logout&formhash=2fafe52f
这里看上去简单,但参数formhash包含的信息非常广(如$discuz_user, $discuz_uid, $discuz_pw),要在SNS站点上模拟出这个fomrhash字符串,则需要摸索清楚DZ
的加密功能及那些数都数不清的参数间是如何调用,但这几乎是一个不可能的事情(研究时,差点就卡死在这里了。。。。)。
后来想到,这个formhash参数,是在DZ页头文件common.inc.php中生成的,那我在调用链接/bbs/logging.php?action=logout&formhash=2fafe52f时,不管我传入的这
个formhash参数是否正确,那个正确的formhash总应该是在common.inc.php文件中的,而且,退出登陆这功能,只要能成功退出就行,不需要考虑太多安全因素。所以,
我用了下面这个方法:
位置:/bbs/logging.php文件中$action == ‘logout’字样的下方第一行,加入:$formhash = FORMHASH;
当别人点击退出按钮时,同时执行一次上面链接即可
<a href=”$link_logout” onclick=”javascript:dzlt_logout(‘/bbs/logging.php?action=logout& formhash=2fafe52f’);”>退出</a>
//用JS模拟退出DZ论坛 function dzlt_logout(p){$.post(‘p’);}
总结:
经过以上六步,最终我们实现了SNS站点与DZ论坛,在注册、登陆、退出时的同步操作。
附件:
1、DZ论坛注册时,填入bbs_members数据表中的用户密码,是一个随机码,没有任何意义,不需要在此问题上多做研究,真正的用户密码是存放在UCenter
系统中的名为uc_center的数据表中。
2、DZ的用户密码的加密算法是$salt = substr(uniqid(rand()), -6);$password = md5(md5($password).$salt);然后将$salt存入数据库,以后每次判断登陆时,
都必须先取出该用户名的salt值,再与现在登陆时输入的密码,进行加密,看结果与数据库中存入的密码字符串是否相符合。所以,在SNS站点的用户信息数据表
中,也必须有salt这个字段,以保存密码加密字符,当然,加密算法也应该是一样才好。
转载请注明:苏demo的别样人生 » 完美解决DZ论坛整合