Yii框架应用程序整合Ucenter实现同步注册、登录和退出等

  •   
  • 4011
  • PHP
  • 2
  • super_dodo
  • 2014/08/28

如今很多网站都要整合论坛程序,而康盛的Discuz系列产品往往是首选。然后就有了整合用户的需要,康盛提供了Ucenter架构,方便对不同的应用程序进行单点登录整合。

进来我尝试将ucenter整合到Yii网站中,获得了成功,虽然登录同步程序不是很妥当,基本使用没有问题了。我将继续改进。下面说说步骤:

下载安装ucenter和discuz,我使用的是ucenter1.6和discuz7.2,由于7.2自带的uc_client是旧版本,所以需要覆盖一下1.6版本。
复制一份uc_client文件夹到 protected/vendors/下,然后建立一个ucenter.php文件,内容如下:

<?php  
include dirname(__FILE__).'/../config/main.php';  
include dirname(__FILE__).'/uc_client/client.php';  
&#91;/php&#93;
可以看到这里只是包含了两个文件。

然后打开yii的主配置文件 protected/config/main.php,加入ucenter的一些全局变量的设置:
&#91;php&#93;
<?php  
define('UC_CONNECT', 'mysql');              // 连接 UCenter 的方式: mysql/NULL, 默认为空时为 fscoketopen()  
                                            // mysql 是直接连接的数据库, 为了效率, 建议采用 mysql  
//数据库相关 (mysql 连接时, 并且没有设置 UC_DBLINK 时, 需要配置以下变量)  
define('UC_DBHOST', 'localhost');           // UCenter 数据库主机  
define('UC_DBUSER', 'root');                // UCenter 数据库用户名  
define('UC_DBPW', '');                  // UCenter 数据库密码  
define('UC_DBNAME', '027xfbbs');                // UCenter 数据库名称  
define('UC_DBCHARSET', 'utf8');             // UCenter 数据库字符集  
define('UC_DBTABLEPRE', '027xfbbs.uc_');            // UCenter 数据库表前缀  
  
//通信相关  
define('UC_KEY', 'ebR4GhhpZB7e9Mhb');               // 与 UCenter 的通信密钥, 要与 UCenter 保持一致  
define('UC_API', 'http://027xf.test/ucenter');  // UCenter 的 URL 地址, 在调用头像时依赖此常量  
define('UC_CHARSET', 'utf8');               // UCenter 的字符集  
define('UC_IP', '');                    // UCenter 的 IP, 当 UC_CONNECT 为非 mysql 方式时, 并且当前应用服务器解析域名有问题时, 请设置此值  
define('UC_APPID', 2);                  // 当前应用的 ID  
  
// uncomment the following to define a path alias  
// Yii::setPathOfAlias('local','path/to/local-folder');  
  
