Discuz!官方免费开源建站系统

 找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索

史上第一强:Discuz!5.5源代码分析源代码分析系列(6)-积分系统代码分析(上)

[复制链接]
郭鑫 发表于 2007-6-3 13:23:47 | 显示全部楼层 |阅读模式
申明下版权:
1.这里面的每个中文字都是我打的,code部分是引用的,当然我也加了一点注释在里面了。
2.如果要转载的话请注明
  1. 转自[url]discuz.dismall.com[/url] 作者:郭鑫
复制代码

3.由于我个人的能力有限,写这篇文章没有参考一点资料,甚至连本地环境也没有搭建(遇到了白屏问题),所以难免会有错误的地方,大家发现了的话请跟帖或者联系我吧,我会尽快更正。



  Discuz拥有一套完整的积分系统,从3.0来引进了扩展积分的概念,使得定制程度极高,本教程覆盖了Discuz 5.5的积分系统的大部分源代码和实现原理,本文章适合有一定编程基础和开发过全站系统,对系统全局有宏观把握的会员。

  这篇文章只是积分系统的一半,也就是平时发帖,附件等等的增减,对于积分交易,我会在不久后再补一篇。


(一)数据表分析

1.cdb_members
用户的积分集中在cdb_members这个表,其中,posts表示帖子数,digestposts表示精华帖,oltime表示在线时间,pageviews表示页面访问量,credits表示积分,extcreditsX为扩展积分

