标签 Discuz 下的文章

Discuz! X1.5版本的缓存丢失问题排查

下午有同事反映之前升级的两个站点开通了QQ互联后出现缓存丢失问题,有一个站点排查发现是由于QQ昵称的特殊字符导致,整理排查过程。

问题描述:

使用QQ登录注册后(QQ昵称带有特殊字符,假设为),论坛缓存出现丢失情况,手动更新后恢复正常,丢失情况类似下图:
[caption id="attachment_971" align="alignnone" width="300"]Discuz! 缓存丢失后的页面 Discuz! 缓存丢失后的页面[/caption]

排查分析:

首先看前台显示,发现注册的“精€€ぷ灵€€”用户名显示成了“精”,进入数据库里的pre_common_member表中确定当前注册的用户名是什么,如图:
[caption id="attachment_972" align="alignnone" width="300"]用户表记录 用户表记录[/caption]

从图可以看出来,注册的“精€€ぷ灵€€”用户名到数据库里变成了“精”,推测是由于Mysql把特殊字符后面的所有东西全部干掉导致。

注册用户时会更新缓存表里的userstats记录,进入pre_common_syscache表里找到对应记录,如图:
[caption id="attachment_973" align="alignnone" width="300"]缓存表记录 缓存表记录[/caption]

从记录可以看出来,这里的序列化结果断掉了,同样的也是从特殊字符开始后面的所有东西都没有了。

至于为什么手动更新缓存就会好,是由于手动更新缓存的时候,最后注册会员的名字是从用户表中查询出来然后再序列化写入缓存表,用户表中的用户名是没有特殊字符的,所以写入缓存表的数据结构是完整的,所以缓存没有问题,有兴趣的童鞋可以参考source\function\cache\cache_userstats.php文件代码。

原因猜测:

个人猜测是由于Mysql不支持特殊字符,插入的带有特殊字符数据,Mysql会将特殊字符及后面的数据全部扔掉。
由于用户名中带有特殊字符,所以缓存表里的记录的序列化值中也会含有特殊字符,同样的抛弃特殊字符及后面的数据,就会导致序列化结构不完整,进而导致前台显示的时候由于反序列化失败导致缓存不完整。

解决方法:

修复普通注册:找到source\module\member\member_register.php文件,搜索下面的代码:

$totalmembers = DB::result_first("SELECT COUNT(*) FROM ".DB::table('common_member'));
$userstats = array('totalmembers' => $totalmembers, 'newsetuser' => $username);

save_syscache('userstats', $userstats);

改为:

require_once libfile('cache/userstats', 'function');
build_cache_userstats();

修复QQ互联注册(仅针对Discuz! X1.5的QQ互联插件):找到source\module\connect\connect_register.php文件,搜索代码:

$totalmembers = DB::result_first("SELECT COUNT(*) FROM ".DB::table('common_member'));
$userstats = array('totalmembers' => $totalmembers, 'newsetuser' => $username);

save_syscache('userstats', $userstats);

改为:

require_once libfile('cache/userstats', 'function');
build_cache_userstats();

搜索代码:

$_G['setting']['lastmember'] = $username;
save_syscache('setting', $_G['setting']);

删除这段代码。

以上的方法可以解决缓存丢失的问题,但是根本的解决方法应该是在用户注册时过滤特殊字符。

版块开启审核的情况下QQ互联无法自动同步的问题分析

下午排查发现一个站点开启了审核的情况下QQ互联无法自动同步的问题,特整理排查过程。

问题描述:

站点端开启了审核功能,所有发帖都先进入待审核状态,审核通过后才可以正常访问,发帖无法自动同步到空间和微博。

代码分析:

找到source/plugin/qqconnect/connect.class.php文件,可以搜索到如下触发自动同步的代码:

if((!getstatus($_G['forum_thread']['status'], 7) || !getstatus($_G['forum_thread']['status'], 8))
         && $_G['forum_thread']['displayorder'] >= 0 && $_G['member']['conisbind']
         && $_G['uid'] == $_G['forum_thread']['authorid']) {
    $_G['connect']['feed_log'] = DB::fetch_first("SELECT * FROM ".DB::table('connect_feedlog')." WHERE tid='$_G[tid]'");
    if($_G['connect']['feed_log']) {
        $_G['connect']['feed_interval'] = 300;
        $_G['connect']['feed_publish_max'] = 1000;
        if(getstatus($_G['connect']['feed_log']['status'], 1) || (getstatus($_G['connect']['feed_log']['status'], 2)
            && TIMESTAMP - $_G['connect']['feed_log']['lastpublished'] > $_G['connect']['feed_interval']
            && $_G['connect']['feed_log']['publishtimes'] < $_G['connect']['feed_publish_max'])) {
            $_G['connect']['feed_js'] = $feedlogstatus = true;
        }

        if(getstatus($_G['connect']['feed_log']['status'], 3) || (getstatus($_G['connect']['feed_log']['status'], 4)
            && TIMESTAMP - $_G['connect']['feed_log']['lastpublished'] > $_G['connect']['feed_interval']
            && $_G['connect']['feed_log']['publishtimes'] < $_G['connect']['feed_publish_max'])) {
            $_G['connect']['t_js'] = $tlogstatus = true;
        }

        if($feedlogstatus || $tlogstatus) {
            $status = $feedlogstatus ? setstatus(2, 1, $status) : $status;
            $status = $tlogstatus ? setstatus(4, 1, $status) : $status;
            DB::query("UPDATE ".DB::table('connect_feedlog')." SET status='$status', lastpublished='$_G[timestamp]', publishtimes=publishtimes+1 WHERE tid='$_G[tid]'");
        }
    }
}

