环境:Apache/2.2.21 + PHP/5.3.10 + winXP
背景:ecshop2.7.3 打上补丁、discuz X3.1、ucenter1.6 全部utf-8编码实现同步登录、退出、用户创建

 1、在ucenter中看到的是全部通信成功,但就是无法同步登录,注册新用户也可以同步。而且在ecshop登录的时候还会出现400 Bad Request错误

排查ecshop2.7.3与discuz X3.1同步登录时问题


让最模板极度郁闷,于是挨个的追踪,一直追踪到ecshop/uc_client/client.php中的uc_fopen函数,大致位于178行。看了下,也没有什么问题。到网上到处搜索,众说纷云,有些最模板还是会直接否定掉的。由于网络文章一堆抄。算了。到这个函数这里,最模板准备记录下,它到底发什么数据出去,又接收到什么怎样的数据才显示出400给最模板。
于是又再次抓包:

排查ecshop2.7.3与discuz X3.1同步登录时问题



结果真让人汗颜,返回是正确的结果,为什么用浏览器登录返回却是不正常的。把这些地址复制到同一浏览器里,结果可以同步登录了。晕倒了。问题确定了,是socket出的问题。于是就用curl试了一下,呵呵,登录同步成功。

if(stripos($return, '400 Bad Request') != false  || empty($return)) {
$return = '';
$curl = curl_init(); 
curl_setopt($curl, CURLOPT_URL, $url); 
curl_setopt($curl, CURLOPT_USERAGENT, $_SERVER['HTTP_USER_AGENT']); 
if($post) { 
curl_setopt($curl, CURLOPT_POST, 1); 
curl_setopt($curl, CURLOPT_POSTFIELDS, $post); 

if($cookie) { 
curl_setopt($curl, CURLOPT_COOKIE, $cookie); 

curl_setopt($curl, CURLOPT_TIMEOUT, $timeout); 
curl_setopt($curl, CURLOPT_HEADER, 0); 
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); 
$return = curl_exec($curl); 
if (curl_errno($curl)) { 
//echo '<pre><b>错误:</b><br />'.curl_error($curl); 

curl_close($curl); 
}
另外,再修正下官方的host,因为最模板这里记录下header的时候,host居然为空的,不知道是不是最模板ucenter配置的问题。
$path = $matches['path'] ? $matches['path'].($matches['query'] ? '?'.$matches['query'] : '') : 'http://www.moke8.com/';
$host = empty($matches['host']) ? dirname($path) : $matches['host'];
大约位于184行。


2、上面可以解决ecshop登录,discuz也登录,但ecshop退出,discuz却保持登录状态
修改ecshop/includes/lib_common.php
$res = call_user_func_array($func, empty($params) ? array('0') : $params);    完成上面2步以后,可以实现ecshop登录、退出后,discuz也跟着做同样的动作。


3、一定要将ecshop/uc_client与discuzX/uc_client保持一致
将ecshop/uc_client/data/cache/apps.php与discuzX/uc_client/data/cache/apps.php内容保持一致
将ecshop/uc_client/client.php与discuzX/uc_client/client.php 内容保持一致 

4、从ecshop登录,discuz退出,会出现ecshop没有退出的现象。由于cookie值域的问题。因为discuz在退出的时候会用JS调用到这个api来同步退出。
修改ecshop/api/uc.php中的set_cookie函数,约408行

setcookie('ECS[user_id]', '', $time, $GLOBALS['cookie_path'], $GLOBALS['cookie_domain']);
setcookie('ECS[username]', '', $time, $GLOBALS['cookie_path'], $GLOBALS['cookie_domain']);
setcookie('ECS[email]', '', $time, $GLOBALS['cookie_path'], $GLOBALS['cookie_domain']);

5、ecshop/includes/modules/integrates/ucenter.php
ucenter($cfg)函数(约75行)$this->is_ecshop = 1;后面加入:
$this->cookie_path = $cfg['cookie_path'];
$this->cookie_domain = $cfg['cookie_domain'];

第463行set_cookie($username='')函数加入域范围
/* 摧毁cookie */
$time = time() - 3600;
setcookie("ECS[user_id]", '', $time, $this->cookie_path, $this->cookie_domain); 
setcookie("ECS[password]", '', $time, $this->cookie_path, $this->cookie_domain);



OK,至此ecshop和discuz就可以完全注册登录退出同步了。


PS:如果discuz X3.1在退出时提示:Discuz!  System Error 您当前的访问请求当中含有非法字符,已经被系统拒绝
 可以下载官方的语言包覆盖就行了l 注意此语言包为GBK版


目前,只有注册并同步登录未实现:参考了一下网上的代码,但最模板这里并没有成功
discuz/api/uc.php中synlogin函数第191行
if(($member = getuserbyuid($uid, 1))) {
dsetcookie('auth', authcode("$member[password]\t$member[uid]", 'ENCODE'), $cookietime);
}else{
//下面为增加部分
$username = $get['username']; 
$password = md5(time().rand(100000, 999999));
$email = $get['email'];
$ip = $_SERVER['REMOTE_ADDR'];
$time = time(); 

$userdata = array(
'uid' => $uid,
'username' => $username,
'password' => $password,
'email' => $email,
'adminid' => 0,
'groupid' => 10,
'regdate' => $time,
'credits' => 0,
'timeoffset' => 9999
);
DB::insert('common_member', $userdata);

$status_data = array(
'uid' => $uid,
'regip' => $ip,
'lastip' => $ip,
'lastvisit' => $time,
'lastactivity' => $time,
'lastpost' => 0,
'lastsendmail' => 0,
);
DB::insert('common_member_status', $status_data);
DB::insert('common_member_profile', array('uid' => $uid));
DB::insert('common_member_field_forum', array('uid' => $uid));
DB::insert('common_member_field_home', array('uid' => $uid));
DB::insert('common_member_count', array('uid' => $uid)); 
$query = DB::query("SELECT uid, username, password FROM ".DB::table('common_member')." WHERE uid='$uid'");
if($member = DB::fetch($query)) {
dsetcookie('auth', authcode("$member[password]\t$member[uid]", 'ENCODE'), $cookietime);
}