// This is the main Web application configuration. Any writable  
// CWebApplication properties can be configured here.  
return array(  
    'basePath'=>dirname(__FILE__).DIRECTORY_SEPARATOR.'..',  
  
.....  

请根据你的情况修改上面的数据库名等设置。

实现同步注册,我采用的是定义了表单RegisterForm来处理用户的注册,下面是一个典型的注册表单及其验证和业务逻辑代码:

<?php  
  
/** 
 * LoginForm class. 
 * LoginForm is the data structure for keeping 
 * user login form data. It is used by the 'login' action of 'SiteController'. 
 */  
class RegisterForm extends CFormModel  
{  
    public $username;  
    public $password;  
    public $repassword;  
    public $email;  
    public $verifyCode;  
  
    /** 
     * Declares the validation rules. 
     * The rules state that username and password are required, 
     * and password needs to be authenticated. 
     */  
    public function rules()  
    {  
        return array(  
            // username and password are required  
            array('username, password, repassword, email, verifyCode', 'required'),  
            array('username', 'length', 'max'=>20, 'min'=>5),  
            // 用户名唯一性验证  
            //array('username', 'unique','caseSensitive'=>false,'className'=>'user','message'=>'用户名"{value}"已经被注册,请更换'),  
            array('username', 'checkname'),  
            // 密码一致性验证  
            array('repassword', 'compare', 'compareAttribute'=>'password','message'=>'两处输入的密码并不一致'),  
            // 电子邮件验证  
            array('email', 'email'),  
            // 电子邮件唯一性  
            //array('email', 'unique','caseSensitive'=>false,'className'=>'user','message'=>'电子邮件"{value}"已经被注册,请更换'),  
            array('email', 'checkemail'),  
            //array('birthday', 'match', 'pattern'=>'%^\d{4}(\-|\/|\.)\d{1,2}\1\d{1,2}$%', 'allowEmpty'=>true, 'message'=>'生日必须是年-月-日格式'),  
            //array('mobile', 'length', 'max'=>11, 'min'=>11, 'tooLong'=>'手机号码错误','tooShort'=>'手机号码错误'),  
            array('verifyCode', 'captcha', 'allowEmpty'=> false),  
        );  
    }  
  
    public function checkname($attribute,$params)  
    {  
        //ucenter  
        Yii::import('application.vendors.*');  
        include_once 'ucenter.php';  
        $flag = uc_user_checkname($this->username);  
          
        switch($flag)  
        {  
            case -1:  
                $this->addError('username', '用户名不合法');  
                break;  
            case -2:  
                $this->addError('username','包含不允许注册的词语');  
                break;  
            case -3:  
                $this->addError('username','用户名已经存在');  
                break;  
        }  
    }  
      
    public function checkemail($attribute,$params)  
    {  
        //ucenter  
        Yii::import('application.vendors.*');  
        include_once 'ucenter.php';  
        $flag = uc_user_checkemail($this->email);  
  
        switch($flag)  
        {  
            case -4:  
                $this->addError('email', 'Email 格式有误');  
                break;  
            case -5:  
                $this->addError('email','Email 不允许注册');  
                break;  
            case -6:  
                $this->addError('email','该 Email 已经被注册');  
                break;  
        }  
    }  
  
    /** 
     * Declares attribute labels. 
     */  
    public function attributeLabels()  
    {  
        return array(  
            'username'=>'设定用户名',  
            'password'=>'设定密码',  
            'repassword'=>'再次输入密码',  
            'email'=>'电子邮件地址',  
            'mobile'=>'手机号码',  
            'verifyCode'=>'验证码',  
        );  
    }  
  
    /** 
     * 注册用户 
     * @return boolean whether register is successful 
     */  
    public function register($uid)  
    {  
        //ucenter  
        Yii::import('application.vendors.*');  
        include_once 'ucenter.php';  
        $uid = uc_user_register($this->username, $this->password, $this->email);  
        if($uid>0)  
        {  
            $model = new user;  
            $model->attributes = $_POST['RegisterForm'];  
            $model->password = md5($_POST['RegisterForm']['password']);  
            $model->id = $uid;  
              
            return $model->save();  
        }  
    }  
} 

我们看看上面的代码,调用了uc_user_checkname和uc_user_checkemail完成了用户名和email的验证,然后调用了 uc_user_register将用户注册到ucenter,成功后,再注册到Yii应用。

实现用户登录,典型的Yii应用使用 CUserIdentity来实现登录,我们要做的就是继承它,实现自己的验证逻辑:

<?php  
  
/** 
 * UserIdentity represents the data needed to identity a user. 
 * It contains the authentication method that checks if the provided 
 * data can identity the user. 
 */  
class UserIdentity extends CUserIdentity  
{     
    public $id;  
    /** 
     * Authenticates a user. 
     * The example implementation makes sure if the username and password 
     * are both 'demo'. 
     * In practical applications, this should be changed to authenticate 
     * against some persistent user identity storage (e.g. database). 
     * @return boolean whether authentication succeeds. 
     */  
    public function authenticate()  
    {  
        //ucenter  
        Yii::import('application.vendors.*');  
        include_once 'ucenter.php';  
        list($uid, $username, $password, $email) = uc_user_login($this->username, $this->password);  
        if($uid > 0)  
        {  
            $user = user::model()->findByPk($uid);  
              
            if($user == null)//说明网站数据库中没有,而ucenter中有这个用户,添加用户  
            {  
                $user = new user;  
                $user->username = $username;  
                $user->password = md5($password);  
                $user->email = $email;  
                $user->id = $uid;  
                $user->save();  
                  
                $user->refresh();  
            }  
              
            $this->username = $user->username;  
            $this->id = $user->id;  
              
            $user->last_login_time = $user->this_login_time;  
            $user->this_login_time = time();  
            $user->last_login_ip = $user->this_login_ip;  
            $user->this_login_ip = Yii::app()->getRequest()->userHostAddress;  
            $user->save();   
              
            $this->errorCode=self::ERROR_NONE;  
        }  
        elseif($uid == -1)  
        {  
            $this->errorCode=self::ERROR_USERNAME_INVALID;  
        }  
        elseif($uid == -2)  
        {  
            $this->errorCode=self::ERROR_PASSWORD_INVALID;  
        }  
          
        return !$this->errorCode;  
    }  
      
    public function getId()  
    {  
        return $this->id;  
    }  
}  

请根据自己的应用情况进行修改即可,这里我们不需要对Yii的用户登录做任何修改。

然后我们修改 SiteController/actionLogin 方法,将同步登录其他应用的js输出到浏览器:

/** 
     * Displays the login page 
     */  
    public function actionLogin()  
    {  
        $model=new LoginForm;  
  
        // if it is ajax validation request  
        if(isset($_POST['ajax']) && $_POST['ajax']==='login-form')  
        {  
            echo CActiveForm::validate($model);  
            Yii::app()->end();  
        }  
  
        // collect user input data  
        if(isset($_POST['LoginForm']))  
        {  
            $model->attributes=$_POST['LoginForm'];  
            // validate user input and redirect to the previous page if valid  
            if($model->validate() && $model->login())  
            {  
                //ucenter  
                Yii::import('application.vendors.*');  
                include_once 'ucenter.php';  
                $script = uc_user_synlogin(Yii::app()->user->id);  
                $this->render('loginsuc', array(  
                    'script' => $script,  
                ));  
                Yii::app()->end();  
            }  
        }  
        // display the login form  
        $this->render('login',array('model'=>$model));  
    } 

简单的loginsuc.php视图文件:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">  
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">  
<head>  
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />  
</head>  
<body>  
<?php   
$this->layout = 'none';  
echo $script;   
?>  
<script type="text/javascript">setTimeout('location.href="<?php echo Yii::app()->user->returnUrl ?>"',3000);</script>  
登录成功,正在返回登录前页面...  
</body>  
</html> 

继续修改 SiteController/actionLogout方法,实现同步退出:

/** 
     * Logs out the current user and redirect to homepage. 
     */  
    public function actionLogout()  
    {  
        Yii::app()->user->logout();  
        //ucenter  
        Yii::import('application.vendors.*');  
        include_once 'ucenter.php';  
        $script = uc_user_synlogout();  
        $this->render('logoutsuc', array(  
            'script' => $script,  
        ));  
        Yii::app()->end();  
    } 

简单的logoutsuc.php视图文件:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">  
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">  
<head>  
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />  
</head>  
<body>  
<?php   
$this->layout = 'none';  
echo $script;   
?>  
<script type="text/javascript">setTimeout('location.href="<?php echo Yii::app()->homeUrl ?>"',3000);</script>  
退出成功,正在返回首页...  
</body>  
</html>  

进行到这里,我们已经实现了整合ucenter的登录和注册了,这样ucenter中有的用户,可以登录到yii应用,yii应用也可以注册用户到ucenter了。但是这还没有完成,我们需要的是在discuz中用户登录时,也同步登录yii应用,退出亦然,那么我们需要实现 Yii应用的 api/uc.php 这个接口程序。由于我们要用到Yii的框架资源,所以我没有采用硬编码的方式实现这个接口,而是创建了一个UcApplication类完成这个任务,继续往下看。

首先建立 api/uc.php 入口文件,代码如下:

<?php  
define('UC_CLIENT_VERSION', '1.6.0');  
define('UC_CLIENT_RELEASE', '20110501');  
  
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');  
  
// change the following paths if necessary  
$yii=dirname(__FILE__).'/../protected/yii-1.1.6/framework/yii.php';  
$config=dirname(__FILE__).'/../protected/config/main.php';  
  
// remove the following lines when in production mode  
defined('YII_DEBUG') or define('YII_DEBUG',true);  
// specify how many levels of call stack should be shown in each log message  
defined('YII_TRACE_LEVEL') or define('YII_TRACE_LEVEL',0);  
  
require_once($yii);  
require(dirname(__FILE__).'/../protected/components/UcApplication.php');  
Yii::createApplication('UcApplication', $config)->run();  

这里可以看到,这个脚本和标准的index.php是一样的,只是使用了不同的Application类。我们接着看这个类。
建立 protected/components/UcApplication.php类文件:

<?php  
class UcApplication extends CWebApplication  
{  
    public $defaultController = 'Uc';  
      
    private $route = '';  
      
    protected function preinit()  
    {  
        $this->parseRequest();  
    }  
      
    private function parseRequest()  
    {  
        $_DCACHE = $get = $post = array();  
  
        $code = @$_GET['code'];  
        parse_str($this->_authcode($code, 'DECODE', UC_KEY), $get);  
        if(MAGIC_QUOTES_GPC) {  
            $get = $this->_stripslashes($get);  
        }  
          
        $timestamp = time();  
        if($timestamp - $get['time'] > 3600) {  
            //exit('Authracation has expiried');  
        }  
        if(emptyempty($get)) {  
            exit('Invalid Request');  
        }  
        $action = $get['action'];  
          
        require_once 'xml.class.php';  
        $post = xml_unserialize(file_get_contents('php://input'));  
        Yii::log($get, 'debug');  
        Yii::log($post, 'debug');  
        $_GET = $get;  
        $_POST = $post;  
          
        $this->route = $this->defaultController .'/'. $action;  
          
        if(!in_array($action, array('test', 'deleteuser', 'renameuser', 'gettag', 'synlogin', 'synlogout', 'updatepw', 'updatebadwords', 'updatehosts', 'updateapps', 'updateclient', 'updatecredit', 'getcreditsettings', 'updatecreditsettings')))   
        {  
            exit(API_RETURN_FAILED);  
        }  
    }  
      
    public function processRequest()  
    {  
        $this->runController($this->route);  
    }  
      
    private 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&#91;$i&#93; = ord($cryptkey&#91;$i % $key_length&#93;);  
        }  
      
        for($j = $i = 0; $i < 256; $i++) {  
            $j = ($j + $box&#91;$i&#93; + $rndkey&#91;$i&#93;) % 256;  
            $tmp = $box&#91;$i&#93;;  
            $box&#91;$i&#93; = $box&#91;$j&#93;;  
            $box&#91;$j&#93; = $tmp;  
        }  
      
        for($a = $j = $i = 0; $i < $string_length; $i++) {  
            $a = ($a + 1) % 256;  
            $j = ($j + $box&#91;$a&#93;) % 256;  
            $tmp = $box&#91;$a&#93;;  
            $box&#91;$a&#93; = $box&#91;$j&#93;;  
            $box&#91;$j&#93; = $tmp;  
            $result .= chr(ord($string&#91;$i&#93;) ^ ($box&#91;($box&#91;$a&#93; + $box&#91;$j&#93;) % 256&#93;));  
        }  
      
        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));  
        }  
      
    }  
  
    private function _stripslashes($string) {  
        if(is_array($string)) {  
            foreach($string as $key => $val) {  
                $string[$key] = $this->_stripslashes($val);  
            }  
        } else {  
            $string = stripslashes($string);  
        }  
        return $string;  
    }  
}