其中的$_G['connect']['feed_js']和$_G['connect']['t_js']两个变量为控制是否触发自动同步到空间和微博的变量。
注意开头的if判断里的下面这句:

&& $_G['member']['conisbind'] && $_G['uid'] == $_G['forum_thread']['authorid']

这里要求是发帖人自己访问的时候才会触发自动同步的代码。

结论:

前面提到站点开启了审核功能,所有发帖都会先进入待审核状态,由管理人员审核通过后其他人才可以正常访问到。
当帖子被审核通过后,如果发帖人没有重新访问过自己的帖子,那么同样是不会自动同步到空间和微博的。

另外,自动同步的帖子是有时间限制的,如果发帖时间距当前时间超过12个小时,即使发帖人重新访问自己的帖子,这个时候也不会再触发自动同步了。

版主已阅插件升级到了Discuz! X2.5

闲来无事,顺便把2年前写的插件升级到Discuz! X2.5吧。

升级主要就是一些代码按Discuz! X2.5的规则重写,最麻烦的就是数据库这块。
因为论坛本身表的一些查询满足不了,所以需要新加几个方法,一开始一直纠结在要用原来表类里的底层方法,没找到好的实现方法,基本上是把原来表类里的底层方法在插件表文件里重写了一遍。后来问了下同事,看了下他们搜索的代码实现机制,发现是直接用的DB::**实现的,呃,最基本的方法被我忘了。

好吧,用DB::**重写。
剩下的可能就是一些代码整理优化和测试了,暂时不会增加设置项,和之前的版本保持一致。

过程中遇到一个问题:
如果你要新加论坛原有表的数据库方法,你插件里的数据库表文件不要跟论坛本身的表文件重名,因为Discuz!现在还不支持命名空间,否则可能会出现报错。

PS:插件已上线应用中心,地址是http://addon.discuz.com/?@dst_read.plugin

0419更新:版主已阅插件排进前10,哈哈~~~

让Discuz! X2.5版QQ互联的QQ注册跳转到完善资料页的方法

Discuz! X2.5的QQ互联增加了QQ互联游客组,使没有注册的QQ通过QQ登录后变为QQ互联游客组,可以获得一些浏览帖子内容和部分附件的权限。
当用户需要进行登录后的某项操作时,才提示他进行完善资料或者绑定已有帐号。

鉴于论坛有很多人反馈想改回原来Discuz! X2.0的注册方法,直接完善资料进行注册。
特给出一个小的修改方案予以实现,QQ登录完后跳转到完善资料页。
找到source\plugin\qqconnect\connect\connect_login.php文件,搜索代码

$utilService->redirect($referer);

改为

dheader('Location:member.php?mod=connect&referer=index.php');

云平台常见报错的解决方法

之前负责云平台版块,一直想要将云平台的常见问题总结下来方便大家排查解决问题。
由于各种原因,一直没时间全面的总结,大家遇到问题建议还是到官方论坛搜索一下,很多问题之前其实都已经解决了,并给出了相应的解决方法。

最近又发现有站长反应搬家后云平台出现问题,云平台报错如下:

出了点小错,由于站点ID/通信KEY等关键信息丢失导致Discuz!云平台服务出现异常,使用诊断工具检测站点ID和KEY,如有疑问请访问官方论坛寻求帮助

搬家同时更换了域名的情况:
1.有搬家前的数据库备份的情况,在备份数据中执行下面的sql。

SELECT `svalue` FROM `pre_common_setting` WHERE `skey` in ('my_siteid', 'my_sitekey')

查询出来的为当前的站点ID、KEY,请做好这两个值的备份。
然后进入新域名站点后台->云平台->诊断工具下,点击手动修改站点ID/KEY,如图。
[caption id="attachment_740" align="alignnone" width="300" caption="云平台诊断工具"]云平台诊断工具[/caption]

在弹层里填入前面查询的站点ID和站点KEY,同时将云平台的状态改为已开通,提交保存。
[caption id="attachment_741" align="alignnone" width="300" caption="云平台诊断工具"]云平台诊断工具[/caption]

然后进入新域名站点后台->云平台->站点信息下,点击同步站点信息。同步成功后,您的站点ID对应的域名就变成了您的新域名。

2.没有搬家前的数据库备份的情况,请将原来开通云平台的域名重新指向新域名的站点。然后通过老域名访问站点后台->云平台->诊断工具,点击手动修改站点ID/KEY,如图。
[caption id="attachment_742" align="alignnone" width="218" caption="云平台诊断工具"]云平台诊断工具[/caption]

在弹层里将站点ID/KEY删掉,同时将云平台的状态改为尚未开通云平台,提交保存。如果您的诊断工具里的状态没有站点ID/KEY,同时云平台状态已经是尚未开通就不用进行前面的操作。

然后使用老域名进入站点后台->云平台->云平台首页进行开通云平台,这时候会提示重复注册。按提示下载修复文件,然后上传到网站根目录下,使用老域名访问修复文件,按照提示找回站点ID/KEY即可。找回后,使用新域名访问站点后台->云平台->站点信息,点击同步站点信息。同步成功后,您的站点ID对应的域名就变成了您的新域名。

只是进行搬家,并没更换域名的情况:
您可以按上面的第2种方法进行自行找回ID/KEY。

其他情况请到官方发帖求助,请求官方协助解决。