Yiiフレームワークアプリケーション統合Ucenterによる同期登録、ログイン、終了等の実現
今では多くのサイトがフォーラムプログラムを統合しなければならないが、康盛のDiscuzシリーズ製品は往々にして第一選択である.その後、ユーザーを統合する必要があり、康盛はUcenterアーキテクチャを提供し、異なるアプリケーションを単一のログイン統合するのに便利です.
入ってきてucenterをYiiサイトに統合してみましたが、ログイン同期プログラムは適切ではありませんが、基本的には問題ありません.改善を続けます.次の手順に従います.
<?php
include dirname(__FILE__).'/../config/main.php';
include dirname(__FILE__).'/uc_client/client.php';
は、ここに2つのファイルが含まれているだけであることがわかります.次にyiiのプライマリプロファイルprotected/config/mainを開く.php、ucenterのいくつかのグローバル変数の設定を追加します:<?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.'..',
.....
あなたの状況に応じて上のデータベース名などの設定を変更してください.<?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アプリケーションに登録する.<?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のユーザーログインに対して何の修正も必要ありません./**
* 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>
/**
* 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>
<?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クラスを使用しています.私たちはこのクラスを見続けます.<?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(empty($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[$i] = ord($cryptkey[$i % $key_length]);
}
for($j = $i = 0; $i < 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 < $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() > 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通知の復号化、対応するコントローラの呼び出し、および動作実装動作を実現していることがわかります.<?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
";
$s .= '$_CACHE[\'badwords\'] = '.var_export($data, TRUE).";\r
";
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
";
$s .= '$_CACHE[\'hosts\'] = '.var_export($_POST, TRUE).";\r
";
fwrite($fp, $s);
fclose($fp);
echo API_RETURN_SUCCEED;
}
public function actionUpdateapps() {
if(!API_UPDATEAPPS) {
echo API_RETURN_FORBIDDEN;
}
$UC_API = $_POST['UC_API'];
//note app
$cachefile = $this->appdir.'./uc_client/data/cache/apps.php';
$fp = fopen($cachefile, 'w');
$s = "<?php\r
";
$s .= '$_CACHE[\'apps\'] = '.var_export($_POST, TRUE).";\r
";
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
";
$s .= '$_CACHE[\'settings\'] = '.var_export($_POST, TRUE).";\r
";
fwrite($fp, $s);
fclose($fp);
echo API_RETURN_SUCCEED;
}
public function actionUpdatecredit() {
if(!API_UPDATECREDIT) {
echo API_RETURN_FORBIDDEN;
}
$credit = $_GET['credit'];
$amount = $_GET['amount'];
$uid = $_GET['uid'];
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インタフェースを実現することができます.何か問題があったら、コメントを歓迎して、私に連絡してください.みんなで進歩しましょう.
PS:ucenterを統合したYiiアプリケーションは導入時にprotected/vendors/uc_Client/data/およびそのサブディレクトリ、ファイルは書き込み可能に設定されます.さもないと変な問題があります.