分类 代码分析 下的文章

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!的QQ互联版本区别

Discuz! 的QQ互联共分为三个版本:Mysql版QQ互联、云平台版的QQ互联和空间版的QQ互联,其中插件版的QQ互联属于空间版的QQ互联。

Mysql版的QQ互联

这个版本是Discuz! 推出的最早版本的QQ互联,属于内测产品,并未大规模开放使用,仅对部分大站点开放了使用。

点击QQ登录的授权链接为:

http://dz.qzone.qq.com/cgi-bin/login?****

支持的版本有Discuz! 7.2 和 Discuz! X1.5两个版本。

云平台版的QQ互联

这个版本的QQ互联作为了Discuz! 云平台的一个服务推出给了广大站长。

点击QQ登录的授权连接为:

http://connect.discuz.qq.com/oauth/authorize?****

支持的版本有Discuz! X1.5.1 和 Discuz! X2两个个版本。

空间版的QQ互联

由于腾讯全面开放了QQ互联服务(http://connect.qq.com/),所以Discuz! 版的QQ互联也逐渐迁移到了腾讯的标准Oauth互联下。

点击QQ登录的授权连接为:

http://openapi.qzone.qq.com/oauth/qzoneoauth_authorize?****

支持的版本有Discuz! 7.2(集成到了云平台服务中) 、 Discuz! X1.5(QQ互联插件包) 和 Discuz! X2.5(集成到了云平台服务中)三个版本。

SVN的“local edit, incoming delete upon update”问题

多人开发中都会采用svn提交代码,方便又可以保证多人的代码不会被覆盖。

这次在开发过程中,遇到一个“local edit, incoming delete upon update”的问题,搜索一番后才找到解决方法,特地记录。

同事删除了文件并且提交了,而我又修改了我本地的文件,所以在我使用svn status查看状态的时候就出现了一个下面的信息:

! C ***/**/abc.php
> local edit, incoming delete upon update

解决方法:
确定把自己的代码合并到相应的文件后,执行下面的命令:

svn revert ***/**/abc.php

删除本地文件的编辑信息,然后再执行下面的删除文件命令:

rm ***/**/abc.php

QQ互联插件乱码问题解决

最近发现论坛有人反应QQ互联插件乱码,出于以往的经验,是由于安装时与站点编码不一致导致。
关键现在安装的时候会自动选择与站点编码一致的xml文件安装,实在搞不懂为啥还会出现这类问题,焦虑了,有问题的站长不妨把你的安装过程详细写下来,方便我们排查是否是bug。

由于QQ互联是系统插件,是无法卸载和重新安装的,必须要通过数据库操作才能解决此类问题。

解决方法:

第一种方法:

1.根据您网站的编码,选择执行下面对应的sql(需要在数据库里执行)。
简体GBK编码的站点:

UPDATE pre_common_plugin SET modules = 'a:6:{i:0;a:10:{s:4:"name";s:7:"connect";s:4:"menu";s:0:"";s:3:"url";s:0:"";s:4:"type";s:2:"11";s:7:"adminid";s:1:"0";s:12:"displayorder";s:1:"0";s:8:"navtitle";s:0:"";s:7:"navicon";s:0:"";s:10:"navsubname";s:0:"";s:9:"navsuburl";s:0:"";}i:1;a:10:{s:4:"name";s:7:"spacecp";s:4:"menu";s:6:"QQ绑定";s:3:"url";s:0:"";s:4:"type";s:1:"7";s:7:"adminid";s:1:"0";s:12:"displayorder";s:1:"1";s:8:"navtitle";s:0:"";s:7:"navicon";s:0:"";s:10:"navsubname";s:0:"";s:9:"navsuburl";s:0:"";}i:2;a:10:{s:4:"name";s:6:"qqshow";s:4:"menu";s:4:"QQ秀";s:3:"url";s:0:"";s:4:"type";s:1:"7";s:7:"adminid";s:1:"0";s:12:"displayorder";s:1:"2";s:8:"navtitle";s:0:"";s:7:"navicon";s:0:"";s:10:"navsubname";s:0:"";s:9:"navsuburl";s:0:"";}i:3;a:10:{s:4:"name";s:7:"connect";s:4:"menu";s:0:"";s:3:"url";s:0:"";s:4:"type";s:2:"28";s:7:"adminid";s:1:"0";s:12:"displayorder";s:1:"0";s:8:"navtitle";s:0:"";s:7:"navicon";s:0:"";s:10:"navsubname";s:0:"";s:9:"navsuburl";s:0:"";}s:6:"system";i:2;s:5:"extra";a:2:{s:11:"installtype";s:6:"SC_GBK";s:10:"langexists";i:1;}}' WHERE name = 'QQ互联';

简体UFT-8编码的站点:

UPDATE pre_common_plugin SET modules = 'a:6:{i:0;a:10:{s:4:"name";s:7:"connect";s:4:"menu";s:0:"";s:3:"url";s:0:"";s:4:"type";s:2:"11";s:7:"adminid";s:1:"0";s:12:"displayorder";s:1:"0";s:8:"navtitle";s:0:"";s:7:"navicon";s:0:"";s:10:"navsubname";s:0:"";s:9:"navsuburl";s:0:"";}i:1;a:10:{s:4:"name";s:7:"spacecp";s:4:"menu";s:6:"QQ绑定";s:3:"url";s:0:"";s:4:"type";s:1:"7";s:7:"adminid";s:1:"0";s:12:"displayorder";s:1:"1";s:8:"navtitle";s:0:"";s:7:"navicon";s:0:"";s:10:"navsubname";s:0:"";s:9:"navsuburl";s:0:"";}i:2;a:10:{s:4:"name";s:6:"qqshow";s:4:"menu";s:4:"QQ秀";s:3:"url";s:0:"";s:4:"type";s:1:"7";s:7:"adminid";s:1:"0";s:12:"displayorder";s:1:"2";s:8:"navtitle";s:0:"";s:7:"navicon";s:0:"";s:10:"navsubname";s:0:"";s:9:"navsuburl";s:0:"";}i:3;a:10:{s:4:"name";s:7:"connect";s:4:"menu";s:0:"";s:3:"url";s:0:"";s:4:"type";s:2:"28";s:7:"adminid";s:1:"0";s:12:"displayorder";s:1:"0";s:8:"navtitle";s:0:"";s:7:"navicon";s:0:"";s:10:"navsubname";s:0:"";s:9:"navsuburl";s:0:"";}s:6:"system";i:2;s:5:"extra";a:2:{s:11:"installtype";s:7:"SC_UTF8";s:10:"langexists";i:1;}}' WHERE name = 'QQ互联';

2.执行完上述sql后,进入站点后台-》工具下,点击更新缓存。

第二种方法:

如果第一种方法执行后不起效,您进入您网站目录/source/plugin/qqconnect目录下,检查是否存在discuz_plugin_qqconnect.xml文件。
如果存在,则可以按下面的方法再试下。
不需要区分网站编码,执行下面的sql:

UPDATE pre_common_plugin SET modules = 'a:6:{i:0;a:10:{s:4:"name";s:7:"connect";s:4:"menu";s:0:"";s:3:"url";s:0:"";s:4:"type";s:2:"11";s:7:"adminid";s:1:"0";s:12:"displayorder";s:1:"0";s:8:"navtitle";s:0:"";s:7:"navicon";s:0:"";s:10:"navsubname";s:0:"";s:9:"navsuburl";s:0:"";}i:1;a:10:{s:4:"name";s:7:"spacecp";s:4:"menu";s:6:"QQ绑定";s:3:"url";s:0:"";s:4:"type";s:1:"7";s:7:"adminid";s:1:"0";s:12:"displayorder";s:1:"1";s:8:"navtitle";s:0:"";s:7:"navicon";s:0:"";s:10:"navsubname";s:0:"";s:9:"navsuburl";s:0:"";}i:2;a:10:{s:4:"name";s:6:"qqshow";s:4:"menu";s:4:"QQ秀";s:3:"url";s:0:"";s:4:"type";s:1:"7";s:7:"adminid";s:1:"0";s:12:"displayorder";s:1:"2";s:8:"navtitle";s:0:"";s:7:"navicon";s:0:"";s:10:"navsubname";s:0:"";s:9:"navsuburl";s:0:"";}i:3;a:10:{s:4:"name";s:7:"connect";s:4:"menu";s:0:"";s:3:"url";s:0:"";s:4:"type";s:2:"28";s:7:"adminid";s:1:"0";s:12:"displayorder";s:1:"0";s:8:"navtitle";s:0:"";s:7:"navicon";s:0:"";s:10:"navsubname";s:0:"";s:9:"navsuburl";s:0:"";}s:6:"system";i:2;s:5:"extra";a:2:{s:11:"installtype";s:0:"";s:10:"langexists";i:1;}}' WHERE name = 'QQ互联';

执行完后,进入站点后台-》工具下更新缓存。

Discuz官方原文地址:
http://www.discuz.net/thread-2940572-1-1.html

如果还有问题请到Discuz官方原问跟帖回复。 :)