这里可以看到,主要逻辑是processRequest方法,实现了ucenter通知的解码、调用相应的控制器和动作实现操作。
然后建立 protected/controller/UcController.php文件,代码如下:

<?php  
class UcController extends Controller  
{  
    private $appdir = '';  
      
    protected function beforeAction(CAction $action)  
    {  
        $this->appdir = Yii::app()->basePath . '/vendors/';  
        return parent::beforeAction($action);  
    }  
      
    public function actionTest() {  
        echo API_RETURN_SUCCEED;  
    }  
  
    public function actionDeleteuser() {  
        $uids = explode(',', str_replace("'", '', $_GET['ids']));  
        !API_DELETEUSER && exit(API_RETURN_FORBIDDEN);  
          
        $users = user::model()->findAllByPk($uids);  
        foreach($users as $user)  
        {  
            $user->delete();  
        }  
  
        echo API_RETURN_SUCCEED;  
    }  
  
    public function actionRenameuser() {  
        $uid = $_GET['uid'];  
        $usernameold = $_GET['oldusername'];  
        $usernamenew = $_GET['newusername'];  
        if(!API_RENAMEUSER) {  
            echo API_RETURN_FORBIDDEN;  
        }  
          
        $user = user::model()->findByPk($uid);  
        if($user !== null)  
        {  
            $user->username = $usernamenew;  
            if($user->save(false))  
                echo API_RETURN_SUCCEED;  
            else  
                echo API_RETURN_FAILED;  
        }  
    }  
  
