这个项目本来承诺在国庆期间发布的,但后来发现,joomla1.5 Native已经是主流,而研究表明CB1.2已经直接采用joomla1.5框架本身的验证插件进行验证,因此,CB组件不再需要——不少呼吁不装CB的朋友们有福了:-)。

因业余时间完成了Wordpress for Ucenter桥接器并应用于公司站点后,感叹于WP代码的清晰和扩展开发的轻松(将在以后介绍思路),我在今天晚上复核了Joomla1.5框架库的所有代码,重新发现了系统架构设计者的伟大,然后完全重写这个方案(将逐步在blog.treeber.com发布)。

当前已经完成/api/uc.php及附带函数文件,应该能够做到在其他应用中的登录、注销、改名、删除用户等动作均反馈到Joomla1.5中。

而从Joomla1.5中同步至应用中,则将以Joomla1.5自动化插件(bot)及CB插件的形式发布(当前在kolidon本地机器的测试版本尚需修改Authenticate插件中内容,正在设法解决。

如上,今天先放出api/uc.php文件,以供急需的朋友调试后使用(即,用户的登录、注册等均应在其他ucenter支持的应用中完成),api目录中尚需要另一个文件func_joomla_cb_user.inc.php,请在http://blog.treeber.com版本2安装说明一文中下载。

安装办法
在configuration.php相同的目录中新增configuration_ucenter.php文件,加一些预定义常量(不推荐在configuration.php中直接加);
注意事项亦主要在保证joomla中用户最大ID小于Ucenter中最大用户ID(Joomla新安装最佳)。
× 特别注意1:
当前代码仅供试验,使用此方案后,您的joomla中的用户密码极可能与实际密码不符!此问题将在此方案的完整版和安装说明放出后得到解决。
× 特别注意2:
目前需要修改源码,文件plugins/authentication/joomla.php中
约88行,将
$testcrypt = JUserHelper::getCryptedPassword($credentials['password'], $salt);
改为
if($options['checkpassword']=='skip')
$testcrypt = $crypt;
else
$testcrypt = JUserHelper::getCryptedPassword($credentials['password'], $salt);

<!--p
/**
 * UCenter 应用程序接口 for joomla1.5.x版(discuz, xspace等comsenz系程序社区化功能与joomla1.0.x的完美整合)
 * ucenter for joomla,KOLIDON version 3.1
 ucenter支持的各类应用程序中的用户、站内短消息、好友、积分、头像,可自动同步到joomla1.5.x中。
 
 本程序基于comsenz 提供的ucenter开放的API接口进行开发,安装请参见作者个人站点。
 * @Author:	kolidon@gmail.com
 * @Site:	http://blog.treeber.com
 * licensing under CCA3.0
 **/
 
define('UC_VERSION', '1.0.0');		//UCenter 版本标识
 
define('API_DELETEUSER', 1);		//用户删除 API 接口开关
define('API_RENAMEUSER', 1);		//用户改名 API 接口开关
define('API_UPDATEPW', 1);		//用户改密码 API 接口开关
define('API_GETTAG', 0);		//获取标签 API 接口开关
define('API_SYNLOGIN', 1);		//同步登录 API 接口开关
define('API_SYNLOGOUT', 1);		//同步登出 API 接口开关
define('API_UPDATEBADWORDS', 0);	//更新关键字列表 开关
define('API_UPDATEHOSTS', 1);		//更新域名解析缓存 开关
define('API_UPDATEAPPS', 1);		//更新应用列表 开关
define('API_UPDATECLIENT', 1);		//更新客户端缓存 开关
define('API_UPDATECREDIT', 0);		//更新用户积分 开关
define('API_GETCREDITSETTINGS', 1);	//向 UCenter 提供积分设置 开关
define('API_UPDATECREDITSETTINGS', 0);	//更新应用积分设置 开关
 
define('API_RETURN_SUCCEED', '1');
define('API_RETURN_FAILED', '-1');
define('API_RETURN_FORBIDDEN', '-2');
 
//error_reporting(E_ALL);
 
//joomla library include files check this constant;
define( '_VALID_MOS', 1 );
define('UC_API', 1);
define('MAGIC_QUOTES_GPC', get_magic_quotes_gpc());
 
define('S_ROOT', substr(dirname(__FILE__), 0, -3));
define('UC_CLIENT_ROOT', S_ROOT.'./uc_client/');
 
include_once('func_joomla_cb_user.inc.php');
 
define( '_JEXEC', 1 );
define('JPATH_BASE', S_ROOT );
define( 'DS', DIRECTORY_SEPARATOR );
require_once ( JPATH_BASE .DS.'includes'.DS.'defines.php' );
require_once ( JPATH_BASE .DS.'includes'.DS.'framework.php' );
 
$mainframe =&#038; JFactory::getApplication('site');
$mainfram-->initialise();
$database = &amp; JFactory::getDBO();
 
include_once(UC_CLIENT_ROOT.'./client.php');
//var_dump($database);
 
$code = $_GET['code'];
parse_str(uc_authcode($code, 'DECODE', UC_KEY), $get);
 
if(MAGIC_QUOTES_GPC) {
	$get = dstripslashes($get);
}
 
if(time() - $get['time'] &gt; 3600) {
	exit('Authracation has expiried');
}
if(empty($get)) {
	exit('Invalid Request');
}
$action = $get['action'];
$timestamp = time();
 
if($action == 'test') {
 
	exit(API_RETURN_SUCCEED);
 
} elseif($action == 'deleteuser') {
 
	!API_DELETEUSER &amp;&amp; exit(API_RETURN_FORBIDDEN);
 
	//删除用户 API 接口
	$uids = $get['ids'];
 
	//todo:: clean all the content\pictures\files\videos, set their userid to 0
 
	//delete the user in joomla systable and comprofiler
	$database-&gt;setQuery("DELETE FROM #__users WHERE id IN ($uids);");
	$database-&gt;query();
 
	$database-&gt;setQuery("select aro_id FROM #__core_acl_aro WHERE value IN ($uids);");
	$aro_id = $database-&gt;loadResult();
 
	$database-&gt;setQuery("DELETE FROM #__core_acl_groups_aro_map WHERE aro_id IN ($aro_id);");
	$database-&gt;query();
 
	$database-&gt;setQuery("DELETE FROM #__core_acl_aro WHERE `value` IN ($uids);");
	$database-&gt;query();
 
	$database-&gt;setQuery("DELETE FROM #__comprofiler WHERE user_id IN ($uids);");
	$database-&gt;query();
 
	exit(API_RETURN_SUCCEED);
 
} elseif($action == 'renameuser') {
 
	!API_RENAMEUSER &amp;&amp; exit(API_RETURN_FORBIDDEN);
 
	//用户改名 API 接口
	$id = $get['uid'];
	$usernamenew = $get['newusername'];
	$activeuser = uc_get_user($id, 1);
 
	//todo, the very first,we need to syn all the user table to prevent the username or id collision
	//Now we imagine everything is ok
 
	//if joomla user not exsits, add it
	checkuserexists_user($activeuser);
	$database-&gt;setQuery("update #__users set username='$usernamenew' WHERE id IN ($id);");
	$database-&gt;query();
 
	//if user in comprofiler not exsits, add it
	checkuserexists_comprofiler($activeuser);
 
	exit(API_RETURN_SUCCEED);
 
} elseif($action == 'updatepw') {
 
	!API_UPDATEPW &amp;&amp; exit(API_RETURN_FORBIDDEN);
 
	//此处问题在于更新的ucenter版本中已经不再提供password
	//因此,问题留待本地登录同步成功通知ucenter前重生成,或索性将joomla1.5中密码废弃
	//若废弃密码,则用户在joomla1.5中登录时,应向ucenter查询用户密码正确性
	$username = $get['username'];
	$password = $get['password'];
 
	$activeuser = uc_get_user($username);
	checkuserexists_user($activeuser);
	checkuserexists_comprofiler($activeuser);
 
	$database-&gt;setQuery("update #__users set password='". md5($password) ."' WHERE username ='$username';");
	$database-&gt;query();
	//遗留代码
 
	exit(API_RETURN_SUCCEED);
 
} elseif($action == 'synlogin' &amp;&amp; $_GET['time'] == $get['time']) {
	//echo "hello";
	!API_SYNLOGIN &amp;&amp; exit(API_RETURN_FORBIDDEN);
 
	//同步登录 API 接口
	$id = intval($get['uid']);
 
	// is uer exists?
	$activeuser = uc_get_user($id, 1);
 
	checkuserexists_user($activeuser);
	checkuserexists_comprofiler($activeuser);
 
	$database-&gt;setQuery("select username, password from #__users where id=$id");
	list($username, $password) = $database-&gt;loadRow();
	//exit($username.$password);
	header('P3P: CP="NOI ADM DEV PSAi COM NAV OUR OTRo STP IND DEM"');
	$mainframe-&gt;login( array( 'username' =&gt; $username, 'password' =&gt; $password ), array( 'checkpassword' =&gt; 'skip' ) );
	exit(API_RETURN_SUCCEED);
} elseif($action == 'synlogout') {
 
	!API_SYNLOGOUT &amp;&amp; exit(API_RETURN_FORBIDDEN);
 
	//同步登出 API 接口
	//当前应不需去除session表中记录
	header('P3P: CP="NOI ADM DEV PSAi COM NAV OUR OTRo STP IND DEM"');              // needed for IE6 to accept this anti-spam cookie in higher security setting.
	$mainframe-&gt;logout();
} else {
	exit(API_RETURN_FAILED);
}
 
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 &lt;= 255; $i++) {
		$rndkey[$i] = ord($cryptkey[$i % $key_length]);
	}
 
	for($j = $i = 0; $i &lt; 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 &lt; $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() &gt; 0) &amp;&amp; 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 dsetcookie($var, $value, $life = 0, $prefix = 1) {
	global $cookiedomain, $cookiepath, $timestamp, $_SERVER;
	setcookie($var, $value,
		$life ? $timestamp + $life : 0, $cookiepath,
		$cookiedomain, $_SERVER['SERVER_PORT'] == 443 ? 1 : 0);
}
 
function dstripslashes($string) {
	if(is_array($string)) {
		foreach($string as $key =&gt; $val) {
			$string[$key] = dstripslashes($val);
		}
	} else {
		$string = stripslashes($string);
	}
	return $string;
}