分类: UCHome

UCHome中提醒的实现机制

没有评论

2011 年 03 月 11 日 at 上午 10:56分类:PHP | UCHome

在UCHome中,在我们的导航栏中有这么有个导航按钮,那就是带着个小喇叭的提醒数目。
一般情况下,这个按钮是不显示的,只有在有新的提醒的时候才显示。那么这些提醒都包括哪些事情呢?
我们先来看下这个提醒数的输出变量是什么,在header.htm文件中我们看到输出这个提醒数目的变量是:$_SGLOBAL[member][allnotenum],我们就找到这个变量。
我们看下get_space()这个函数就会知道了

//提醒数
$space['allnotenum'] = 0;
foreach (array('notenum','pokenum','addfriendnum','mtaginvitenum','eventinvitenum','myinvitenum') as $value) {
	$space['allnotenum'] = $space['allnotenum'] + $space[$value];
}

这个提醒的数目中包括了一下事情:
notenum:通知数;pokenum:打招呼数;addfriendnum:新增好友数;mtaginvitenum:群组邀请数;eventinvitenum:活动邀请数;myinvitenum:邀请数;总共这些数目之和会显示在导航栏的提醒当中。
我们以新增好友数为例来说明。
当我们把对方加为好友时,只是把相关的信息写入了friend表中,但是这样子还是个对方未确认的状态,所以该条数据中的status字段的值是0(false);此外还把更新了一次space数据表:

//增加对方好友申请数
$_SGLOBAL['db']->query("UPDATE ".tname('space')." SET addfriendnum=addfriendnum+1 WHERE uid='$uid'");
showmessage('request_has_been_sent');

将被加好友的space数据表中的信息中的addfriendnum数目加1,那么这样子提醒已经写入数据表了。
那么是如何显示出来的呢?继续。。
我们在UCHome用于显示数据的页面无非就两个:network.php,space.php,在这两个文件中,我们都能看到以下代码:

$space = getspace($uid, 'uid');

这里通过调用函数getspace()来完成数据的搜索。并且将数据放在超全局变量$_SGLOBAL[member][allnotenum]中。
这样子就能完成显示的功能了。
但是事情还没有做完,这个提醒总不能一直显示吧 ,当我看过了 那就就应该不显示了吧,再来看看这个过程是怎么实现的。
当我们点击某一个提醒时,会跳转到相关的操作页面,如好友,会跳转到http://localhost/UCHome/cp.php?ac=friend&op=request这个页面之下。
我们找到这个页面的文件,当我们在页面中点击批准对方的好友申请时,会执行http://localhost/UCHome/cp.php?ac=friend&op=add相关的代码。我们主要来看如下代码:

//我的好友申请数进行变化
$_SGLOBAL['db']->query("UPDATE ".tname('space')." SET addfriendnum=addfriendnum-1 WHERE uid='$space[uid]' AND addfriendnum>0");

这其中会调用函数friend_update()这个函数在function_cp.php文件中,他的作用的更新双向好友的状态
那么这样子以来 整个提醒的过程就操作完成了!

UCHome关于注册同步登陆的问题

一条评论

2011 年 03 月 07 日 at 下午 2:46分类:PHP | Ucenter | UCHome | WEB开发

在uchome中,当我们注册一个用户账号时,注册完毕之后,那么默认就是处在登陆状态的。
但是在uchome这个应用是处在登陆状态了,但是其他应用程序并不是处在登陆状态的。
也就是说uchome在注册的时候并不能实现注册时实现同步登陆的效果。
那么这个问题该怎么解决呢?其实也不是很难。
记得要实现同步登陆,那么就必须调用ucenter服务器端得接口函数uc_user_synlogin();
通过调用该函数产生的一些JS串来远程加载相关应用下面api/uc.php文件里面的相关函数,一次来设置cookie以实现同步登陆的问题。
那么在注册过程中我们也是可以调用该函数来执行同步登陆的效果的。
uchome中用户注册的时候,会先对一系列的数据进行校验,之后回调用ucenter的接口函数uc_user_register进行注册,
对其返回的结果进行相关的判断,如果注册成功了,那么接下来执行的是把用户的数据插入本地的member数据表中,之后在执行开通空间和加载默认好友等事情。然后还会把相关的信息写入session表中,同时设置COOKIE,以表示登陆了。
那么只要在这里插入我们想要的代码就行了;如下:

