彼岸网

 找回密码
 立即注册
搜索
热搜: 活动

tag 标签: 管理中心

相关帖子

版块 作者 回复/查看 最后发表

没有相关内容

相关日志

分享 分析Discuz系统安装后无法登录UCenter问题
热度 2 天香公主 2016-12-10 01:32 AM
分析Discuz系统安装后无法登录UCenter问题
最近遇到了一个奇怪的Discuz/UCenter问题。我在服务商namecheap提供的测试网站上全新安装的Discuz 3.2 系统里登录管理中心后,点击最后一个tab来登录与Discuz一同安装的UCenter出现问题,几乎每次填写了UCenter创始人的密码(就是在安装Discuz设的管理员密码)后点击登录后又回到了该登录页。但如果不断的重复登录的话,多试几次也会有一次成功,但是进去后点击网页上任何链接后就又被推回了登录页。而在我自己本地机器上安装的Discuz/UCenter里则从无这类问题。这是怎么回事呢? 让我们先来查下有关代码。在填写了UCenter创始人密码点击登录后,向服务器发送的请求是 admin.php?m=usera=login 最终检查密码正确性的代码在文件 uc_server/control/admin/user.php 里的函数 control.onlogin 中,其中关键部分是在确认了用户提供的密码是正确的后从用户名(如果是创始人的话,用户名自动定为UCenterAdministrator)产生了一个 sid(估计意为 session id): xmp { white-space: pre-wrap; display: block; border: 1px solid lightgrey; padding: 5px;} sid)); exit; 这些代码表明 sid 被同时放入了 query string 和 cookie 中。以图中的数据为例: query string 中的 sid: f70blEiCdTNvsQpCEXhME6PPP9dSXxCg5W9kFeISvc9K11%2FjGmcOPPyrtfYymtqKVMXuBBlsOi5GNw cookie 中的 sid: f70blEiCdTNvsQpCEXhME6PPP9dSXxCg5W9kFeISvc9K11%252FjGmcOPPyrtfYymtqKVMXuBBlsOi5GNw 两者有个细微的差别,前者有的 % 在后者里变成了 %25。其原因是代码用的设置的办法是基于PHP的 setcookie 函数,它自动将提供的内容做了一次 url 编码( 链接 ): Note that the value portion of the cookie will automatically be urlencoded when you send the cookie, and when it is received, it is automatically decoded and assigned to a variable by the same name as the cookie name. If you don't want this, you can use setrawcookie() instead if you are using PHP 5. 当用户登录成功后,服务器端的代码向客户端发送了一个redirect指令。这样客户端接受了cookie后向服务器端发了一个query string和cookie中都带着sid(但有上面提到的细微差别)的请求 admin.php?m=framea=mainiframe=1sid=..., 在服务器收到这个请求后会检查发送过来的sid从中找到用户名。但在这一步上Discuz出了问题,没能找到用户名。问题出来哪里呢?让我们看一下相关的代码,在文件 uc_server/model/admin.php里的adminbase类中: sid_decode($sid) ? $sid : ''; ... } 其中函数 getgpc 的定义是 function getgpc($k, $t='R') { switch($t) { case 'P': $var = &$_POST; break; case 'G': $var = &$_GET; break; case 'C': $var = &$_COOKIE; break; case 'R': $var = &$_REQUEST; break; } return isset($var ) ? (is_array($var ) ? $var : trim($var )) : NULL; } 函数 adminbase 中的第三句说的是如果变量cookie_status的值非零,则从cookie (即 $_COOKIE)里得到sid,不然就从请求(即 $_REQUEST)里经一次 url 解码后得到sid。由于$_COOKIE在赋值时已经经过一次 url 解码,所以 getgpc('sid', 'C') 给出的是前面产生的sid,以上面的例子为例,就是 f70blEiCdTNvsQpCEXhME6PPP9dSXxCg5W9kFeISvc9K11%2FjGmcOPPyrtfYymtqKVMXuBBlsOi5GNw。那么 rawurlencode(getgpc('sid', 'R')) 是不是也给出同样的值呢?这取决于getgpc('sid', 'R') (即 $_REQUEST )是不是 f70blEiCdTNvsQpCEXhME6PPP9dSXxCg5W9kFeISvc9K11/jGmcOPPyrtfYymtqKVMXuBBlsOi5GNw。由于 $_REQUEST 在赋值时也经过一次 url 解码,所以 $_REQUEST 如果从 query string 里取值的话就能得到预期的结果,但是如果从 cookie 里取值的话就会得到错误的值 f70blEiCdTNvsQpCEXhME6PPP9dSXxCg5W9kFeISvc9K11%2FjGmcOPPyrtfYymtqKVMXuBBlsOi5GNw。 经检查发现在我的namecheap服务器上总是从cookie取得,而在我本地机器上总是从query string取得。这就是在服务器上出现问题的原因。它导致了后面使用sid_decode是得不到用户名,从而将登录用户重新带回了登录页。那么为什么在不同机器上有不同行为呢?或者说 $_REQUEST 在 cookie 和 query string 有同名变量时,应该从何者取值呢?从PHP手册 ( 链接 ) 看是这样说的: 这个次序取决于PHP设置文件 php.ini 里 variables_order 的值,如果这个值没定义的话,则取决于另一个变量 request_order 的值。 request_order string: This directive describes the order in which PHP registers GET, POST and Cookie variables into the _REQUEST array. Registration is done from left to right, newer values override older values. If this directive is not set, variables_order is used for $_REQUEST contents. 检查我的本地机器上的设置发现 request_order 是GP,所以 $_REQUEST 从 query string (即G)得到了sid。而检查我的namecheap服务器的设置发现 request_order无定义而 variables_order 的值是EGPCS,所以 $_REQUEST 从 cookie (即C)得到了sid。 故而解决办法是将前述那段代码里的第三句 cookie_status ? getgpc('sid', 'C') : rawurlencode(getgpc('sid', 'R')); 改为 cookie_status ? getgpc('sid', 'C') : rawurlencode(getgpc('sid', 'G')); 或者更保险点 cookie_status ? getgpc('sid', 'C') : (getgpc('sid', 'G')?rawurlencode(getgpc('sid', 'G')):getgpc('sid', 'C')); 网上有些帖子建议了另一种解决办法(如 链接 ),将函数 adminbase 里的第二句 cookie_status = 0; 改为 cookie_status = isset($_COOKIE ) ? 1 : 0; (而不改第三句),即将函数 adminbase 改为 sid_decode($sid) ? $sid : ''; ... } 这个代码正是单独下载的UCenter软件里的对应代码。这个改动说的是如果浏览器支持cookie(并且设置项variables_order里含有C)的话就从cookie里取sid,不支持的话就从query string里取sid (而改动前的意思是不管浏览器是否支持cookie,都从 query string 里取sid)。这种解决办法其实是有个前提就是浏览器支持cookie。不然的话还是会遇到我前面指出的问题从而仍然无法登录。所以这种改法还应该将第三句里的 'R' 改成 'G'。 当然一个网站要解决这个问题也可以不改代码而修改PHP设置里前述两个设置项的值。 另外为何用户如果不断尝试登陆最终还是能成功进去,但进去后点击任何链接就又被退回到登陆页?登陆成功是因为那次的 sid 里没有任何经 url 编码会变化的字符,因而那个 bug 就没起作用。如下图 但是登陆成功后并不是一劳永逸,因为下面的代码表明每次发送回复时有会产生新的 sid,而且它赋在了网页上每个链接路经的 query string上,而这个新的 sid 很有可能是含有在 url 编码下会变化的字符,所以点击后由于前述 bug就被推出来了。
个人分类: Discuz|2800 次阅读|4 个评论
分享 Discuz系统学习:频道和专题
热度 3 天香公主 2015-5-16 04:40 PM
Discuz系统学习:频道和专题
Discuz系统学习:频道和专题 频道(channel)不是象门户(portal),论坛,日志那样是在管理中心里的全局->站点功能里可以关闭和开启单独的站点功能。它被看成是门户功能的一部分,要在管理中心里的门户->频道栏目里建造。在那里可以选择各种频道网页模板,网站或第三方开发者还可以添加这种频道模板。 你能想象栏目众多的美中网博客首页 http://news.sinovision.net/portal.php?mod=listcatid=1 就是个频道页吗?频道页可以起两种作用:第一种是作为文章栏目,如海外天空网的新闻页 http://www.overseasky.com/bbs/portal.php?mod=listcatid=1 就是个典型的文章列表页,这种频道页可以在建造时选择文章分类单列模板或文章分类两列模板或第三方提供的频道模板,以及允许发布文章来产生。这样的频道是一类文章的总和。第二种是作为与门户页类似的聚合页,比如上面提到的美中网的博客首页,要建造这样的频道网页可以在建频道时选择频道空白模板为列表页模板名,发布文章设为否,由此产生的是一个完全由DIY来设置内容的空白页,它和门户页没有任何区别,也就是说我们可以造多个门户页。以下我将这两种频道称之为第一类频道和第二类频道。 Discuz还提供了另一个门户功能,称为专题。专题和频道的主要区别是 1)频道有上下级关系,而专题是单独的。2)频道可以成为包含文章的栏目,而专题不能。但专题页也能起和第二类频道页能起同样的作用,细微显示上的差异也可以通过修改相应的模版来调节。而频道内置的模版里显示的相关分类栏也给第二类频道页带来不便。所以我感觉用专题页比第二类频道页更合适。其它网页诸如论坛页博客页尽管也提供DIY功能,但却没有这样的自由度,一是他们上面都有一定不属于DIY控制的内容,二是Discuz也没有提供选择建造该页的模板的可能,三是它只此一页没法分出多份,把它挪为它用的话,网站就没有论坛列表页或日志列表页了。只有专题和频道能产生多份完全由DIY设置内容的网页。 我们知道网站的内容大都存在于个人博文,论坛帖子和文章里,博文可以有分类,论坛也有板块,文章也分(第一类频道)栏目。门户页本身基本上不存内容,但它把这些博文帖子文章聚合到一页上来了,让用户一目了然。缺点是如果网站用户兴趣差别太大,他们会在那里看到不想看到的内容。而如果建多个专题页(或第二类频道页,下同)的话,就能把网站内容按主题分割开来,让不同兴趣的网民各取所需。比如一个网站里的博文可以分成政治,经济,文学,艺术四类,它的论坛也有这么四个同名板块,还有二个(第一类)频道一是政经新闻二是文艺新闻。那我们可以建两个专题页,在第一个网页上放各种最新/热门/热评/推荐/置顶的政治类博文栏,经济类博文栏,政治板块栏,经济板块栏,和政经新闻栏,而第二个网页上放文学类博文栏,艺术类博文栏,文学板块栏,艺术板块栏,和文艺新闻栏。这样爱好讨论政经的网民可以进政治门户,爱好文艺的网友可以进文艺门户。 网站的内容除了频道里的文章,论坛里的主题,和博客里的博文外,还有个人的微博。如何把微博内容也分割到各专题页呢?我想网站可以给每个专题页建一个帐号 (如政经组,文艺组)交给各组的负责人用,然后那些希望自己的微博出现在某专题页上的人可以加对应该频道的帐号为好友。这样在该专题页上显示该帐号的好友微博就行了。 不难加个功能,让每个用户自行挑选他们进入网站时哪个门户是他们的默认首页。下面我们讨论一个简单的处理办法。在顶部加一个'设为本站首页'链接: 对顶部导航栏 (top navagation) 内容的调整可以在管理中心里做:界面->导航设置->顶部导航。这样加的导航项称为自定义(即网站提供)导航项对应着数据库里common_nav数表里一个type值是1的record。从/source/function/cache/cache_setting.php 里的get_cachedata_topnav函数看,除非修改代码,不然对自定义项只能定义href,而没法和内置(即Discuz软件提供)项那样有代码处理事件(如onclick)。也可以在数据库里执行下面的语句来达到同样的结果: xmp { white-space: pre-wrap; display: block; border: 1px solid lightgrey; padding: 5px;} insert into common_nav (parentid, name, title, url, identifier, type, available, displayorder, icon, subname, suburl, navtype, logo ) values (0, '设为本站首页', '', '#', 'setdefaultpage', 1, 1, 3, '', '', '', 4, '') 当点击这个链接时调用的函数定义在 /static/js/common.js 里: function setDefaultpage() { setcookie('defaultpage', window.location.href); } 最后我们在/source/function/cache/cache_setting.php 里将链接和上面这个函数联系起来: fetch_all_by_navtype(4) as $nav) { $nav = ''; if(!$nav ) { if($nav == 'sethomepage') { $nav = 'javascript:;'; $nav = ' onclick="setHomepage(\''.$_G .'\');"'; } elseif($nav == 'setfavorite') { $nav = $_G ; $nav = ' onclick="addFavorite(this.href, \''.addslashes($_G ).'\');return false;"'; } } elseif($nav == 'setdefaultpage') { $nav = 'javascript:;'; $nav = ' onclick="setDefaultpage();return false;"'; } 然后我们在管理中心将门户页设成首页,但在门户页里检查用户是否已经另设首页。有的话把他带到自己的首页。没有的话,提示用户选择首页。下面是改动后的 portal/index.htm : var url = getcookie('defaultpage'); if (url && window.location != url) window.location = url;
个人分类: Discuz|2540 次阅读|5 个评论

小黑屋|Archiver|彼岸网  

Powered by Discuz! X3.1 © 2001-2014 Comsenz Inc.
GMT-4, 2026-8-26 04:47 AM , Processed in 0.023295 second(s), 14 queries.

返回顶部