    public function actionGettag() {  
        $name = $_GET['id'];  
        if(!API_GETTAG) {  
            echo API_RETURN_FORBIDDEN;  
        }  
          
        $echo = array();  
        echo $this->_serialize($return, 1);  
    }  
  
    public function actionSynlogin() {  
        $uid = $_GET['uid'];  
        $username = $_GET['username'];  
        if(!API_SYNLOGIN) {  
            echo API_RETURN_FORBIDDEN;  
        }  
          
        $identity=new UcUserIdentity($username);  
  
        if($identity->authenticate())  
        {  
            Yii::app()->user->login($identity, 0);  
        }  
  
        header('P3P: CP="CURa ADMa DEVa PSAo PSDo OUR BUS UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR"');  
        //$_SESSION[Yii::app()->user->stateKeyPrefix.'__id'] = $uid;  
        //$_SESSION[Yii::app()->user->stateKeyPrefix.'__name'] = $username;  
    }  
  
    public function actionSynlogout() {  
        if(!API_SYNLOGOUT) {  
            echo API_RETURN_FORBIDDEN;  
        }  
  
        //note 同步登出 API 接口  
        header('P3P: CP="CURa ADMa DEVa PSAo PSDo OUR BUS UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR"');  
        Yii::app()->user->logout();  
    }  
  