//设置cookie
ssetcookie('auth', authcode("$setarr[password]\t$setarr[uid]", 'ENCODE'), 2592000);
ssetcookie('loginuser', $username, 31536000);
ssetcookie('_refer', '');

//调用ucenter接口函数的同步登录函数
$ucsynlogin = uc_user_synlogin($newuid);

然后我们修改do_reister.php文件中的205行左右的代码:

showmessage('registered', $jumpurl);

修改为:

showmessage('registered', $jumpurl,1,array($ucsynlogin));

那么这样子,我们要的实现效果就可以解决了!

UCHOME2.0积分机制分析

没有评论

2011 年 03 月 07 日 at 上午 11:53分类:PHP | UCHome | WEB开发

A:管理员在后台修改积分规则
B:数据被写入数据表creditrule 中,其中rewardtype=1表示奖励措施rewardtype=0表示处罚措施并将数据写入缓存文件data/data_creditrule.php 中
C:用户发表文章或者进行其他操作的时候,通过getreward函数来获取奖罚积分

//积分
	$reward = getreward('publishblog', 0);

D:然后通过SQL语句将数据写入用户数据库表space中,从而增加或减少用户积分

$_SGLOBAL['db']->query("UPDATE ".tname('space')." SET {$blognumsql}, lastpost='$_SGLOBAL[timestamp]', updatetime='$_SGLOBAL[timestamp]', credit=credit+$reward[credit], experience=experience+$reward[experience] WHERE uid='$_SGLOBAL[supe_uid]'");

E:getreward函数部分通过包含data/data_creditrule.php 缓存文件来调用积分规则
getreward()函数在function_common.php文件中

UCHome中道具机制的分析

没有评论

2011 年 03 月 07 日 at 上午 10:48分类:PHP | UCHome | WEB开发

uchome中的道具不是在一个地方统一使用的,而是分布在文章,空间,好友,图片等处的。
A:道具的设定。
管理员在系统的管理后台设置某个道具的功能参数,之后这些数据将被保存在magic数据表中;
B:道具的所用功能都是由magic.php文件路由的,也就是说只要是关于道具的操作的都会用到magic.php文件;
C:道具的购买:
用户购买道具之后,用户的所有道具数据被写入usermagic数据表中。
D:道具的使用:(这里以隐身草为例)
我们在是space_feed.htm文件中可以看到以下代码:

<!--{if $_SGLOBAL[magic][invisible]}-->
...........
<!--{else}-->
<img src="image/magic/invisible.small.gif" alt="{$_SGLOBAL[magic][invisible]}" class="magicicon"><a id="a_magic_invisible" href="magic.php?mid=invisible" onclick="ajaxmenu(event,this.id,1)" class="gray">我要隐身</a>
<!--{/if}-->
<!--{/if}-->

在相关的模板文件中包含着我要隐身的超级链接;用户点击之后,会进入magic.php文件中进行相关的操作。在该文件中通过函数magic_get()获得相关道具的数据,把该数据传递给$magic变量,然后查询用户是否拥有该道具,不拥有则提示购买。拥有则调用相关的道具的处理文件与模板

include_once(S_ROOT.'./source/magic_'.$mid.'.php');
include_once template('magic_'.$mid);

用户一旦使用了该道具之后,便会在session表中记录相关的信息;
同时调用magic_use函数,修改道具使用记录以及用户拥有的道具数量

//隐身卡
if(submitcheck("usesubmit")) {

	$expire = $_SGLOBAL['timestamp'] + ($magic['custom']['effectivetime'] ? $magic['custom']['effectivetime'] : 86400);
	$_SGLOBAL['db']->query("UPDATE ".tname("session")." SET magichidden = 1 WHERE uid='$_SGLOBAL[supe_uid]'");

	magic_use($mid, array('expire'=>$expire), true);
	showmessage('magicuse_success', $_POST['refer'], 0);
}

通过该函数修改usermagic,magicuselog数据表中的相关信息

E:使用效果:
详见以下代码(space_feed.htm)

<div class="r_option">
						<!--{if $_SGLOBAL[session][magichidden]}-->当前隐身<!--{else}-->当前在线<!--{/if}-->

						<!--{if $_SGLOBAL[magic][invisible]}-->
							<!--{if $_SGLOBAL[session][magichidden]}-->
							<img src="image/magic/invisible.small.gif" class="magicicon"><a id="a_magic_appear" href="cp.php?ac=magic&op=appear" onclick="ajaxmenu(event,this.id)" class="gray">我要在线</a>
							<!--{else}-->
							<img src="image/magic/invisible.small.gif" alt="{$_SGLOBAL[magic][invisible]}" class="magicicon"><a id="a_magic_invisible" href="magic.php?mid=invisible" onclick="ajaxmenu(event,this.id,1)" class="gray">我要隐身</a>
							<!--{/if}-->
						<!--{/if}-->
					</div>

