优化Discuz!6.1的RSS

标签:Discuz!, PHP, RSS

这些天用Google阅读器发现一个问题,仅管我的论坛设为60分钟更新一次RSS,但经常几天才会在阅读器上看到一次更新。于是检查了一下rss.php,发现果然是discuz的bug导致。

相信很多discuz的站长都遇到过进入RSS页面什么帖都不显示,但刷新下就显示出来了的情况。
原因就在于discuz生成RSS页面时会判断是否需要更新,当访问RSS页面时距上次更新超过后台所设置的TTL时间时,discuz就会自动更新RSS的数据;但更新完后就直接退出了,而不会输出数据!
所以当阅读器第一次访问时,只获取了论坛的基本信息。之后,阅读器根据获得的TTL,决定在TTL分钟后再次访问;但下次访问时,discuz会发现需要更新数据了,所以又只给阅读器基本信息。如果你的论坛有很多人订阅,那倒没关系;如果只有1个人订阅,那可能一辈子都收不到更新!

懂php的应该都看得懂rss.php中的这段代码吧:
if($fidarray) {
	$query = $db->query("SELECT * FROM {$tablepre}rsscaches WHERE fid IN (".implode(',', $fidarray).") ORDER BY dateline DESC LIMIT $num");
	if($db->num_rows($query)) {
		while($thread = $db->fetch_array($query)) {
			if($timestamp - $thread['lastupdate'] > $ttl * 60) {
				updatersscache();
				break;
			} else {
				echo 	"    <item>\n".
					"      <title>".dhtmlspecialchars($thread['subject'])."</title>\n".
					"      <link>{$boardurl}viewthread.php?tid=$thread[tid]</link>\n".
					"      <description><![CDATA[$thread[description]]]></description>\n".
					"      <category>".dhtmlspecialchars($thread['forum'])."</category>\n".
					"      <author>".dhtmlspecialchars($thread['author'])."</author>\n".
					"      <pubDate>".gmdate('r', $thread['dateline'])."</pubDate>\n".
					"    </item>\n";
			}
		}
	} else {
		updatersscache();
	}
}
我们所要做的,就是在执行updatersscache()后,再次从数据库中取数据,然后输出。

用下面的代码替换上述代码即可:
if($fidarray && !fetchthread()) {
	updatersscache();
	fetchthread();
}

function echothread($thread) {
	global $boardurl;
	echo
	"    <item>\n".
	"      <title>".dhtmlspecialchars($thread['subject'])."</title>\n".
	"      <link>{$boardurl}viewthread.php?tid=$thread[tid]</link>\n".
	"      <description><![CDATA[$thread[description]]]></description>\n".
	"      <category>".dhtmlspecialchars($thread['forum'])."</category>\n".
	"      <author>".dhtmlspecialchars($thread['author'])."</author>\n".
	"      <pubDate>".gmdate('r', $thread['dateline'])."</pubDate>\n".
	"    </item>\n";
}

function fetchthread() {
	global $timestamp, $num, $tablepre, $db, $ttl, $fidarray;
	static $first = TRUE;
	$query = $db->query("SELECT * FROM {$tablepre}rsscaches WHERE fid IN (".implode(',', $fidarray).") ORDER BY dateline DESC LIMIT $num");
	if($db->num_rows($query)) {
		while($thread = $db->fetch_array($query)) {
			if($first && $timestamp - $thread['lastupdate'] > $ttl * 60) {
				$first = FALSE;
				updatersscache();
				fetchthread();
				break;
			} else {
				$first = FALSE;
				echothread($thread);
			}
		}
		return TRUE;
	}
	return FALSE;
}
接下来,如果你的论坛开启了伪静态,请按如下方式替换:
搜索
<link>{$boardurl}viewthread.php?tid=$thread[tid]</link>\n".
改为
<link>{$boardurl}thread-$thread[tid]-1-1.html</link>\n".
搜索
<link>{$boardurl}forumdisplay.php?fid=$rssfid</link>\n".
改为
<link>{$boardurl}forum-$rssfid-1.html</link>\n".
顺便说下那个$num = 20;,如果你的论坛新主题发得很频繁,可以适当增大该值。假设你的论坛每小时有50个新主题,TTL为30分钟,那么你的$num应不低于50×60÷30=100。

此外,我还觉得自动生成的那一串地址很长,例如http://www.keakon.cn/bbs/rss.php?auth=9a26GCBlk8hZq83%2BxYTVIuEUcsYlNku6nqn1htmUzngW2UAFUcYxRa(注意,我有做更改。)
在rss.php中发现auth后的那串东西其实是一串加密后的验证码,有了这串东西,就获得了生成你所能访问版块和帖子的权限,有可能比游客或一般会员生成的更多。
但这一长串实在很麻烦,如果你的论坛可让游客浏览大部分内容,那大可删掉这串东西。实在有需要,你也可以生成2种地址,供会员自行选择。

删除的办法:打开discuz.htm和forumdisplay.htm,搜索&auth=$rssauth,删掉即可。
不过head中还有个rss的link,可以在index.php中将'rss.php?auth='.$rssauth."改为"rss.php,forumdisplay.php中将'&auth='.$rssauth.删掉。请注意其中的引号和小数点不要遗漏或添加。

最后,由于每次访问RSS页面,都会读取1~2次数据库。虽说rsscaches是个很小的表,但如果你的订阅数很多(例如超过1000),TTL又很短的话,也是很影响性能的。
如果不考虑访问权限的话,可以定期生成一个rss.xml文件,稍微修改下就可以用discuz自带的计划任务实现了。
不过已经很晚了,我懒得做了。等哪天有很多人订阅时再去改吧…

0条评论 你不来一发么↓

    想说点什么呢?