    public function actionUpdatepw() {  
        if(!API_UPDATEPW) {  
            echo API_RETURN_FORBIDDEN;  
        }  
        $username = $_GET['username'];  
        $password = $_GET['password'];  
          
        $user = user::model()->findByAttributes(array('username'=>$username));  
        if($user !== null)  
        {  
            $user->password = md5($password);  
            if($user->save())  
                echo API_RETURN_SUCCEED;  
            else  
                echo API_RETURN_FAILED;  
        }  
        else  
            echo API_RETURN_FAILED;  
    }  
  
    public function actionUpdatebadwords() {  
        if(!API_UPDATEBADWORDS) {  
            echo API_RETURN_FORBIDDEN;  
        }  
        $cachefile = $this->appdir.'./uc_client/data/cache/badwords.php';  
        $fp = fopen($cachefile, 'w');  
        $data = array();  
        if(is_array($_POST)) {  
            foreach($_POST as $k => $v) {  
                $data['findpattern'][$k] = $v['findpattern'];  
                $data['replace'][$k] = $v['replacement'];  
            }  
        }  
        $s = "<?php\r\n";  
        $s .= '$_CACHE&#91;\'badwords\'&#93; = '.var_export($data, TRUE).";\r\n";  
        fwrite($fp, $s);  
        fclose($fp);  
        echo API_RETURN_SUCCEED;  
    }  
  
    public function actionUpdatehosts() {  
        if(!API_UPDATEHOSTS) {  
            echo API_RETURN_FORBIDDEN;  
        }  
        $cachefile = $this->appdir.'./uc_client/data/cache/hosts.php';  
        $fp = fopen($cachefile, 'w');  
        $s = "<?php\r\n";  
        $s .= '$_CACHE&#91;\'hosts\'&#93; = '.var_export($_POST, TRUE).";\r\n";  
        fwrite($fp, $s);  
        fclose($fp);  
        echo API_RETURN_SUCCEED;  
    }  
  
    public function actionUpdateapps() {  
        if(!API_UPDATEAPPS) {  
            echo API_RETURN_FORBIDDEN;  
        }  
        $UC_API = $_POST&#91;'UC_API'&#93;;  
  
        //note 写 app 缓存文件  
        $cachefile = $this->appdir.'./uc_client/data/cache/apps.php';  
        $fp = fopen($cachefile, 'w');  
        $s = "<?php\r\n";  
        $s .= '$_CACHE&#91;\'apps\'&#93; = '.var_export($_POST, TRUE).";\r\n";  
        fwrite($fp, $s);  
        fclose($fp);  
  
        //note 写配置文件  
        $config_file = Yii::app()->basePath.'./config/main.php';  
        if(is_writeable($config_file)) {  
            $configfile = trim(file_get_contents($config_file));  
            $configfile = substr($configfile, -2) == '?>' ? substr($configfile, 0, -2) : $configfile;  
            $configfile = preg_replace("/define\('UC_API',\s*'.*?'\);/i", "define('UC_API', '$UC_API');", $configfile);  
            if($fp = @fopen($config_file, 'w')) {  
                @fwrite($fp, trim($configfile));  
                @fclose($fp);  
            }  
        }  
      
        echo API_RETURN_SUCCEED;  
    }  
  