UCHome动态机制的分析

没有评论

2011 年 03 月 06 日 at 下午 9:46分类:PHP | UCHome | WEB开发

在uchome中动态feed的操作很频繁。
1.全局动态的配置
这里所说的全局动态配置是指管理员在后台设置的动态规则,将会存在数据表config中,在config中有一个字段为privacy,这个字段对应的值分为两部分,其中一部分使我们之前说的权限设置$_SCONFIG['privacy']['view']还有一部分就是这里要说的全局动态配置$_SCONFIG['privacy']['feed'];我们在数据缓存文件data_config.php文件中可以找到$_SCONFIG['privacy']['feed']这个数组里面的相关动态的配置;

2.用户自定义设置的动态配置
用户在后台设置自己定义的动态规则;数据被保存在spcaefiled中的字段privacy中。

3:动态的产生
A:在检查是否将某个动作写入动态时有两种方式
第一种就是在发布文章的时候,在底下有个选择是否发送动态,然后在文章写入数据库之后会有个判断,如果选择发送,则产生动态,否则不产生。如下代码:

//产生feed
	if($POST['makefeed']) {
		include_once(S_ROOT.'./source/function_feed.php');
		feed_publish($blogid, 'blogid', $olds?0:1);
	}

这里调用feed的产生函数,这个我们之前的部分已经讲过了。
第二种方法就是在处理动作之后(例如加好友)调用ckprivacy函数进行验证是否发送动态。如下代码:

//加好友发布事件
if(ckprivacy('friend', 1)) {
        $fs = array();
	$fs['icon'] = 'friend';
	$fs['title_template'] = cplang('feed_friend_title');
	$fs['title_data'] = array('touser'=>"<a href=\"space.php?uid=$tospace[uid]\">".$_SN[$tospace['uid']]."</a>");
	$fs['body_template'] = '';
	$fs['body_data'] = array();
	$fs['body_general'] = '';
        feed_add($fs['icon'], $fs['title_template'], $fs['title_data'], $fs['body_template'], $fs['body_data'], $fs['body_general']);
}

下面是ckprivacy函数的部分代码。下面的$feedmode就是该函数的第二个参数,就是这里的1.第一个参数是$type

