UCenter 接口
API 接口
以下关于文件的阐述以及代码的样例,均以 PHP 程序为例。
UCenter 的 API 接口文件必须存放于应用程序根目录的“api/”目录中,文件名可以自定义,默认为 uc.php,即“api/uc.php”。文件结构可分为 4 部分,包含 12 个接口项目。第 1 部分为常量定义、第 2 部分为通知方式判断以及初始化输入参数、第 3 部分为接口类代码段、第 4 部分为函数定义。
1、常量定义
define('UC_CLIENT_VERSION', '1.5.0');	//note UCenter 版本标识
define('UC_CLIENT_RELEASE', '20081031');
define('API_DELETEUSER', 1);		//note 用户删除 API 接口开关
define('API_RENAMEUSER', 1);		//note 用户改名 API 接口开关
define('API_GETTAG', 1);		//note 获取标签 API 接口开关
define('API_SYNLOGIN', 1);		//note 同步登录 API 接口开关
define('API_SYNLOGOUT', 1);		//note 同步登出 API 接口开关
define('API_UPDATEPW', 1);		//note 更改用户密码 开关
define('API_UPDATEBADWORDS', 1);	//note 更新关键字列表 开关
define('API_UPDATEHOSTS', 1);		//note 更新域名解析缓存 开关
define('API_UPDATEAPPS', 1);		//note 更新应用列表 开关
define('API_UPDATECLIENT', 1);		//note 更新客户端缓存 开关
define('API_UPDATECREDIT', 1);		//note 更新用户积分 开关
define('API_GETCREDITSETTINGS', 1);	//note 向 UCenter 提供积分设置 开关
define('API_GETCREDIT', 1);		//note 获取用户的某项积分 开关
define('API_UPDATECREDITSETTINGS', 1);	//note 更新应用积分设置 开关
define('API_RETURN_SUCCEED', '1');
define('API_RETURN_FAILED', '-1');
define('API_RETURN_FORBIDDEN', '-2');
				2、通知方式判断以及初始化输入参数
if(!defined('IN_UC')) {
	error_reporting(0);
	set_magic_quotes_runtime(0);
	define('DISCUZ_ROOT', substr(dirname(__FILE__), 0, -3));
	defined('MAGIC_QUOTES_GPC') || define('MAGIC_QUOTES_GPC', get_magic_quotes_gpc());
	require_once DISCUZ_ROOT.'./config.inc.php';
	$_DCACHE = $get = $post = array();
	$code = @$_GET['code'];
	parse_str(_authcode($code, 'DECODE', UC_KEY), $get);
	if(MAGIC_QUOTES_GPC) {
		$get = _stripslashes($get);
	}
	$timestamp = time();
	if($timestamp - $get['time'] > 3600) {
		exit('Authracation has expiried');
	}
	if(empty($get)) {
		exit('Invalid Request');
	}
	$action = $get['action'];
	require_once DISCUZ_ROOT.'./uc_client/lib/xml.class.php';
	$post = xml_unserialize(file_get_contents('php://input'));
	if(in_array($get['action'], array('test', 'deleteuser', 'renameuser', 'gettag', 'synlogin',
	'synlogout', 'updatepw', 'updatebadwords', 'updatehosts', 'updateapps', 'updateclient',
	'updatecredit', 'getcreditsettings', 'updatecreditsettings'))) {
		require_once DISCUZ_ROOT.'./include/db_'.$database.'.class.php';
		$GLOBALS['db'] = new dbstuff;
		$GLOBALS['db']->connect($dbhost, $dbuser, $dbpw, $dbname, $pconnect, true, $dbcharset);
		$GLOBALS['tablepre'] = $tablepre;
		unset($dbhost, $dbuser, $dbpw, $dbname, $pconnect);
		$uc_note = new uc_note();
		exit($uc_note->$get['action']($get, $post));
	} else {
		exit(API_RETURN_FAILED);
	}
} else {
	define('DISCUZ_ROOT', $app['extra']['apppath']);
	require_once DISCUZ_ROOT.'./config.inc.php';
	require_once DISCUZ_ROOT.'./include/db_'.$database.'.class.php';
	$GLOBALS['db'] = new dbstuff;
	$GLOBALS['db']->connect($dbhost, $dbuser, $dbpw, $dbname, $pconnect, true, $dbcharset);
	$GLOBALS['tablepre'] = $tablepre;
	unset($dbhost, $dbuser, $dbpw, $dbname, $pconnect);
}
				3、接口代码段
				接口类名称为 uc_note ,接口名称作为此类的一个方法,uc_note 代码结构大体如下:
				
				
				具体可以参考 Discuz! X2.5 代码中的/api/uc.php
				
