以用戶登錄為例介紹,其它注銷,改密碼,消息,頭像,好友均類同。
- 從用戶xxx在某一應用程序的login.php,輸入用戶名,密碼講起。先用uc_user_login函數到uc_server驗證此用戶和密碼,如正確,則寫入session,寫入cookies,並更新應用程序會員表中的登錄ip,登錄時間。用戶感覺不到這個過程。
- 然后通過uc_user_synlogin通知uc_server 用戶xxx登錄成功,這個過程可能使用ajax,用戶感覺不到通知過程。
- uc_server收到這個消息后,馬上命令手下,把xxx登錄的消息,像令牌環一樣,發給所有願意接收(后台中那個是否開啟同步登錄)這個消息的其它應用程序。其實就是帶參數訪問一下各應用程序的uc.php,用戶感覺不到這個過程。
- 各應用程序靠api下的uc.php來接收uc_server發來的消息,並對uc_server言聽計從,讓干什么就干什么。現在,收到讓xxx用戶在你的程序中登錄的命令,馬上執行。並寫本應用程序的session,並且使用p3p,寫入相同域或不同域的cookies. 用戶感覺不到這個過程。
- 最后所有和uc整合的程序,xxx均登錄成功。用戶從www.test.com/bbs登錄后, 跳到www.test.com/news同樣顯示登錄。因為bbs 和news系統在后台均已登錄。
- 應用程序與uc server的會話結束。
得益於uc設計的精巧過程,整個過程,用戶完全感覺不到ucenter的存在。這是整合程序歷史上的創新。
以下為Supesite的uc_client和ucenter登錄通信過程的一個例子:
1、登錄入口index.php?action=login
//系統頻道 if($_SGET['action'] != 'index') { if(empty($channels['menus'][$_SGET['action']]['upnameid']) && $channels['menus'][$_SGET['action']]['upnameid'] != 'news') { $scriptfile = S_ROOT.'./'.$_SGET['action'].'.php'; } else { $scriptfile = S_ROOT.'./news.php'; } //echo $scriptfile; if(file_exists($scriptfile)) { include_once($scriptfile); exit(); } }
提交登錄action:batch.login.php?action=login
2、登錄處理地址batch.login.php?action=login
include_once(S_ROOT.'./uc_client/client.php'); // 登錄操作及其中涉及到的一些函數: $password = $_POST['password']; $username = $_POST['username']; // 去ucenter進行遠程登錄驗證 $ucresult = uc_user_login($username, $password, $loginfield == 'uid');
如果登錄成功,則查本地用戶信息。如果有更新本地信息,如果沒有插入新的用戶數據保持與ucenter進行同步。
然后同步其他子系統登錄信息:
$msg = $lang['login_succeed'].uc_user_synlogin($members['uid']); function uc_user_synlogin($uid) { $uid = intval($uid); $return = uc_api_post('user', 'synlogin', array('uid'=>$uid)); return $return; }
下面是一些程序代碼與注釋:
1 /** 2 * dfopen 方式取指定的模塊和動作的數據 3 * 4 * @param string $module 請求的模塊 5 * @param string $action 請求的動作 6 * @param array $arg 參數(會加密的方式傳送) 7 * @return string 8 */ 9 function uc_api_post($module, $action, $arg = array()) { 10 $s = $sep = ''; 11 foreach($arg as $k => $v) { 12 $k = urlencode($k); 13 if(is_array($v)) { 14 $s2 = $sep2 = ''; 15 foreach($v as $k2 => $v2) { 16 $k2 = urlencode($k2); 17 $s2 .= "$sep2{$k}[$k2]=".urlencode(uc_stripslashes($v2)); 18 $sep2 = '&'; 19 } 20 $s .= $sep.$s2; 21 } else { 22 $s .= "$sep$k=".urlencode(uc_stripslashes($v)); 23 } 24 $sep = '&'; 25 } 26 $postdata = uc_api_requestdata($module, $action, $s); 27 28 return uc_fopen2(UC_API.'/index.php', 500000, $postdata, '', TRUE, UC_IP, 20); 29 } 30 31 /** 32 * 構造發送給用戶中心的請求數據 33 * 34 * @param string $module 請求的模塊 35 * @param string $action 請求的動作 36 * @param string $arg 參數(會加密的方式傳送) 37 * @param string $extra 附加參數(傳送時不加密) 38 * @return string 39 */ 40 function uc_api_requestdata($module, $action, $arg='', $extra='') { 41 $input = uc_api_input($arg); 42 $post = "m=$module&a=$action&inajax=2&release=".UC_CLIENT_RELEASE."&input=$input&appid=".UC_APPID.$extra; 43 return $post; 44 } 45 46 function uc_api_url($module, $action, $arg='', $extra='') { 47 $url = UC_API.'/index.php?'.uc_api_requestdata($module, $action, $arg, $extra); 48 return $url; 49 } 50 51 function uc_api_input($data) { 52 $s = urlencode(uc_authcode($data.'&agent='.md5($_SERVER['HTTP_USER_AGENT'])."&time=".time(), 'ENCODE', UC_KEY)); 53 return $s; 54 } 55 56 /** 57 * 遠程打開URL 58 * @param string $url 打開的url, 如 http://www.baidu.com/123.htm 59 * @param int $limit 取返回的數據的長度 60 * @param string $post 要發送的 POST 數據,如uid=1&password=1234 61 * @param string $cookie 要模擬的 COOKIE 數據,如uid=123&auth=a2323sd2323 62 * @param bool $bysocket TRUE/FALSE 是否通過SOCKET打開 63 * @param string $ip IP地址 64 * @param int $timeout 連接超時時間 65 * @param bool $block 是否為阻塞模式 66 * @return 取到的字符串 67 */ 68 function uc_fopen2($url, $limit = 0, $post = '', $cookie = '', $bysocket = FALSE, $ip = '', $timeout = 15, $block = TRUE) { 69 $__times__ = isset($_GET['__times__']) ? intval($_GET['__times__']) + 1 : 1; 70 if($__times__ > 2) { 71 return ''; 72 } 73 $url .= (strpos($url, '?') === FALSE ? '?' : '&')."__times__=$__times__"; 74 return uc_fopen($url, $limit, $post, $cookie, $bysocket, $ip, $timeout, $block); 75 } 76 77 function uc_fopen($url, $limit = 0, $post = '', $cookie = '', $bysocket = FALSE, $ip = '', $timeout = 15, $block = TRUE) { 78 $return = ''; 79 $matches = parse_url($url); 80 !isset($matches['host']) && $matches['host'] = ''; 81 !isset($matches['path']) && $matches['path'] = ''; 82 !isset($matches['query']) && $matches['query'] = ''; 83 !isset($matches['port']) && $matches['port'] = ''; 84 $host = $matches['host']; 85 $path = $matches['path'] ? $matches['path'].($matches['query'] ? '?'.$matches['query'] : '') : '/'; 86 $port = !empty($matches['port']) ? $matches['port'] : 80; 87 if($post) { 88 $out = "POST $path HTTP/1.0\r\n"; 89 $out .= "Accept: */*\r\n"; 90 //$out .= "Referer: $boardurl\r\n"; 91 $out .= "Accept-Language: zh-cn\r\n"; 92 $out .= "Content-Type: application/x-www-form-urlencoded\r\n"; 93 $out .= "User-Agent: $_SERVER[HTTP_USER_AGENT]\r\n"; 94 $out .= "Host: $host\r\n"; 95 $out .= 'Content-Length: '.strlen($post)."\r\n"; 96 $out .= "Connection: Close\r\n"; 97 $out .= "Cache-Control: no-cache\r\n"; 98 $out .= "Cookie: $cookie\r\n\r\n"; 99 $out .= $post; 100 } else { 101 $out = "GET $path HTTP/1.0\r\n"; 102 $out .= "Accept: */*\r\n"; 103 //$out .= "Referer: $boardurl\r\n"; 104 $out .= "Accept-Language: zh-cn\r\n"; 105 $out .= "User-Agent: $_SERVER[HTTP_USER_AGENT]\r\n"; 106 $out .= "Host: $host\r\n"; 107 $out .= "Connection: Close\r\n"; 108 $out .= "Cookie: $cookie\r\n\r\n"; 109 } 110 $fp = @fsockopen(($ip ? $ip : $host), $port, $errno, $errstr, $timeout); 111 if(!$fp) { 112 return '';//note $errstr : $errno \r\n 113 } else { 114 stream_set_blocking($fp, $block); 115 stream_set_timeout($fp, $timeout); 116 @fwrite($fp, $out); 117 $status = stream_get_meta_data($fp); 118 if(!$status['timed_out']) { 119 while (!feof($fp)) { 120 if(($header = @fgets($fp)) && ($header == "\r\n" || $header == "\n")) { 121 break; 122 } 123 } 124 125 $stop = false; 126 while(!feof($fp) && !$stop) { 127 $data = fread($fp, ($limit == 0 || $limit > 8192 ? 8192 : $limit)); 128 $return .= $data; 129 if($limit) { 130 $limit -= strlen($data); 131 $stop = $limit <= 0; 132 } 133 } 134 } 135 @fclose($fp); 136 return $return; 137 } 138 }
遠程同步登錄子系統操作之后:
//顯示信息 function showmessage($message, $url_forward='', $second=3, $vars=array()) { global $_SGLOBAL, $_SCONFIG, $_SC, $channels; if(empty($_SGLOBAL['inajax']) && $url_forward && empty($second)) { //直接301跳轉 obclean(); header("HTTP/1.1 301 Moved Permanently"); header("Location: $url_forward"); } else { if(!defined('IN_SUPESITE_ADMINCP')) { $tpl_file = 'showmessage'; $fullpath = 0; include_once(S_ROOT.'./language/message.lang.php'); if(!empty($mlang[$message])) $message = $mlang[$message]; } else { $tpl_file = 'admin/tpl/showmessage.htm'; $fullpath = 1; include_once(S_ROOT.'./language/admincp_message.lang.php'); if(!empty($amlang[$message])) $message = $amlang[$message]; } if(isset($_SGLOBAL['mlang'][$message])) $message = $_SGLOBAL['mlang'][$message]; foreach ($vars as $key => $val) { $message = str_replace('{'.$key.'}', $val, $message); } //顯示 obclean(); if(!empty($url_forward)) { $second = $second * 1000; $message .= "<script>setTimeout(\"window.location.href ='$url_forward';\", $second);</script><ajaxok>"; } include template($tpl_file, $fullpath); ob_out(); } exit(); }