可能这个标题起的不是太好,但是也不知道怎么写了,算了就这样吧,反正这个也不是今天的重点,今天想说的是怎么实现在任意页面下实现登陆Discuz!论坛。如果你是想看怎么实现和看源码的话,请直接下载附件,以下内容你可以不用看了,如果你想学习PHP的会话机制和Discuz!是怎么实现会话机制的,请浪费你一点时间,接着向下看。
―――――――――――――――――――――――――神奇的分割线――――――――――――――――――――――――――――
1、 首先介绍一些PHP的常用概念,如果你对PHP有一定的了解,这部分就不要看了。
 变量的范围
1) 超局变量――特指一些PHP内置的变量,例如:$_GET/$HTTP_GET_VARS 这些变量可以在所有的PHP页面下直接调用。
2) 全局变量――指整个页面下随便调用的变量,例如不在函数过程下的变量以及在函数过程下声明为global 的变量,像Discuz!的$Discuz_uid/$Discuz_user都是全局变量。
3) 局部变量――指的是函数下没有声明为golbal的变量,注:局部变量和全局变量可以同名,但是如果没有声明为golbal变量,则PHP将认为是2个不同的变量,虽然名字相同。
 PHP的会话(session)机制实现方式
注意:关于会话这个概念不想多说什么了,可以查找相关书籍和资料,不是1句2句能说清的,固不放在这里讨论了。你只要知道会话就是客户端-浏览器和服务端-web服务器一次完整交流信息,例如从打开浏览器访问Discuz论坛(会话开始),经过一系列的操作,到最后关闭浏览器或者关闭所访问的Discuz论坛页面或者超出一定的时间自动断开,也就是不在和Discuz论坛页面交流信息(会话结束),这就是一个完整的会话。
今天讨论的就是怎么维持一个人的会话呢?我认为php可以通过以下几种方式实现(可能不是太全面,请一些高人大大指点):
1) Ip地址――通过获取$REMOTE_HOST和$REMOTE_ADDR来维持一个会话,但是如果是n个用户通过代理服器和路由器来上网的话,这个方式就不那么好用了。
2) 隐藏变量――通过表单的传递机制或者链接机制,将维持会话的信息传递到下一个要访问的页面。简单的例子:
表单机制- <form action=”1.php” method=”post”>
- <input type=”hidden” name=”hidden_var” value=”要传递的信息”>
- ……
- ……
- </form>
复制代码 链接机制- <a href=”1.php? hidden_var=要传递的信息”>链接</a>
复制代码 这样就将要传递的信息送到了1.php,可以继续通过这个信息来维持会话。但是这2个方式必须建立在每个页面都要有一个表单或者都要有能传递信息到下一个页面的链接,很明显这种机制不是那么安全,一旦被人获悉你的信息,那么就可以伪造,所以要在你要传递的信息做好加密手段。经典的范例,Discuz的后台控制就是通过这个方式实现维持会话的。(如果你是为了学习PHP以及利用PHP维持会话,我支持你的研究,如果你为了某种不同的目的,对不起,请你离开,这非我写本文的初衷)
3) 通过cookie――就是通过PHP将一些信息写到客户端cookie里,客户端每次访问一个网站,就会将某个网站的cookie里的信息自动送给所访问的服务器,在PHP中是通过$_COOKIE(老版PHP)和$HTTP_COOKIE_VARS(新版PHP)记录客户端的cookie信息,然后通过获取的cooike记录的信息来维持会话。使用Cooike维持会话的经典教科书――Discuz!论坛前台维持会话。
―――――――――――――――――――――――――――又一次的现身-神奇的分隔线――――――――――――――――――――――――
2、 现在来讨论讨论Discuz!论坛怎么通过cookie实现维持会话的!还是那句话,不想看可以不看。
 首先,你要了解setcookie这个PHP内置函数,这个可以到网上查一些资料,我这里就不多说了。
 Discuz!控制会话所用的php文件:include/commin.php、include/ global.func.php(其实是里面的2个主要函数dsetcookie和updatesession,还有编码的authcode)和登陆/登出控制logging.php。用到的数据表cdb_sessions。
 下面是一个流程图(个人的观点,不一定对,希望有人给出指正)请看附件
 我们按照给出的流程图来分析Discuz!代码
