ucenter采用MVC架构,多数用于同步各个应用中的用户数据,实现用户的一站式注册、登录、退出以及社区其他数据的交互。
简单分析
index.php入口文件
$m = getgpc('m'); //判断加载哪一个Model
$a = getgpc('a'); //判断加载哪一个Control
if(empty($m) && empty($a)) {
header('Location: admin.php');
exit;
}
...
//加载基类,基类中定义了很多的方法,所有控制器类都继承于该基类
if(file_exists(UC_ROOT.RELEASE_ROOT.'model/base.php')) {
require UC_ROOT.RELEASE_ROOT.'model/base.php';
} else {
require UC_ROOT.'model/base.php';
}
...
//判断是否加载的是指定的model
if(in_array($m, array('app', 'frame', 'user', 'pm', 'pm_client', 'tag', 'feed', 'friend', 'domain', 'credit', 'mail', 'version'))) {
if(file_exists(UC_ROOT.RELEASE_ROOT."control/$m.php")) {
include UC_ROOT.RELEASE_ROOT."control/$m.php";
} else {
include UC_ROOT."control/$m.php";
}
$classname = $m.'control'; //构造control类,如$m=user时control就为usercontrol
$control = new $classname();
$method = 'on'.$a; //构造方法名
if(method_exists($control, $method) && $a{0} != '_') {
$data = $control->$method();
echo is_array($data) ? $control->serialize($data, 1) : $data;
exit;
} elseif(method_exists($control, '_call')) { //如果方法存在且不是私有方法则执行该方法
$data = $control->_call('on'.$a, '');
echo is_array($data) ? $control->serialize($data, 1) : $data;
exit;
} else {
exit('Action not found!');
}
}
例子
xxx/index.php?m=user&a=login
这样,就会初始化usercontrol
并调用onlogin
方法。
model层直接与数据库交互,control层与model层交互,得到结果,返回给view。
如果我们要扩展自己的方法该怎么办?
首先,增加model类,定义我们所需要的方法,直接与DB进行交互。
其次,增加control类,并继承自base,定义on{xxxx}方法,与相对的model交互,并返回结果。
同步登录通信原理
原文参考地址:http://www.jb51.net/article/54297.htm
以discuz
登录为例的流程:
- 用户登录discuz,通过logging.php文件中的函数
uc_user_login
对post过来的数据进行验证,也就是对username和password进行验证 - 如果验证成功,将调用文件路径为
uc_client/client.php
中的函数uc_user_synlogin
,在这个函数中调用uc_api_post('user', 'synlogin', array('uid'=>$uid))
- 然后这个函数后向Ucenter的index.php传递数据,index.php接受传递的数据,获得model为user,action为synlogin的值。
- 然后Ucenter的index.php调用
control/user.php
类中的onsynlogin
方法,通过foreach循环,以生成javascript(<script type="text/javascript" src="{应用url?time=时间戳&code=含有用户信息的加密字符串}"></script>
)并加载的方式通知uc应用列表中开启同步登陆的应用进行同步登录;即通过get方式传递给各个应用目录中api下的uc.php一些数据。 - uc.php接收通知并处理get过来的数据,用
authcode
对url中参数code进行解密得出用户信息,以存cookie等方式进行同步登录。
用户信息加密解密使用的函数
function authcode($string, $operation = 'DECODE', $key = '', $expiry = 0) {
$ckey_length = 4;
$key = md5($key ? $key : UC_KEY);
$keya = md5(substr($key, 0, 16));
$keyb = md5(substr($key, 16, 16));
$keyc = $ckey_length ? ($operation == 'DECODE' ? substr($string, 0, $ckey_length): substr(md5(microtime()), -$ckey_length)) : '';
$cryptkey = $keya.md5($keya.$keyc);
$key_length = strlen($cryptkey);
$string = $operation == 'DECODE' ? base64_decode(substr($string, $ckey_length)) : sprintf('%010d', $expiry ? $expiry + time() : 0).substr(md5($string.$keyb), 0, 16).$string;
$string_length = strlen($string);
$result = '';
$box = range(0, 255);
$rndkey = array();
for($i = 0; $i <= 255; $i++) {
$rndkey[$i] = ord($cryptkey[$i % $key_length]);
}
for($j = $i = 0; $i < 256; $i++) {
$j = ($j + $box[$i] + $rndkey[$i]) % 256;
$tmp = $box[$i];
$box[$i] = $box[$j];
$box[$j] = $tmp;
}
for($a = $j = $i = 0; $i < $string_length; $i++) {
$a = ($a + 1) % 256;
$j = ($j + $box[$a]) % 256;
$tmp = $box[$a];
$box[$a] = $box[$j];
$box[$j] = $tmp;
$result .= chr(ord($string[$i]) ^ ($box[($box[$a] + $box[$j]) % 256]));
}
if($operation == 'DECODE') {
if((substr($result, 0, 10) == 0 || substr($result, 0, 10) - time() > 0) && substr($result, 10, 16) == substr(md5(substr($result, 26).$keyb), 0, 16)) {
return substr($result, 26);
} else {
return '';
}
} else {
return $keyc.str_replace('=', '', base64_encode($result));
}
}
authcode()
的四个参数,一般情况下只用到前三个:
$string
提供需要加密的字符串
$operation
加密方式,ENCODE是加密,DECODE是解密
$key
密钥,在整合程序时填写的密钥。