if($feedmode) {
		if($type == 'spaceopen') {
			if(!empty($_SCONFIG['privacy']['feed'][$type])) {
				$result = true;
			}
               //判断用户是否设置了该时间要发送动态
		} elseif(!empty($space['privacy']['feed'][$type])) {
			$result = true;
		}
	} elseif($space['self']){
		//自己
		$result = true;

通过这样子的判断就能知道是否要发送动态了,发送动态就是将动态信息写进动态feed表中。

UCHome权限各种机制的分析

没有评论

2011 年 03 月 06 日 at 下午 5:15分类:PHP | UCHome | WEB开发

uchome中用到的权限判断很多,下面来说说uchome中权限的实现。
1.全站用户默认的权限设置:
A:管理员在后台设置全站的默认权限管理规则,此时系统将这些权限的数据卸载config表中的privacy字段所对应的值,该值是经过序列化之后的一些字符串。
B:系统运行的时候将会更新系统的配置文件,产生缓存文件data_config.php,那么系统默认的权限设置数据存在于$_SCONFIG[privacy][view]这个数组中
C:在空间的入口文件space.php文件中,我们看到以下代码:

//这是权限判断
		if(!ckprivacy($do)) {
			include template('space_privacy');
			exit();
		}

这是系统判断的操作,通过function_common.php文件中的函数ckprivacy()来判断系统是否允许该动作执行。
该函数返回的bool值的数据
D:若无权限查看则提示加为好友才能观看,并终止程序。

2.用户自定义的权限设置:
A:用户在自己的控制面板设置权限访问规则,数据被储存在spacefield表中的privacy字段所对应的值,该值也是经过序列化之后的一个字符串。
B:在space.php入口文件中通过getspace函数获取用户spacefield表中的数据存储在$spaces数组中
C:通过函数ckprivacy查看用户是否有权限查看数据,具体跟全站用户默认权限设置C处相同

3.用户组的权限设置
A:管理员在后台设置各用户组的权限
B:在admin\admincp_usergroup.php文件中通过下面这段代码

if(empty($thevalue['gid'])) {
		//添加
		inserttable('usergroup', $setarr);
	} else {
		//更新
		updatetable('usergroup', $setarr, array('gid'=>$thevalue['gid']));
	}

将用户组配置文件更新至 usergroup表中各个字段的值
C:通过usergroup_cache 函数来更新缓存文件,根据用户组ID生成不同的缓存文件,我们在data目录下面可以看到很多的关于用户组的缓存文件如:data_usergroup.php,data_usergroup_1.php等等其中data\data_usergroup.php 文件为所有用户组名称与ID 数组,其余的为其序列号对应的用户组ID的权限设置数组:权限查询方法为$_SGLOBAL['usergroup'][1][allowblog]
D:在需要检查权限的各个文件中用checkperm(权限名) 分别进行权限的检查。而不是集中在入口处进行权限检查;如下:

//禁止访问
	if(checkperm('banvisit')) {
		ckspacelog();
		showmessage('you_do_not_have_permission_to_visit');
	}

4.实名认证:
A:在后台设置未经实名认证的用户权限
B:将数据写入config表中 以var=>datavalue 键值对的形式存储
C:生成配置缓存文件于\data\data_config.php的数组中,调用方法:$_SCONFIG[name_allowfriend]
D:在需要实名认证权限检查的文件中调用该函数查询是否具有某权限 ckrealname(‘blog’);函数有返回值,但是在返回之前就已经跳转了,提示用户没有某个权限

5.视频认证:跟实名认证机制是一样的,只不过权限检查函数为 ckvideophoto(‘blog’);

6.指定文章(图片)等的浏览权限 (这里以文章浏览权限为例)
A:用户发布文章的时候指定是好友可见还是密码查看
B:数据传递给文章发布函数
C:文章发布函数,将数据写入 文章表blog中,
D:用户查看文章的时候,查询出该文章的隐私信息,然后在source\space_blog.php文件中通过下列语句来检查是否需要密码或者是否具有权限。

//检查好友权限
	if(!ckfriend($blog['uid'], $blog['friend'], $blog['target_ids'])) {
		//没有权限
		include template('space_privacy');
		exit();
	} elseif(!$space['self'] && $blog['friend'] == 4) {
		//密码输入问题
		$cookiename = "view_pwd_blog_$blog[blogid]";
		$cookievalue = empty($_SCOOKIE[$cookiename])?'':$_SCOOKIE[$cookiename];
		if($cookievalue != md5(md5($blog['password']))) {
			$invalue = $blog;
			include template('do_inputpwd');
			exit();
		}
	}

UCHome登陆验证机制分析

没有评论

2011 年 03 月 04 日 at 下午 2:18分类:PHP | UCHome | WEB开发

1、登陆详解:
A:用户填好登录表单之后数据被提交给source\do_login.php 处理
B:在do_login.php中下面这些语句接收传递来的用户名密码与cookie生效时间

        $password = $_POST['password'];
	$username = trim($_POST['username']);
	$cookietime = intval($_POST['cookietime']);

C:然后验证用户提交来的用户名以及密码的正确性,不正确则跳转并提示登录失败

//同步获取用户源
	if(!$passport = getpassport($username, $password)) {
		showmessage('login_failure_please_re_login', 'do.php?ac='.$_SCONFIG['login_action']);
	}

注意:这里验证用户名与密码的正确性是通过getpassport()函数里面调用uc_client在Ucenter用户中心数据库中查询的
D:若验证通过之后,再将获取到得用户账户信息赋给setarr变量数组

$setarr = array(
		'uid' => $passport['uid'],
		'username' => addslashes($passport['username']),
		'password' => md5("$passport[uid]|$_SGLOBAL[timestamp]")//本地密码随机生成
	);

E:查询uchome的数据库看该用户信息是否存在于Uchome数据库中,不存在的话,则将从Ucenter中查询到的用户数据写入到uchome的member表中,存在则将member中的密码替换掉从Ucenter中查询出来的密码,存入setarr变量数组中。

//检索当前用户
	$query = $_SGLOBAL['db']->query("SELECT password FROM ".tname('member')." WHERE uid='$setarr[uid]'");
	if($value = $_SGLOBAL['db']->fetch_array($query)) {
		//把ucenter中的用户密码替换成UChome中member表中的密码
		$setarr['password'] = addslashes($value['password']);
	} else {
		//更新本地用户库
		inserttable('member', $setarr, 0, true);
	}

F:将用户登录信息写入到Uchome的session表中
Insertsession函数在source\function_space.php中定义
其主要功能为a:清除session表中的某个用户的记录b:获得用户的IP以及是否使用隐身道具c: 将setarr变量数组中的数据插入到session表中。d:更新统计数数据等
G:将用户名与密码加密写入cookie中

//设置cookie
	ssetcookie('auth', authcode("$setarr[password]\t$setarr[uid]", 'ENCODE'), $cookietime);
	ssetcookie('loginuser', $passport['username'], 31536000);
	ssetcookie('_refer', '');

2:验证部分
判断当前用户登录状态是通过source\function_common.php中的checkauth函数实现的
下面就来分析这个函数

function checkauth() {
	global $_SGLOBAL, $_SC, $_SCONFIG, $_SCOOKIE, $_SN;

	if($_SGLOBAL['mobile'] && $_GET['m_auth']) $_SCOOKIE['auth'] = $_GET['m_auth'];
	if($_SCOOKIE['auth']) {
		@list($password, $uid) = explode("\t", authcode($_SCOOKIE['auth'], 'DECODE'));
		$_SGLOBAL['supe_uid'] = intval($uid);
		if($password && $_SGLOBAL['supe_uid']) {
			//从session表中获取ID为$_SGLOBAL[supe_uid]的session数据
			$query = $_SGLOBAL['db']->query("SELECT * FROM ".tname('session')." WHERE uid='$_SGLOBAL[supe_uid]'");
			//若session表中有该用户的数据
			if($member = $_SGLOBAL['db']->fetch_array($query)) {
				//判断session表中的密码和cookie中的密码是否相等
				if($member['password'] == $password) {
					$_SGLOBAL['supe_username'] = addslashes($member['username']);
					$_SGLOBAL['session'] = $member;
				} else {
					$_SGLOBAL['supe_uid'] = 0;
				}
			//若session表中么有有该用户的数据,则从用户数据表member中查询该ID得用户数据
			} else {
				$query = $_SGLOBAL['db']->query("SELECT * FROM ".tname('member')." WHERE uid='$_SGLOBAL[supe_uid]'");
				if($member = $_SGLOBAL['db']->fetch_array($query)) {
					if($member['password'] == $password) {
						$_SGLOBAL['supe_username'] = addslashes($member['username']);
						$session = array('uid' => $_SGLOBAL['supe_uid'], 'username' => $_SGLOBAL['supe_username'], 'password' => $password);
						include_once(S_ROOT.'./source/function_space.php');
						insertsession($session);//登录
					} else {
						$_SGLOBAL['supe_uid'] = 0;
					}
				} else {
					$_SGLOBAL['supe_uid'] = 0;
				}
			}
		}
	}
	if(empty($_SGLOBAL['supe_uid'])) {
		clearcookie();
	} else {
		$_SGLOBAL['username'] = $member['username'];
	}
}

A:判断$_cookie[auth]是否存在,若不存在则不进行任何处理,并清除所有cookie
B:从cookie中反解出用户名跟密码信息
注意:这里说的密码以及上面说的将密码加密进cookie中的密码并不是用户的真实密码,而是经过md5双重加密并且salt处理后的密码
C:从session数据表中取出用户ID为$_SGLOBAL[supe_uid]的用户信息,若该记录存在则执行下面的操作,否则执行D操作(直接查询用户数据库)如果取出来的密码与cookie中的密码相等,那么判定为登录成功将数据写入到$_SGLOBAL['session']数组否则判定为登录失败,清除所有cookie
D:在C步时,若在session表中没有该用户的数据则,在用户数据表member中查询该ID得用户数据,看cookie中的密码是否与数据库中的密码一样,如果一样则登录成功,并将用户数据写入到session表中保持用户的登录状态,否则登录失败
上面无论是用session表来判定登录状态还是用member表来判定登录状态,都会影响到一个变量,那就是$_SGLOBAL['supe_uid'],在程序处理的时候,用户登录与否一般要用到得变量就是$_SGLOBAL['supe_uid']。

UCHome中的feed机制分析

没有评论

2011 年 03 月 04 日 at 上午 11:14分类:PHP | UCHome | WEB开发

说到feed就不得不提到推或者拉,什么叫推呢?就是将用户的动态信息推送给自己的好友。如何推送呢?其实就是将数据写进用户的每个好友的数据表中,这样好友查询起来就会很方便,只要一句where uid=自己的ID 就能找出自己的所有feed信息;那么拉呢?其实就是将所有用户产生的动态信息,都存在用户自己所在的表中。那么要查看好友的动态怎么办呢? 就得去找自己所有的好友所对应的feed信息。
那么Uchome使用的是什么方式呢?Uchome使用的是拉的方式,因为这样的话产生的数据冗余比较低,而且不用每次产生动态的时候 插入多条数据,加速了动态插入操作。
我们就拿用户发表日志这个动作来简单看看Uchome的feed机制。
用户发布日志所使用的函数是 source/function_blog.php文件里的blog_post()函数
用户发表日志成功后会调用source/function_feed.php文件里的feed_publish($id, $idtype, $add=0)函数来产生feed
产生feed的方式很简单,根据不同的idtype来得到不同的feed内容,根据add来判断是插入新的feed还是更新feed
然后将feed信息 与用户ID 一起写入feed表中。此外还有一种添加feed的方法是在添加好友中,当用户单方向的添加好友成功后,会调用function_cp.php函数文件里面的feed_add()函数,执行feed的添加操作。
这样子就能将feed信息写进数据表feed中了。
显示feed就更简单了。
首先获取用户的所有好友,然后通过WHERE uid IN (好友ID列表) 从feed中查出 好友的所有feed信息
当然按照这种策略的话 这里的feed信息会越来越多,所以UCHOME有一个计划任务去定期处理feed
source\cron\cleanfeed.php
我们在space.php文件中可以看到以下的代码:

//计划任务
if(!empty($_SCONFIG['cronnextrun']) && $_SCONFIG['cronnextrun'] <= $_SGLOBAL['timestamp']) {
	include_once S_ROOT.'./source/function_cron.php';
	runcron();
}

这个里面的函数runcron()在文件function_cron.php文件中
就是用来清除几天前的feed信息,具体的要看你自己如何去配置了。

UCHome下伪静态的实现及路径解析

没有评论

2011 年 03 月 03 日 at 下午 9:01分类:PHP | UCHome | WEB开发

仅适用于程序可以通过独立域名或者二级域名直接访问。
如果您的程序需要域名后面加目录名(比如:xxxxx)的方式才可以访问,那么,您需要手工修改以下规则:
将 “RewriteBase /” 修改为 “RewriteBase /xxxxx”
其中,“xxxxx” 为您的程序目录名

<IfModule mod_rewrite.c>

RewriteEngine On

RewriteBase /UCHome

RewriteRule ^(space|network)\-(.+)\.html$ $1.php?rewrite=$2 [L]

RewriteRule ^(space|network)\.html$ $1.php [L]

RewriteRule ^([0-9]+)$ space.php?uid=$1 [L]

</IfModule>

添加内容时,请遵照上面的提示,修改程序所在的路径
然后保存为文件 .htaccess 。将 .htaccess 文件上传到程序所在的目录中
进入站点设置,根据需要开启 URL 静态化功能.

虽然这样子已经能够使url伪静态话了,但是要是你注意看的话,会发现一点,那就是在我们伪静态话之前和静态化之后,页面所有文件的链接地址都是没有改变的,但是,在进行伪静态处理之后,当我们把鼠标放在相关的链接上面时,链接的地址已经发生了变化,但是,查看源文件还是没有变化的。这是什么原因呢??

找了好长时间,终于知道是什么原因了。
在要进行伪静态处理的space.php文件中,我们可以看到如下代码:

if($_SCONFIG['allowrewrite'] && isset($_GET['rewrite'])) {
	$rws = explode('-', $_GET['rewrite']);
	if($rw_uid = intval($rws[0])) {
		$_GET['uid'] = $rw_uid;
	} else {
		$_GET['do'] = $rws[0];
	}
	if(isset($rws[1])) {
		$rw_count = count($rws);
		for ($rw_i=1; $rw_i<$rw_count; $rw_i=$rw_i+2) {
			$_GET[$rws[$rw_i]] = empty($rws[$rw_i+1])?'':$rws[$rw_i+1];
		}
	}
	unset($_GET['rewrite']);
}

这是获取伪静态并进行处理的相关代码。将获取到的值复值给相关的变量,留给后续的程序执行,这里并没有什么。
需要注意的是$_SCONFIG['allowrewrite'],这个配置项是在UCHome的后台开启的。这些并没有什么不能明白的。但是那个链接的地址到底是怎么回事呢?
我们找到文件function_common.php文件。这个文件里面有个函数ob_out();如下:

function ob_out() {
	global $_SGLOBAL, $_SCONFIG, $_SC;

	$content = ob_get_contents();

	$preg_searchs = $preg_replaces = $str_searchs = $str_replaces = array();

	if($_SCONFIG['allowrewrite']) {
		$preg_searchs[] = "/\<a href\=\"space\.php\?(uid|do)+\=([a-z0-9\=\&]+?)\"/ie";
		$preg_searchs[] = "/\<a href\=\"space.php\"/i";
		$preg_searchs[] = "/\<a href\=\"network\.php\?ac\=([a-z0-9\=\&]+?)\"/ie";
		$preg_searchs[] = "/\<a href\=\"network.php\"/i";

		$preg_replaces[] = 'rewrite_url(\'space-\',\'\\2\')';
		$preg_replaces[] = '<a href="space.html"';
		$preg_replaces[] = 'rewrite_url(\'network-\',\'\\1\')';
		$preg_replaces[] = '<a href="network.html"';
	}
	if($_SCONFIG['linkguide']) {
		$preg_searchs[] = "/\<a href\=\"http\:\/\/(.+?)\"/ie";
		$preg_replaces[] = 'iframe_url(\'\\1\')';
	}

	if($_SGLOBAL['inajax']) {
		$preg_searchs[] = "/([\x01-\x09\x0b-\x0c\x0e-\x1f])+/";
		$preg_replaces[] = ' ';

		$str_searchs[] = ']]>';
		$str_replaces[] = ']]&gt;';
	}

	if($preg_searchs) {
		$content = preg_replace($preg_searchs, $preg_replaces, $content);
	}
	if($str_searchs) {
		$content = trim(str_replace($str_searchs, $str_replaces, $content));
	}

	obclean();
	if($_SGLOBAL['inajax']) {
		xml_out($content);
	} else{
		if($_SCONFIG['headercharset']) {
			@header('Content-Type: text/html; charset='.$_SC['charset']);
		}
		echo $content;
		if(D_BUG) {
			@include_once(S_ROOT.'./source/inc_debug.php');
		}
	}
}

这个函数是在parse_template()函数里面被调用的。看如下代码:

//换行
	$template = preg_replace("/ \?\>[\n\r]*\<\? /s", " ", $template);
	
	//附加处理
	$template = "<?php if(!defined('IN_UCHOME')) exit('Access Denied');?><?php subtplcheck('".implode('|', $_SGLOBAL['sub_tpls'])."', '$_SGLOBAL[timestamp]', '$tpl');?>$template<?php ob_out();?>";

在所有的模板解析完成之后,调用函数ob_out(),判断当前的系统有没有开启Rewrite,如果开启了则进行相关正则替换,实现我们开启了伪静态之后看到的那个链接效果。

这个过程中最重要的步骤就是那个ob_out()函数了。

UCHome中各种缓存的实现机制

没有评论

2011 年 03 月 03 日 at 下午 2:04分类:PHP | UCHome | WEB开发

在uchome中的缓存处理中,主要涉及的文件有:function_common.php和function_cache.php这两个函数文件,
此外还有很多相关的操作文件
在uchome的缓存目录data中主要的缓存文件有以下几种形式:对模板htm文件的缓存,对数据配置文件的缓存,和相关数据的缓存。
先来说说对模板文件htm的缓存:
先来看下在function_common.php文件中的这个函数template

function template($name) {
	global $_SCONFIG, $_SGLOBAL;

	if($_SGLOBAL['mobile']) {
		$objfile = S_ROOT.'./api/mobile/tpl_'.$name.'.php';
		if (!file_exists($objfile)) {
			showmessage('m_function_is_disable_on_wap');
		}
	} else {
		if(strexists($name,'/')) {
			$tpl = $name;
		} else {
			//$_SCONFIG[template]为模板风格的变量
			$tpl = "template/$_SCONFIG[template]/$name";
		}
               //------------------------主要部分----------------------------------------
		$objfile = S_ROOT.'./data/tpl_cache/'.str_replace('/','_',$tpl).'.php';
		if(!file_exists($objfile)) {
			include_once(S_ROOT.'./source/function_template.php');
			//解析模板文件
			parse_template($tpl);
		}
                //------------------------主要部分----------------------------------------
	}
	//直接返回解析过的缓存文件
	return $objfile;
}

这是任何一步操作都要执行的函数,他的功能就是加载并解析模板文件,他的这个解析过程其实很简单,首先判断在模板缓存目录下面是否存在该文件的缓存文件,如果存在,那么就直接加载这个缓存文件,输出到浏览器,实现快速解析。那么要是改缓存文件不存在的话,那么就加载function_template.php这个文件,调用这个文件下面的parse_template()函数,我们来看下这个函数

function parse_template(){
    .......
    .......
       //将解析后的代码写入缓存文件中,以便下次直接读取
	if(!swritefile($objfile, $template)) {
		exit("File: $objfile can not be write!");
	}
}

该函数负责解析模板文件里面的相关变量,解析完成之后然后再执行function _common.php文件里面的swritefile()函数,将解析后的代码写入data/tpl_cache/目录下面的缓存文件中,这样子就是实现了模板文件的缓存。
————————————————————————-
再来看下缓存数据文件的生成:
数据文件的缓存文件主要在data目录下面,数据文件的缓存文件名都是以data_开头的。数据文件的缓存实现原理实际上和模板文件的缓存实现的原理是一样的,数据文件的缓存主要用到的文件是function_cache.php文件,我们以配置文件的数据缓存来讲下;配置文件的缓存文件是data_config.php,主要用到的函数是在function_cahce.php文件里面的config_cache()函数,我们来看下这个函数:

//更新配置文件
function config_cache($updatedata=true) {
	global $_SGLOBAL;

	$_SCONFIG = array();
	$query = $_SGLOBAL['db']->query('SELECT * FROM '.tname('config'));
	while ($value = $_SGLOBAL['db']->fetch_array($query)) {
		if($value['var'] == 'privacy') {
			$value['datavalue'] = empty($value['datavalue'])?array():unserialize($value['datavalue']);
		}
		$_SCONFIG[$value['var']] = $value['datavalue'];
	}
	cache_write('config', '_SCONFIG', $_SCONFIG);
       .............
}

function_cache.php文件里面的缓存实现函数只是负责生成相应的数据缓存文件,如果存在了,那就覆盖之。之后调用cache_write()函数,将需要缓存的数据写入指定的缓存文件中,当我们需要调用相关的信息时,我们用以下代码可以实现:

if(!@include_once(S_ROOT.'./data/data_config.php')) {
	include_once(S_ROOT.'./source/function_cache.php');
	config_cache();
	include_once(S_ROOT.'./data/data_config.php');
}

原理是:我们先判断下需要的数据所在的数据缓存文件是否存在,如果存在那么就直接加载之,如果不存在,那么我先加载实现数据缓存的函数文件:function_cache.php文件,然后调用相关的函数就能生成相关的数据缓存文件了,最后在加载改数据缓存文件。
———————————————————————-
还有一种缓存是以txt文档的形式存放的,目录在data/下面,这种缓存文件主要存放的是序列化之后的数组,也就是将一个数组的的数据存放在改文件中。

if(empty($_SCONFIG['networkpublic'])) {
	
	$cachefile = S_ROOT.'./data/cache_index.txt';
	$cachetime = @filemtime($cachefile);
	
	$spacelist = array();
	if($_SGLOBAL['timestamp'] - $cachetime > 900) {
		//20位热门用户(以用户的好友数量为热门标记)
		$query = $_SGLOBAL['db']->query("SELECT s.*, sf.resideprovince, sf.residecity
			FROM ".tname('space')." s
			LEFT JOIN ".tname('spacefield')." sf ON sf.uid=s.uid
			ORDER BY s.friendnum DESC LIMIT 0,20");
		while ($value = $_SGLOBAL['db']->fetch_array($query)) {
			$spacelist[] = $value;
		}
		swritefile($cachefile, serialize($spacelist));
	} else {
		$spacelist = unserialize(sreadfile($cachefile));
	}

上面这段代码就是这个缓存的实现机制,先获取该缓存文件的时间,判断是否已经过期了,如果过期了,那么就从数据库中重新读取数据,然后经过序列化之后调用函数swritefile()将数据写入TXT文档中,如果没有过期,那就直接调用函数sreadfile()获取内容,然后再反序列化一下 就可以了!
以上讲的就是UCHome中三种缓存的实现原理了。。。。