1) 获取cookie信息
- $sid = daddslashes(($transsidstatus || (defined('CURSCRIPT') && CURSCRIPT == 'wap'))&& (isset($_GET['sid']) || isset($_POST['sid'])) ?
- (isset($_GET['sid']) ? $_GET['sid'] : $_POST['sid']) :
- (isset($_DCOOKIE['sid']) ? $_DCOOKIE['sid'] : ''));
- $discuz_auth_key = md5($_DCACHE['settings']['authkey'].$_SERVER['HTTP_USER_AGENT']);
- list($discuz_pw, $discuz_secques, $discuz_uid) = isset($_DCOOKIE['auth']) ? explode("\t", authcode($_DCOOKIE['auth'], 'DECODE')) : array('', '', 0);
复制代码 以上代码就是用来获取cookie信息,至于cookie的信息是怎么生成的不是我这里要讨论的,只要知道这个是用来做什么就可以了。
2) 判断cookie信息
- if($sid) {
- ……省略代码,详细代码查看include\common.inc.php
- }
- 以及后续代码
- if(!$sessionexists) {
- ……省略代码,详细代码查看include\common.inc.php
- }
复制代码
3) 其他操作就不是我们要讨论的,略过。
4) 登陆/登出判断就是由logging.php控制的。
- if($action == 'logout' && !empty($formhash) && $formhash == FORMHASH) {
- //清除cookie
- clearcookies();
- ……
- //登出消息提示
- showmessage('logout_succeed', dreferer());
- } elseif($action == 'login') {
- if($discuz_uid) {
- showmessage('login_succeed', $indexname);
- }
- ……
- if(!submitcheck('loginsubmit', 1, $seccodecheck)) {
- ……
- include template('login'); //载入登陆界面
- } else {
- ……
- //设置cookie信息
- dsetcookie('cookietime', $cookietime, 31536000);
- dsetcookie('auth', authcode("$discuz_pw\t$discuz_secques\t$discuz_uid", 'ENCODE'), $cookietime);
- ……
- if($groupid == 8) { //登陆判断
- showmessage('login_succeed_inactive_member', 'memcp.php');
- } else {
- //正常登陆显示消息
- showmessage('login_succeed', dreferer());
- }
- } elseif(empty($secques)) { //安全问题判断
- ……
- //载入安全页面
- include template('login_secques');
- dexit();
- }
- }
- ……
- //错误信息判断
- showmessage('login_invalid', NULL, 'HALTED');
- }
- } else {
- //其他未定义信息
- showmessage('undefined_action');
- }
复制代码
5) 看了“4)”的内容,估计会问并没有更新会话信息,不要着急,看你们模版的footer.htm里面肯定有一句:
- ……
- {eval updatesession();}
- ……
复制代码
就是我上面提到的updatesession()函数,至于怎么实现也不是我们这里要讨论的,有兴趣你们下面自己研究,还是那句老话,为了学习研究,我非常支持,至于别的目的,我不欢迎,请你走开。
6) 至于结束会话只是我为了讲解整个流程,而加上去,这个不是由什么控制或者判断的,客户端一直和服务端交流信息,也就是会话一存在,一但不交流信息也就意味着会话结束了。
7) 看到这里还有兴趣向下看的,我在这里谢谢你的支持,下面就是我说的重点了,明白了Discuz!维持会话的机制,也就更加容易实现一些特出的需要,请向下看。
――――――――――――――――――――――又一次的现身-神奇的分隔线―――――――――――――――――――――――――――――
3、应用(不知道叫什么好,姑且叫应用吧)
看到ss(supesite)和Discuz整合到一块,想不想自己的一些原有的网站和discuz!论坛整合到一块呢?如果有此想法,往下看,我将举一个例子:
假如我有一个图书站点(具体可以看起点、幻剑这些大的网站),想通过论坛的积分实现会员查看不同的书籍(这样你就相当于有了积分消费和积分购买系统,完全不用自己在费心费力的做了,多么简单啊,就等着Discuz!大大们给我们完善会员管理和积分管理,偷懒偷懒,呵呵),但是我这里的会员还有别一些设置,完全可以新做一个数据表,只要把cdb_members下的id拷贝过来,其他什么登陆/注册完全交给discuz!做,只要设置这个id的权限,ok了,一个新的会员系统出炉了,这样我们就可以建立什么书柜、收藏夹、其他一些功能,只要登陆以后我们也按照Discuz会话机制维持会话,就可以实现图书系统和论坛系统的跳转,图书系统的设定完全不用考虑Discuz!论坛。
上面讲到只是一个概念,大家可以结合我给出的附件,自行设置,希望能对有上面需求的朋友一些帮助。
至于所谓的任意窗口登陆,就更加容易了,直接把我给出的附件放在你所要的位置即可。
―――――――――――――――――――――――――――又一次的现身-神奇的分隔线――――――――――――――――――――――――
下面讲解下我的附件,我是在discuz!5.0测试,文件路径:
[code]test_login.php 是http://xxxx/test.login.php
ctrl_login.php 是http://xxxx/bbs/ctrl_login.php[code]
请参照以上路径放置。
[ 本帖最后由 hnxxwyq 于 2006-11-27 09:33 编辑 ] |