2.cdb_settings
这个表是论坛的设置存放的表,里面有对于积分公式(creditsformula),公式的说明(creditsformulaexp),积分的策略(creditspolicy)(注:这个存放的是一个序列化的数组),积分交易税(creditstax),启用的交易积分(creditstrans),兑换最低余额(exchangemincredits),扩展积分的名字(extcredits)(注:此外也为一个序列化的数组,初始的积分(initcredits),

3.cdb_forumfields
这个表里面记录了论坛的一些设置,包括发帖积分(postcredits),回复积分(replycredits),下载附件积分(getattachcredits),发表附件积分(postattachcredits),加精华积分(digestcredits),这些对应在后台的论坛设置里面都有。

4.cdb_creditslog
这个是积分交易记录表

5.cdb_paymentlog
这个是帖子付费记录表

(二)源代码分析

1.登陆积分显示
首先是登陆,登陆的时候论坛从cdb_members中取出一些发帖数,积分,扩展积分等等设置,在./include/common.inc.php中有如下代码:

  1. $membertablefields = 'm.uid AS discuz_uid, m.username AS discuz_user, m.password AS discuz_pw, m.secques AS discuz_secques,
  2.         m.adminid, m.groupid, m.groupexpiry, m.extgroupids, m.email, m.timeoffset, m.tpp, m.ppp, m.posts, m.digestposts,
  3.         m.oltime, m.pageviews, m.credits, m.extcredits1, m.extcredits2, m.extcredits3, m.extcredits4, m.extcredits5,
  4.         m.extcredits6, m.extcredits7, m.extcredits8, m.timeformat, m.dateformat, m.pmsound, m.sigstatus, m.invisible,
  5.         m.lastvisit, m.lastactivity, m.lastpost, m.newpm, m.accessmasks, m.xspacestatus, m.editormode, m.customshow';
复制代码

以上就是取出数据库中的会员用到的字段。

发帖,回复,发附件,下附件等的积分增加或减少

2.发帖,回复积分增减

(1)原理分析:
是这样一个过程,发帖的时候前台看到的文件是:post.php,
然后引用如下文件:
include/common.inc.php  DZ通用函数库
include/post.func.php  发帖用到的函数库
include/discuzcode.func.php  解析Discuz Code用到的

接下来跟据传入的action判断引用到哪个文件继续处理
include/newthread.inc.php(新帖)
include/newreply.inc.php(回复)
include/supesite_import.inc.php(导入到supersite)


(2)代码分析:

下面就以发新帖来分析一下Discuz对于积分的处理。

第一部分:post.php

这个文件是发新帖,回复,投票都会用到的,所以它的作用就是初始化一些全局的东西,我就不全文件分析了,只分析一些与积分有关的部分。

  1. $postcredits = $forum['postcredits'] ? $forum['postcredits'] : $creditspolicy['post'];
  2. $replycredits = $forum['replycredits'] ? $forum['replycredits'] : $creditspolicy['reply'];
  3. $digestcredits = $forum['digestcredits'] ? $forum['digestcredits'] : $creditspolicy['digest'];
  4. $postattachcredits = $forum['postattachcredits'] ? $forum['postattachcredits'] : $creditspolicy['postattach'];
复制代码

这一部分的作用就是取出当前论坛的一些积分设置,和我们前面分析的数据表cdb_forumfields对应,得到会员发帖,回复等加多少分。


第二部分:include/newthread.inc.php

这个文件处理发新帖的特定请求。

  1. if(isset($poll)) {
  2.         $special = 1;
  3. } elseif(isset($trade)) {
  4.         $special = 2;
  5. } elseif(isset($reward)) {
  6.         $special = 3;
  7. } elseif(isset($activity)) {
  8.         $special = 4;
  9. } else {
  10.         $special = 0;
  11. }
复制代码

这一部分的代码是用来判断帖子的类型的,1为投票,2为交易帖,3为悬赏,4为活动,0为普通帖。


  1.         $price = intval($price);
  2.         $price = $maxprice && !$special ? ($price <= $maxprice ? $price : $maxprice) : 0;
复制代码

这里是帖子价格的赋值,超过了最大的价格的处理,特殊帖子的价格处理。


  1. } elseif($special == 3 && $allowpostreward) {
  2.                 $rewardprice = intval($rewardprice);
  3.                 if(!$rewardprice) {
  4.                         showmessage('reward_credits_please');
  5.                 } elseif($rewardprice > 32767) {
  6.                         showmessage('reward_credits_overflow');
  7.                 } elseif($rewardprice < $minrewardprice || ($maxrewardprice > 0 && $rewardprice > $maxrewardprice)) {
  8.                         showmessage('reward_credits_between');
  9.                 } elseif(($realprice = $rewardprice + ceil($rewardprice * $creditstax)) > $_DSESSION["extcredits$creditstrans"]) {
  10.                         showmessage('reward_credits_shortage');
  11.                 }

  12.                 $price = $rewardprice;

  13.                 $db->query("UPDATE {$tablepre}members SET extcredits$creditstrans=extcredits$creditstrans-$realprice WHERE uid='$discuz_uid'");
复制代码

前面说过3表示悬赏帖子,那么当你发表成功了一个悬赏帖子后,就会相应在cdb_members表中减少相应的扩展积分,便是上面的代码的作用了。


  1. elseif($special == 3 && $allowpostreward) {
  2.                 $db->query("INSERT INTO {$tablepre}rewardlog (tid, authorid, netamount, dateline) VALUES ('$tid', '$discuz_uid', $realprice, '$timestamp')");
  3.         }
复制代码

后续判断如果为悬赏帖子的话就往cdb_rewardlog(悬赏记录表)里写入一条记录。


  1.         if($attachment) {
  2.                 $searcharray = $pregarray = $replacearray = array();
  3.                 foreach($attachments as $key => $attach) {
  4.                         $db->query("INSERT INTO {$tablepre}attachments (tid, pid, dateline, readperm, price, filename, description, filetype, filesize, attachment, downloads, isimage, uid, thumb, remote)
  5.                                 VALUES ('$tid', '$pid', '$timestamp', '$attach[perm]', '$attach[price]', '$attach[name]', '$attach[description]', '$attach[type]', '$attach[size]', '$attach[attachment]', '0', '$attach[isimage]', '$attach[uid]', '$attach[thumb]', '$attach[remote]')");
  6.                         $searcharray[] = '[local]'.$localid[$key].'[/local]';
  7.                         $pregarray[] = '/\[localimg=(\d{1,3}),(\d{1,3})\]'.$localid[$key].'\[\/localimg\]/is';
  8.                         $replacearray[] = '[attach]'.$db->insert_id().'[/attach]';
  9.                 }
  10.                 $message = str_replace($searcharray, $replacearray, preg_replace($pregarray, $replacearray, $message));
  11.                 $db->query("UPDATE {$tablepre}posts SET message='$message' WHERE pid='$pid'");
  12.                 updatecredits($discuz_uid, $postattachcredits, count($attachments));
  13.         }
复制代码

如果帖子中带有附件的话,就把附件插入cdb_attachments表,然后注意到$message这一个变量在这里用到了替换,这里的作用是图文混排。接下来往cdb_posts写一条记录,再用include/global.func.php定义到一个函数updatecredits来更新积分。
给Discuz的一个小建议:可以判断是不是postattachcredits为0,为0就可以不执行updatecredits这个函数,虽然在函数定义的时候也有判断,不过在这里判断似乎更好。


  1. if($modnewthreads) {

  2.                 $db->query("UPDATE {$tablepre}forums SET todayposts=todayposts+1 WHERE fid='$fid'", 'UNBUFFERED');
  3.                 $allowuseblog && $isblog && $blog ? showmessage('post_newthread_mod_blog_succeed', "blog.php?uid=$discuz_uid") :
  4.                         showmessage('post_newthread_mod_succeed', "forumdisplay.php?fid=$fid");

  5.         } else {

  6.                 if($digest) {
  7.                         foreach($digestcredits as $id => $addcredits) {
  8.                                 $postcredits[$id] = (isset($postcredits[$id]) ? $postcredits[$id] : 0) + $addcredits;
  9.                         }
  10.                 }
  11.                 updatepostcredits('+', $discuz_uid, $postcredits);

  12.                 $lastpost = "$tid\t$subject\t$timestamp\t$author";
  13.                 $db->query("UPDATE {$tablepre}forums SET lastpost='$lastpost', threads=threads+1, posts=posts+1, todayposts=todayposts+1 WHERE fid='$fid'", 'UNBUFFERED');
  14.                 if($forum['type'] == 'sub') {
  15.                         $db->query("UPDATE {$tablepre}forums SET lastpost='$lastpost' WHERE fid='$forum[fup]'", 'UNBUFFERED');
  16.                 }

  17.                 if($allowuseblog && $isblog && $blog) {
  18.                         showmessage('post_newthread_blog_succeed', "blog.php?tid=$tid");
  19.                 } else {
  20.                         showmessage('post_newthread_succeed', "viewthread.php?tid=$tid&extra=$extra");
  21.                 }

  22.         }
复制代码

这里是最后一段代码,作用是这样的:
首先看看是不是在发新帖的时候就被加为文集


3.下载附件积分增减

这一部分主要用到的就是attachment.php这个文件了,下面就来分析这个文件中与积分中有关系的代码:

  1. if(!$isimage) {
  2.         $forum['getattachcredits'] = $forum['getattachcredits'] ? unserialize($forum['getattachcredits']) : array();
  3.         $getattachcredits = $forum['getattachcredits'] ? $forum['getattachcredits'] : $creditspolicy['getattach'];
  4.         updatecredits($discuz_uid, $getattachcredits, -1);
  5. }
复制代码

这一段的意思是:当一个附件不是图像的时候,取出该论坛对于下载附件的积分设置,比方说是-5分,那么就调用updatecredits(global.func中定义)这个函数更新一下积分。


P.S.:相关函数分析:

updatepostcredits函数,定义于./include/post.func.php

  1. function updatepostcredits($operator, $uidarray, $creditsarray) {
  2.         global $db, $tablepre, $discuz_uid, $timestamp;

  3.         $membersarray = $postsarray = array();
  4.         foreach((is_array($uidarray) ? $uidarray : array($uidarray)) as $id) {
  5.                 $membersarray[intval(trim($id))]++;
  6.         }
  7.         foreach($membersarray as $uid => $posts) {
  8.                 $postsarray[$posts][] = $uid;
  9.         }
  10.         $lastpostadd = $uidarray == $discuz_uid ? ", lastpost='$timestamp'" : '';
  11.         $creditsadd1 = '';
  12.         if(is_array($creditsarray)) {
  13.                 foreach($creditsarray as $id => $addcredits) {
  14.                         $creditsadd1 .= ", extcredits$id=extcredits$id$operator$addcredits*\$posts";
  15.                 }
  16.         }
  17.         foreach($postsarray as $posts => $uidarray) {
  18.                 $uids = implode(',', $uidarray);
  19.                 eval("\$creditsadd2 = "$creditsadd1";");
  20.                 $db->query("UPDATE {$tablepre}members SET posts=posts+('$operator$posts') $lastpostadd $creditsadd2 WHERE uid IN ($uids)", 'UNBUFFERED');
  21.         }
  22. }
复制代码

可以看到这个函数有三个传入参数,$operator表示加还是减,$uidarray表示会员的id数组,$creditsarray表示要加减的积分数组。调用方法如:

用法:

  1. updatepostcredits('+', 1, 1);
复制代码

表示给uid为1的会员加1个积分

评分

3

查看全部评分

 楼主| 郭鑫 发表于 2007-6-3 13:25:00 | 显示全部楼层
update 1
回复

使用道具 举报

 楼主| 郭鑫 发表于 2007-6-3 13:25:12 | 显示全部楼层
update2
回复

使用道具 举报

江苏小鱼儿 发表于 2007-6-3 13:28:12 | 显示全部楼层
终于又看到技术帖了,坐沙发支持!
回复

使用道具 举报

9see 发表于 2007-6-3 13:30:47 | 显示全部楼层
好帖,支持.
回复

使用道具 举报

sunjuncai 发表于 2007-6-4 15:04:43 | 显示全部楼层
我也支持.很好的帖子.
回复

使用道具 举报

leohack 发表于 2007-6-4 22:22:20 | 显示全部楼层
纯技术帖   支持
回复

使用道具 举报

chf 发表于 2007-6-4 22:30:35 | 显示全部楼层
辛苦楼主了
回复

使用道具 举报

tanweihai 发表于 2007-6-4 22:46:24 | 显示全部楼层
支持.很好的帖子.
回复

使用道具 举报

老骥99 发表于 2007-6-4 23:40:36 | 显示全部楼层
虽然看不明白,但还是要顶
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|Discuz! 官方站 ( 皖ICP备16010102号 )star

GMT+8, 2024-11-24 11:03 , Processed in 0.049103 second(s), 6 queries , Gzip On, Redis On.

Powered by Discuz! X3.4

Copyright © 2001-2023, Tencent Cloud.

快速回复 返回顶部 返回列表