class uc_note {
	var $dbconfig = '';
	//var $db = '';
	var $appdir = '';
	function _serialize($arr, $htmlon = 0) {
		if(!function_exists('xml_serialize')) {
			include_once DISCUZ_ROOT.'./uc_client/lib/xml.class.php';
		}
		return xml_serialize($arr, $htmlon);
	}
	function uc_note() {
		$this->appdir = substr(dirname(__FILE__), 0, -3);
		$this->dbconfig = $this->appdir.'./config.inc.php';
	}
	function test($get, $post) {
		return API_RETURN_SUCCEED;
	}
	function deleteuser($get, $post) {
		/*代码省略*/
		return API_RETURN_SUCCEED;
	}
	
	/* 更多接口项目 */
}
				test
					此接口供仅测试连接。当 UCenter 发起 test 的接口请求时,如果成功获取到接口返回的 API_RETURN_SUCCEED 值,表示 UCenter 和应用通讯正常。
				
deleteuser
				当 UCenter 删除一个用户时,会发起 deleteuser 的接口请求,通知所有应用程序删除相应的用户。
输入的参数放在 $get['ids'] 中,值为用逗号分隔的用户 ID。如果删除成功则输出 API_RETURN_SUCCEED。
				
输入的参数放在 $get['ids'] 中,值为用逗号分隔的用户 ID。如果删除成功则输出 API_RETURN_SUCCEED。
deleteuser 接口示例 (PHP)
renameuser
				当 UCenter 更改一个用户的用户名时,会发起 renameuser 的接口请求,通知所有应用程序改名。
输入的参数 $get['uid'] 表示用户 ID,$get['oldusername'] 表示旧用户名,$get['newusername'] 表示新用户名。如果修改成功则输出 API_RETURN_SUCCEED。
				
输入的参数 $get['uid'] 表示用户 ID,$get['oldusername'] 表示旧用户名,$get['newusername'] 表示新用户名。如果修改成功则输出 API_RETURN_SUCCEED。
renameuser 接口示例 (PHP)
updatepw
				当用户更改用户密码时,此接口负责接受 UCenter 发来的新密码。
输入的参数 $get['username'] 表示用户名,$get['password'] 表示新密码。如果修改成功则输出 API_RETURN_SUCCEED。
				
输入的参数 $get['username'] 表示用户名,$get['password'] 表示新密码。如果修改成功则输出 API_RETURN_SUCCEED。
updatepw 接口示例 (PHP)
gettag
				如果应用程序存在标签功能,可以通过此接口把应用程序的标签数据传递给 UCenter。
输入的参数放在 $get['id'] 中,值为标签名称。输出的数组需经过 uc_serialize 处理。
				
					
					
				
输入的参数放在 $get['id'] 中,值为标签名称。输出的数组需经过 uc_serialize 处理。
| integer [0] | 标签名称 | ||
|---|---|---|---|
| array [1] | 标签数据 
 | 
gettag 接口示例 (PHP)
synlogin
				如果应用程序需要和其他应用程序进行同步登录,此部分代码负责标记指定用户的登录状态。
输入的参数放在 $get['uid'] 中,值为用户 ID。此接口为通知接口,无输出内容。同步登录需使用 P3P 标准。
				
输入的参数放在 $get['uid'] 中,值为用户 ID。此接口为通知接口,无输出内容。同步登录需使用 P3P 标准。
synlogin 接口示例 (PHP)
synlogout
updatebadwords
				当 UCenter 的词语过滤设置变更时,此接口负责通知所有应用程序更新后的词语过滤设置内容。
设置内容用 POST 方式提交到接口。接口运行完毕输出 API_RETURN_SUCCEED。
				
设置内容用 POST 方式提交到接口。接口运行完毕输出 API_RETURN_SUCCEED。
updatebadwords 接口示例 (PHP)
updatehosts
				当 UCenter 的域名解析设置变更时,此接口负责通知所有应用程序更新后的域名解析设置内容。
设置内容用 POST 方式提交到接口。接口运行完毕输出 API_RETURN_SUCCEED。
				
