/ php

架設discuz與ucenter應用同步登入筆記

Discuz!是個可免費下載的PHP網絡論壇程式,簡稱DZ,由戴志康(Crossday)所創立,目前最新版本是X2.5。[2] 前身為Crossday Bulletin(CDB),最初改自XMB,爾後改寫成為現今的Discuz!社群論壇程式,由康盛創想所有。現在Discuz!已成為大中華地區最多用戶使用的論壇程序。
Discuz!的原始碼可免費下載,但它并不是開源軟件,因為其許可證不符合開放原始碼的定義。from wiki

discuz論壇的架設只要參照官方論壇的說明就沒有問題了,這裡將著重在第三方php網站整合ucenter。ucenter在與其他php應用整合上的流程與架構示意圖大概如下圖:
http://www.xianyunyehe.com/wp-content/uploads/2012/12/125953P2y.png

在所有ucenter的應用中,都是透過uc.php這個檔案來做listening,再根據指示做相對應的動作(如:登入、登出等)。流程大概是,假設ucenter共有A, B這兩個應用,當A透過client.php發出同步登入成功指示給ucenter,接著uc service再去發出登入的指示給下面所有應用(A, B),透過呼叫每個應用的uc.php,帶入相對應動作的get參數。

一開始先去此處下載ucenter的source code,我們需要裡面的advanced資料夾,解壓縮後將examples內的所有檔案與資料夾,還有uc_client資料夾,複製至自己的應用目錄下,如下圖檔案結構

http://farm9.staticflickr.com/8097/8419047827_c784387033.jpg

假設ucenter server已經架設完畢(筆者使用已整合ucenter的discuz版本),第一個動作便是要註冊欲整合的應用至ucenter內,如下圖
http://farm9.staticflickr.com/8184/8420111462_d5774fcd77_b.jpg

完成應用的註冊後,回到應用管理的頁面,確認第三方應用是否通信成功(最主要即是能連到第三方應用的api/uc.php這個檔案),如下圖
http://farm9.staticflickr.com/8368/8419047399_9859eea56d_b.jpg

通信成功剩下的就是針對登入、登出、註冊等做相對應的動作,這裡我的情境是有ucenter, discuz跟第三方應用,即ucenter搭配兩個應用。需求是當第三方應用登入時,要一併新增帳號並登入至discuz論壇內(透過ucenter同步登入功能),而這裡安裝的是已整合ucenter的discuz論壇,所以處理上比較單純,只要專注在修改discuz內api/uc.php這個檔案,並且另外寫個登入介接的php檔案連結即可。

有幾個ucenter的函式要稍微關心一下:

  • uc_user_login: 使用者帳號與密碼登入ucenter
  • uc_authcode: 建立ucenter登入成功的cookie內容
  • uc_user_synlogin: 發佈同步登入訊息給ucenter,通知其他應用也一併登入
  • uc_user_register: 註冊帳號至ucenter

以上這幾個函式都在uc_client/client.php這檔案內,使用前include即可。

大致的流程為:interface.php(登入介接)確認第三方應用登入成功 -> 利用client.php內的函式同步登入到ucenter與其他應用內 -> ucenter service會同步發佈登入成功通知到各個應用內的uc.php -> 接著即呼叫相對應的函式設定cookie同步登入。
http://www.xianyunyehe.com/wp-content/uploads/2012/12/1250595QL.png

<?php
include './config/config_ucenter.php';
include './uc_client/client.php';

list($uid, $username, $password, $email) = uc_user_login($username, $password);
setcookie('Example_auth', '', -86400);
if($uid > 0) {
	//用戶登陸成功,設置 Cookie,加密直接用 uc_authcode 函數,用戶使用自己的函數
	setcookie('Example_auth', uc_authcode($uid."\t".$username, 'ENCODE'));
	//生成同步登錄的代碼
	$ucsynlogin = uc_user_synlogin($uid);
	echo $ucsynlogin;	// output the javascript code to sync login
} else {
	// register to ucenter
	$uid = uc_user_register($username, $password, "[email protected]");
	if($uid <= 0) {
		if($uid == -1) {
			echo '用戶名不合法';
		} elseif($uid == -2) {
			echo '包含要允許註冊的詞語';
		} elseif($uid == -3) {
			echo '用戶名已經存在';
		} elseif($uid == -4) {
			echo 'Email 格式有誤';
		} elseif($uid == -5) {
			echo 'Email 不允許註冊';
		} elseif($uid == -6) {
			echo '該 Email 已經被註冊';
		} else {
			echo '未定義';
		}
	} else {
		//註冊成功,設置 Cookie,加密直接用 uc_authcode 函數,用戶使用自己的函數
		setcookie('Example_auth', uc_authcode($uid."\t".$username, 'ENCODE'));
		$ucsynlogin = uc_user_synlogin($uid);
		echo $ucsynlogin;	// output the javascript code
	}
}
?>

sync是根據ucenter的account,若該username沒在ucenter內要先註冊再發佈同步登入訊息(注意username最少3個字元)。當ucenter登入成功並發佈同步訊息後,會呼叫每個應用api/uc.php的synlogin函式。在這需要針對discuz沒有此帳號即註冊至資料庫內並登入的動作。

<?php
function synlogin($get, $post) {
  global $_G;
  if(!API_SYNLOGIN) {
    return API_RETURN_FORBIDDEN;
  }

  header('P3P: CP="CURa ADMa DEVa PSAo PSDo OUR BUS UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR"');

  $cookietime = 31536000;
  $uid = intval($get['uid']);
  if(($member = getuserbyuid($uid, 1))) {
    dsetcookie('auth', authcode("$member[password]\t$member[uid]", 'ENCODE'), $cookietime);
  } else { //非激活狀態下寫入
	$query = DB::query("SELECT email FROM ".DB::table('ucenter_members')." WHERE uid='$uid'");
    if($a = DB::fetch($query)){
      $email = $a['emaiil'];
	}else{
	  $email = '';
	  }
	  $userdata = array(
        'uid' => $get['uid'],
        'username' => $get['username'],
        'password' => $get['password'],
        'email' => $email,
        'adminid' => 0,
        'groupid' => 10,
        'regdate' => $get['time'],
        'credits' => 0,
        'timeoffset' => 9999
	 );

   $tmp = DB::insert('common_member', $userdata);
   $tmp = DB::insert('common_member_count', array('uid'=>$get['uid']));
   dsetcookie('auth', authcode("$get[password]\t$get[uid]", 'ENCODE'), $cookietime);
  }
}
?>

done.

Reference#