    public function actionUpdateclient() {  
        if(!API_UPDATECLIENT) {  
            echo API_RETURN_FORBIDDEN;  
        }  
        $cachefile = $this->appdir.'./uc_client/data/cache/settings.php';  
        $fp = fopen($cachefile, 'w');  
        $s = "<?php\r\n";  
        $s .= '$_CACHE&#91;\'settings\'&#93; = '.var_export($_POST, TRUE).";\r\n";  
        fwrite($fp, $s);  
        fclose($fp);  
        echo API_RETURN_SUCCEED;  
    }  
  
    public function actionUpdatecredit() {  
        if(!API_UPDATECREDIT) {  
            echo API_RETURN_FORBIDDEN;  
        }  
        $credit = $_GET&#91;'credit'&#93;;  
        $amount = $_GET&#91;'amount'&#93;;  
        $uid = $_GET&#91;'uid'&#93;;  
        echo API_RETURN_SUCCEED;  
    }  
  
    public function actionGetcredit() {  
        if(!API_GETCREDIT) {  
            echo API_RETURN_FORBIDDEN;  
        }  
    }  
  
    public function actionGetcreditsettings() {  
        if(!API_GETCREDITSETTINGS) {  
            echo API_RETURN_FORBIDDEN;  
        }  
        $credits = array();  
        echo $this->_serialize($credits);  
    }  
  
    public function actionUpdatecreditsettings() {  
        if(!API_UPDATECREDITSETTINGS) {  
            echo API_RETURN_FORBIDDEN;  
        }  
        echo API_RETURN_SUCCEED;  
    }  
      
    private function _serialize($arr, $htmlon = 0) {  
        if(!function_exists('xml_serialize')) {  
            include_once 'xml.class.php';  
        }  
        echo xml_serialize($arr, $htmlon);  
    }  
}  

上面用到了xml.class.php这个类文件,可以在uc_client/lib目录找到。

这里需要说明的是,actionSynlogin方法中,利用了我定义的特殊的UserIdentity来登录的,因为不需要提供密码。
再来看看最后一个类:

<?php  
  
/** 
 * UserIdentity represents the data needed to identity a user. 
 * It contains the authentication method that checks if the provided 
 * data can identity the user. 
 */  
class UcUserIdentity extends CUserIdentity  
{     
    public $id;  
      
    /** 
     * Constructor. 
     * @param string $username username 
     */  
    public function __construct($username)  
    {  
        $this->username=$username;  
        $this->password='';  
    }  
    /** 
     * Authenticates a user. 
     * The example implementation makes sure if the username and password 
     * are both 'demo'. 
     * In practical applications, this should be changed to authenticate 
     * against some persistent user identity storage (e.g. database). 
     * @return boolean whether authentication succeeds. 
     */  
    public function authenticate()  
    {  
        $user = user::model()->findByAttributes(array('username'=>$this->username));  
          
        if($user == null)//说明网站数据库中没有,而ucenter中有这个用户,添加用户  
        {  
            //ucenter  
            Yii::import('application.vendors.*');  
            include_once 'ucenter.php';  
            list($uid, $username, $email) = uc_get_user($this->username);  
            if($uid)  
            {  
                $user = new user;  
                $user->username = $username;  
                $user->password = md5(rand(10000,99999));  
                $user->email = $email;  
                $user->id = $uid;  
                $user->save();  
                  
                $user->refresh();  
            }  
        }  
          
        $this->id = $user->id;  
          
        $user->last_login_time = $user->this_login_time;  
        $user->this_login_time = time();  
        $user->last_login_ip = $user->this_login_ip;  
        $user->this_login_ip = Yii::app()->getRequest()->userHostAddress;  
        $user->save();   
          
        $this->errorCode=self::ERROR_NONE;  
          
        return !$this->errorCode;  
    }  
      
    public function getId()  
    {  
        return $this->id;  
    }  
}

可以看到,在这个认证类中,实现了对yii应用中没有的用户的建立操作。然后不需要对yii应用做任何特殊设置,就可以实现api接口了。
然后我们在ucenter中添加yii应用的设置,修改main.php中的相应设置,应该就可以实现ucenter的同步登录、注册、退出、删除用户、修改用户名等等功能了!这个实现方法相对很Yii,呵呵。
有什么问题,欢迎评论,和我联系。大家一起进步吧!

PS: 需要注意的是,整合了ucenter的Yii应用在部署时,需将 protected/vendors/uc_client/data/及其子目录、文件设为可写。否则将会有些奇怪的问题。

原文地址 http://lonestone.iteye.com/blog/1129071

女人放弃一个跟不上她的男人,是有志气。男人放弃一个跟不上他的女人,则是无义。