设置内容用 POST 方式提交到接口。接口运行完毕输出 API_RETURN_SUCCEED。
updatehosts 接口示例 (PHP)
updateapps
				当 UCenter 的应用程序列表变更时,此接口负责通知所有应用程序更新后的应用程序列表。
设置内容用 POST 方式提交到接口。接口运行完毕输出 API_RETURN_SUCCEED。
				
设置内容用 POST 方式提交到接口。接口运行完毕输出 API_RETURN_SUCCEED。
updateapps 接口示例 (PHP)
updateclient
				当 UCenter 的基本设置信息变更时,此接口负责通知所有应用程序更新后的基本设置内容。
设置内容用 POST 方式提交到接口。接口运行完毕输出 API_RETURN_SUCCEED。
				
设置内容用 POST 方式提交到接口。接口运行完毕输出 API_RETURN_SUCCEED。
updateclient 接口示例 (PHP)
updatecredit
				当某应用执行了积分兑换请求的接口函数 uc_credit_exchange_request() 后,此接口负责通知被兑换的目的应用程序所需修改的用户积分值。
输入的参数 $get['credit'] 表示积分编号,$get['amount'] 表示积分的增减值,$get['uid'] 表示用户 ID。
				
输入的参数 $get['credit'] 表示积分编号,$get['amount'] 表示积分的增减值,$get['uid'] 表示用户 ID。
updatecredit 接口示例 (PHP)
getcreditsettings
				此接口负责把应用程序的积分设置传递给 UCenter,以供 UCenter 在积分兑换设置中使用。
此接口无输入参数。输出的数组需经过 uc_serialize 处理。
输出的数组单条结构:
					
					
				如:
				
此接口无输入参数。输出的数组需经过 uc_serialize 处理。
输出的数组单条结构:
| 1 维 KEY | 2 维 KEY | ||
|---|---|---|---|
| array [n] | 积分编号 | string [0] | 积分名称 | 
| string [1] | 积分单位 | ||
					array(
'1' => array('威望', ''),
'2' => array('金钱', '枚'),
)
				
				'1' => array('威望', ''),
'2' => array('金钱', '枚'),
)
getcreditsettings 接口示例 (PHP)
updatecreditsettings
				此接口负责接收 UCenter 积分兑换设置的参数。
输入的参数放在 $get['credit'] 中,值为设置的参数数组。接口运行完毕输出 API_RETURN_SUCCEED。
输入的数组单条结构:
					
					
				如:
				
输入的参数放在 $get['credit'] 中,值为设置的参数数组。接口运行完毕输出 API_RETURN_SUCCEED。
输入的数组单条结构:
| 1 维 KEY | 2 维 KEY | ||
|---|---|---|---|
| array [appid] | 应用程序 ID | integer ['appiddesc'] | 积分兑换的目标应用程序 ID | 
| integer ['creditdesc'] | 积分兑换的目标积分编号 | ||
| integer ['creditsrc'] | 积分兑换的源积分编号 | ||
| string ['title'] | 积分名称 | ||
| string ['unit'] | 积分单位 | ||
| integer ['ratio'] | 积分兑换比率 | ||
					array(
'1' => array(
'appiddesc' => 2,
'creditdesc' => 1,
'creditsrc' => 1,
'title' => '金钱',
'unit' => '枚',
'ratio' => 2,
),
)
				
				'1' => array(
'appiddesc' => 2,
'creditdesc' => 1,
'creditsrc' => 1,
'title' => '金钱',
'unit' => '枚',
'ratio' => 2,
),
)
updatecreditsettings 接口示例 (PHP)
getcredit
				此接口用于把应用程序中指定用户的积分传递给 UCenter。
输入的参数 $get['uid'] 为用户 ID,$get['credit'] 为积分编号。接口运行完毕输出积分值。
				
输入的参数 $get['uid'] 为用户 ID,$get['credit'] 为积分编号。接口运行完毕输出积分值。
getcredit 接口示例 (PHP)
4、函数定义
				接口函数中必须包含以下函数,否则无法正确对 UCenter 传递过来的数据进行解码。
				
				
				
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));
	}
}
function uc_serialize($arr, $htmlon = 0) {
	include_once UC_CLIENT_ROOT.'./lib/xml.class.php';
	return xml_serialize($arr, $htmlon);
}
function uc_unserialize($s) {
	include_once UC_CLIENT_ROOT.'./lib/xml.class.php';
	return xml_unserialize($s);
}