分类 代码分析 下的文章

Discuz! x2更新DIY模板分析

碰到一个DIY模板更新的问题,顺便分析了下更新的机制,整理记录下来了就。

哪些是DIY模板呢?
DIY模板加载的代码比较特殊,具体格式类似下面

include template('diy:***');

***为其他内容,不限。
如加载论坛首页的代码:

include template('diy:forum/discuz:'.$gid);

模板是如何加载的呢?
这里不对x2默认的模板加载方式进行分析,只针对DIY部分的更新加以说明。
找到source/function/function_core.php文件,找到template函数,在函数里可找到如下代码:

if($tpldir == 'data/diy' && ($tplrefresh ==1 || ($tplrefresh > 1 && !($_G['timestamp'] % $tplrefresh))) && filemtime($diypath.$file.'.htm') < filemtime(DISCUZ_ROOT.TPLDIR.'/'.($primaltpl ? $primaltpl : $oldfile).'.htm')) {
	if (!updatediytemplate($file)) {
		unlink($diypath.$file.'.htm');
		$tpldir = '';
	}
}

这段就是判断如果是DIY模板,同时满足更新条件,则更新相应的DIY模板。
更新的操作为updatediytemplate($file)。
还是在function_core.php文件里,找到updatediytemplate函数,代码如下:

function updatediytemplate($targettplname = '') {
	global $_G;
	$r = false;
	$where = empty($targettplname) ? '' : " WHERE targettplname='$targettplname'";
	$query = DB::query("SELECT * FROM ".DB::table('common_diy_data')."$where");
	require_once libfile('function/portalcp');
	while($value = DB::fetch($query)) {
		$r = save_diy_data($value['primaltplname'], $value['targettplname'], unserialize($value['diycontent']));
	}
	return $r;
}

common_diy_data表里存放的就是DIY数据,数据格式类似如下:

这里会从common_diy_data中查出更新的源文件和目前文件。

找到source/function/function_portalcp.php,找到save_diy_data函数,有如下代码:

function save_diy_data($primaltplname, $targettplname, $data, $database = false, $optype = '') {
	global $_G;
	if (empty($data) || !is_array($data)) return false;
	checksecurity($data['spacecss']);
	$file = ($_G['cache']['style_default']['tpldir'] ? $_G['cache']['style_default']['tpldir'] : './template/default').'/'.$primaltplname.'.htm';
	if (!file_exists($file)) {
		$file = './template/default/'.$primaltplname.'.htm';
	}
	if(!file_exists($file)) return false;
	......(中间的部分省略)
	return $r;
}

注意里面的这句代码

$file = ($_G['cache']['style_default']['tpldir'] ? $_G['cache']['style_default']['tpldir'] : './template/default').'/'.$primaltplname.'.htm';

这里会以你当前使用的风格路径下的相应文件$primailtplname.htm为源文件进行更新。

云平台报调用远程接口失败的问题分析

最近帮同事排查了一个这样的问题,类似的情况貌似不少,特总结分析一下。

问题描述:
当开通或关闭某个云平台服务的时候,报如下错误信息:
调用远程接口失败。请检查您的服务器是否处于内网以及您服务器的防火墙设置。

云平台测试站点的接口文件正常,于是开始在文件里断点记录,发现程序也执行完了。
咨询了下云平台的同事,说是有可能是超时导致的。

于是进站点后台,进入chrome开发者模式下的网络选项卡,记录所有网络链接。
然后去开通或关闭某个服务,发现需要耗时8s之久,估计确实像同事说的那样是超时导致的。

问题总结:
出现此类问题的站点一般装了很多插件,更新插件缓存时耗时太久导致云平台访问超时没有正确的返回,进而报上面的错误。
解决的方法有两种:
1> 进入后台->插件下,关闭所有的插件,然后再去云平台下开通/关闭某些服务。
2> 找到source\function\function_cloud.php文件,搜索代码

require_once libfile('function/cache');
updatecache(array('plugin', 'setting', 'styles'));

改为

//require_once libfile('function/cache');
//updatecache(array('plugin', 'setting', 'styles'));

此端更改为注释掉更新缓存的代码。
然后去后台->云平台下开通/关闭某些服务,开通或关闭后还需要再到后台->工具下手动更新一下缓存。

有此问题的站长不妨按上面的方法试下。

Connection refused问题的排查

昨天改动了下开通的代码,今天上线后发现收到很多下面的报错邮件。

返回信息: 通信失败!Connection refused (111)

看了下代码,发现是fsockopen连接的时候返回的这个错误。
于是就网上搜索了下相关的错误信息,没找到类似的错误。

重新检查了遍代码,发现fsockopen的时候是直接连接的IP+端口。
在服务器上,通过curl访问对应的域名发现可以正常输出,没问题。
执行命令:

curl -I 测试域名

执行的结果:

可以看到,通过域名访问没问题。

然后换通过IP访问进行测试。
执行命令:

curl -I IP地址

执行的结果:

可以看到,通过IP访问也是没问题。

下面加上端口进行测试。
执行命令:

curl -I IP地址:端口号

执行的结果:

通过结果发现服务器没有回应,然后通过IP访问某个页面再进行测试。
执行命令:

curl -I IP地址:端口号/xx.php

执行的结果:

这里就可以清楚的看到是“couldn't connect to host”的报错。

通过域名、IP访问都有问题,加上端口后就无法访问,怀疑是端口的问题。
执行命令:

telnet IP地址 端口号

执行的结果:

通过这个结果,猜测相应服务器的这个端口没有开放。
登录相应服务器上排查后得到验证,开放相应端口,至此Connection refused的问题终于得到解决,再也没有收到类似的邮件了。

x2个人资料的隐私更新问题分析及解决方法

问题描述:
后台设置某项用户栏目的默认隐私设为公开,这里以QQ为例。
然后注册一个新会员,设置个人资料里的QQ项。
更改后台此项用户栏目QQ的默认隐私为保密,但是此用户的空间里仍显示QQ项。

 

问题原因:
在source\module\forum\forum_viewthread.php文件判断隐私的地方并未对某项资料的全局隐私做判断,代码如下:

if(!empty($post['privacy']['profile'][$field])) {
	continue;
}

这里仅判断了用户此项资料的隐私设置,如果存在就跳出,不予显示,但是这里并未对这项资料的全局隐私做判断,会导致出现开头提到的问题。

修正方法:
在source\module\forum\forum_viewthread.php文件中,搜索下面代码

if(!empty($post['privacy']['profile'][$field])) {
	continue;
}

改为

if(!empty($post['privacy']['profile'][$field]) || $_G['setting']['privacy']['profile'][$field]) {
	continue;
}

此问题在1010版本下发现,其他版本未验证。

x2后台回收站恢复回帖时无法恢复相应用户的积分问题分析

问题描述:
在后台->内容->回帖回收站下恢复回帖时,无法恢复对应回帖用户的积分(相应用户的积分不增加)。

问题分析:
找到source\function\function_misc.php文件
搜索代码

updatepostcredits('+', $ruidarray, $creditspolicy['reply']);

查看updatepostcredits函数的定义,发现第三个参数错误。
应该改为

updatepostcredits('+', $ruidarray, 'reply');

此问题在1010版本下发现,其他版本未验证。