最近应公司的要求,要开发一个有点像QQ空间那样的会员管理中心网站,发现UCenter的很多功能酷似QQ空间,于是选择了UCenter作为程序的会员管理中心。前台嘛就选择我之前基于ThinkPHP3.1.2框架开发的WBlog好了。但是问题又来了:要求在WBlog前台注册的会员登录时要与UCenter同步,这就是我这次要解决的问题--ThinkPHP与UCenter的整合。
我在网上搜索了一下,ThinkPHP与UCenter的整合并不少,但是似乎越看越觉得头晕,不是少这就是少那,到头来差之毫厘,谬以千里,真够折腾的。我仔细阅读了UCenter的开发文档后,经过多次的调试,终于完成了ThinkPHP与UCenter的整合。感觉这个结果是从苦水里泡出来的一样,呵呵。。。现在把整合的记录分享给需要的童鞋。
温馨提示:在thinphp与UCenter整合中,您需要的基本条件是,有一定的PHP基础,对ThinkPHP框架有所了解,会布署目录和配置数据。
好了,我们开始吧!
下载并安装下面的程序
WBlog3.1.2
UCenter_Home_2.0_SC_UTF8
UCenter 1.6.0
安装WBlog博客程序
已发布的WBlog博客程序还没有会员中心,本次测试的会员中心是后面才写的。如果你能等的话要待我整理好WBlog的会员中心程序才发布,不能等的话也不会影响下面的程序整合,因为你可以找或者自己写简单的满足以下两个条件的thikphp程序:
1、可以注册会员
2、可以登录和退出。
这里我就使用WBlog3.1.2了。在服务器的根目录新建目录wblog1,把下载的WBlog3.1.2解压得到的WBlog目录里的所有文件复制到wblog1。在浏览器输入http://127.0.0.1/wblog1/install/,安装WBlog3.1.2。
温馨提示:在整合时最容易搞错的就是路径问题,在接下来的整合操作的根目录都是指wblog1目录,所以要和服务器根目录区别开来。
安装UCenter 1.6.0(简体UTF-8)
这个程序到官方去下载吧。在网站根目录wblog1新建 ucenter 目录,解压UCenter 1.6.0,把解压得到的upload目录里的所有文件复制到刚才新建的ucenter目录里。在浏览器输入http://127.0.0.1/wblog1/ucenter/install/,安装UCenter 1.6.0。
安装UCenter_Home_2.0_SC_UTF8(简体中文版)
在网站根目录wblog1新建 uh目录并解压UCenter_Home_2.0_SC_UTF8,把解压得到的upload目录里的所有文件复制到刚才新建的uh目录里。在浏览器输入http://127.0.0.1/wblog1/uh/install/,安装UCenter_Home_2.0_SC_UTF8。
需要注意的是,安装UCenter 1.6.0和UCenter_Home_2.0_SC_UTF8时顺序不能颠倒,否则无法安装。
我们安装完了WBlog3.1.2、UCenter_Home_2.0_SC_UTF8和UCenter 1.6.0三个程序后。接下来找到下载的UCenter 1.6.0,把 advanced 目录里面的uc_client 和 examples下面的api 文件夹复制到网站根目录wblog1下,和ThinkPHP在同一目录。找到项目W3note的配置文件夹wblog1/ Conf/,在其新建一个UCenter的配置文件 config_ucenter.php ,然后在WBlog1\W3note\Lib\ORG目录下新建一个UCenter的通讯处理类文件UcService.class.php,我们先不要管文件里面写什么代码,后面将会讲到。好了到这里已经把后面要操作的目录和文件都布局好了。为了理清目录和文件之间的层次关系,我把目录和文件制成目录树列出来:
wblog1根目录
| – index.php//前台入口文件
| – admin.php
| – W3note//前台项目
| | – Lib
| | | – ORG
| | | | –UcService.class.php //UCenter的通讯处理类文件
| | – Conf//W3note项目的配置目录
| | | –config_ucenter.php //UCenter的配置文件
| |
| – Admin
| – ThinkPHP //thinkphp3.1.2核心包和一些扩展
| – install
| – api
| | – uc.php
|
| – uc_client
| – ucenter
| – uh
这样我们就可以一目了然了。
现在开始api目录里面的uc.php 配置了,首先打开这个文件,找到36行的位置这一行代码
1
|
require_once
DISCUZ_ROOT.
'./config.inc.php'
;
|
把'./config.inc.php'这一部分替换成'./W3note/Conf/config_ucenter.php'
往下找还会看到几处的'./config.inc.php',按照上面的操作全部替换掉。这样做目的是把前面建的配置文件config_ucenter.php导进来。 接下来我登录http://127.0.0.1/wblog1/ucenter,在打开左边菜单“应用管理”这一项,然后添加一个新应用,这时我们发现好多东西要填!
照着下面操作就是了。先看应用类型,因为这是我们自己开发的程序,所以就选其它吧,再看应用名称,随便填,只要不超过20字节就行了,我这里填wblog。接下来是应用的主URL,这里填网站的主页http;//127.0.0.1/wblog1,注意了,后面没有“/”。至于应用的其他URL还有应用IP这两项就跳过,不用管它了。接下来是通信密钥,就按其旁边的提示填就是了,我这里填abc123456。往下是应用的物路径,提示说默认为空,那就留空吧,还有查看个人资料页面地址也留空吧。接下来是应用接口文件名称,默认为uc.php,保持原状吧。继续往下看,标签单条显示模板还有标签模板标记说明这两项也不用理它,跳过。是否开启同步登录,选是;是否接受通知也选是吧。终于填完了,那就点击提交吧!
还记得前面在uc.php导入的文件config_ucenter.php吗,里面可是一片空白啊,现在我们就来放些配置信息进去。刚才我们填好的信息提交后,会在提交按钮下面的“应用的UCenter配置信息”下面生成了一些配置信息,我们直接把它复制,然后粘帖到config_ucenter.php,保存。
网上很多教程到这里就表示通信成功了,在这里我非常惊讶!因为通信并未成功!我在这里折腾了一些时间,后来仔细检了uc.php文件的代码,发现59行:
1
|
require_once
DISCUZ_ROOT.
'./include/db_mysql.class.php'
;
|
我在布局的目录中始终找不到db_mysql.class.php,后来发现db_mysql.class.php存UCenter_1.6.0_SC_UTF8\advanced\examples\include目录中,这就是问题所在!因为我们之前复制的只是UCenter_1.6.0_SC_UTF8\advanced\examples\中的api文件。
解决这一问题的办法就是把上面的代码修改为
1
|
require_once
DISCUZ_ROOT.
'./uc_client/lib/db.class.php'
;
|
导入的数据库类文件变了,那么我们也要对其所涉及的内容作相应的修改,在uc.php59行的下面如
1
2
3
4
5
6
7
|
$GLOBALS
[
'db'
] =
new
dbstuff;
$GLOBALS
[
'db'
]->connect(
$dbhost
,
$dbuser
,
$dbpw
,
$dbname
,
$pconnect
, true,
$dbcharset
);
$GLOBALS
[
'tablepre'
] =
$tablepre
;
修改为
$GLOBALS
[
'db'
] =
new
ucclient_db;
$GLOBALS
[
'db'
]->connect(UC_DBHOST, UC_DBUSER, UC_DBPW, UC_DBNAME, UC_DBCONNECT, true, UC_DBCHARSET);
$GLOBALS
[
'tablepre'
] = UC_DBTABLEPRE;
//关键
|
上面数据库的链接信息的静态变量来自config_ucenter.php。
好了,我们回到后台ucenter刷新一下页面,发现什么---通信成功了!
那么接下来我们的目标:
在thinkphp中会员注册成功时,UCenter Home也同时注册成功。
首先在项目W3note入口文件index.php配置一个常量
define('WBLOG_ROOT_PATH', rtrim(dirname(__FILE__), '/\\') . DIRECTORY_SEPARATOR);//物理根目录
常量WBLOG_ROOT_PATH是网站根目录wblog1的物理根目录,在我本地服务器打印输出:
D:\phpsever\apache2\htdocs\wblog1\
有必要在这里强调一下,理解WBLOG_ROOT_PATH很重要,因为在调试过程中路径最容易出错。
还记得前面我们建的UcService.class.php 文件吗?如果忘记了请看一下前面的目录树。打开UcService.class.php文件,新建一个类UcService,然后写一个构造方法导入W3note/Conf/config_ucenter.php和uc_client/client.php两个文件。代码:
1
2
3
4
5
|
class
UcService{
public
function
__construct(){
include_once
(WBLOG_ROOT_PATH .
'W3note/Conf/config_ucenter.php'
);
include_once
(WBLOG_ROOT_PATH .
'uc_client/client.php'
);
}
|
接下来我们写一个会员注册方法register,如
public function register($username, $password, $email){}
方法体放什么代码呢?其实很简单,因为UCenter的开发文档已经为我们准备好了!
找到之前下载的UCenter_1.6.0_SC_UTF8,用浏览器打开UCenter_1.6.0_SC_UTF\advanced\document\index.htm,然后在左边的菜单栏找到“用户接口”,看到用户注册示例 (PHP),把其下的代码复制过来。如下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
/**
* 会员注册
*/
public
function
register(
$username
,
$password
,
$email
){
$uid
= uc_user_register(
$username
,
$password
,
$email
);
//UCenter的注册验证函数
if
(
$uid
<= 0) {
if
(
$uid
== -1) {
return
'用户名不合法'
;
}
elseif
(
$uid
== -2) {
return
'包含不允许注册的词语'
;
}
elseif
(
$uid
== -3) {
return
'用户名已经存在'
;
}
elseif
(
$uid
== -4) {
return
'Email 格式有误'
;
}
elseif
(
$uid
== -5) {
return
'Email 不允许注册'
;
}
elseif
(
$uid
== -6) {
return
'该 Email 已经被注册'
;
}
else
{
return
'未定义'
;
}
}
else
{
return
intval
(
$uid
);
//返回一个非负数
}
}
}
|
这个注册方法register的作用是,在wblog1的会员注册中成功注册一个会员时,也会成功注册UCenter Home的会员中心中。UCenter的注册方法我们在上面已经写好了,现在回到thinkphp。我们在前台W3note项目的控制器MemberAction写一个注册方法,代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
/*
用户名:$username,
密码:$password,
邮箱:$email
*/
public
function
addmember(){
if
(
$this
->isPost()){
$username
=
$_POST
[
'username'
];
$email
=
$_POST
[
'email'
];
$password
= trim(
$_POST
[
'password'
]);
import(
"@.ORG.UcService"
);
//导入UcService.class.php类
$ucService
=
new
UcService;
//实例化UcService类
$uid
=
$ucService
->register(
$username
,
$password
,
$email
);
//注册到UCenter
if
(
$uid
){
//如果上面注册成功将返回一个int类型的数字
$M
= D(
'Member'
);
if
(
$vo
=
$M
->create()) {
if
(
$M
->add()) {
$this
->success(
'注册成功!'
);
}
else
{
$this
->error(
'注册失败!'
);
}
}
else
{
$this
->error();
}
}
else
{
exit
(
$uid
);
}
}
else
{
$this
->error(
'非法数据!'
);
}
}
|
1
2
3
|
我们在thinkphp会员注册页面注册一个帐号,提交表单后,查看wblog1和UCenter的会员数据表,发现两张表都存相同的帐号,说明同步注册已经成功了!
有了帐号我们就可以来做同步登录了。
打开UcService.
class
.php文件,添加一个UC登录和一个登出的方法,代码到UCenter接口开发手册的用户接口那里找用户登录示例代码,把它复制过来,然后稍微更改一下,使其带有返回值,以便下一步的操作,代码如下:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
public
function
uc_login(
$username
,
$password
){
list(
$uid
,
$username
,
$password
,
$email
) = uc_user_login(
$username
,
$password
);
if
(
$uid
> 0) {
return
array
(
'uid'
=>
$uid
,
'username'
=>
$username
,
'password'
=>
$password
,
'email'
=>
$email
);
}
elseif
(
$uid
== -1) {
return
'用户不存在,或者被删除'
;
}
elseif
(
$uid
== -2) {
return
'密码错误'
;
}
elseif
(
$uid
== -3) {
return
'安全提问错误'
;
}
else
{
return
'未定义'
;
}
}
|
继续在用户接口那里找到同步登录的代码示例,找到“uc_user_synlogin($uid);”其作用是执行同步登录,然后写成uc_synlogin方法如下:
1
2
3
|
public
function
uc_synlogin(
$uid
){
return
uc_user_synlogin(
$uid
);
}
|
到这里UcService.class.php文件的登录方法已经写好,接下来打开前台W3note项目的控制器MemberAction.class.php文件写一个同步登录的方法,看代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
|
public
function
checkLogin() {
if
(!
$_POST
[
'username'
])
$this
->error(
'帐号错误!'
);
if
(!
$_POST
[
'password'
])
$this
->error(
'密码错误!'
);
if
(
empty
(
$_POST
[
'verify'
]))
$this
->error(
'验证码必须!'
);
import(
"@.ORG.UcService"
);
//导入UcService.class.php类
$ucService
=
new
UcService;
$uidarray
=
$ucService
->uc_login(
$_POST
[
'username'
],
$_POST
[
'password'
]);
//dump($uidarray);
$loginurl
=
$ucService
->uc_synlogin(
$uidarray
);
echo
$loginurl
;
//输出同步登录代码,否则无法同步登录
if
(!
is_string
(
$uidarray
)){
//生成认证条件
$map
=
array
();
// 支持使用绑定帐号登录
$map
[
'username'
] =
$_POST
[
'username'
];
$map
[
"status"
] =
array
(
'gt'
,0);
if
(
$_SESSION
[
'verify'
] != md5(
$_POST
[
'verify'
])) {
$this
->error(
'验证码错误!'
);
}
$memberinfo
=
$this
->Member->where(
$map
)->find();
if
(false ===
$memberinfo
) {
$this
->error(
'帐号不存在或已禁用!'
);
}
elseif
(
$memberinfo
[
'status'
]==0){
$this
->error(
'帐号已禁用!'
);
}
else
{
$password
= pwdHash(
$_POST
[
'password'
]);
if
(
$memberinfo
[
'password'
] !=
$password
) {
$this
->error(
'密码错误!'
);
}
session(C(
'USER_AUTH_KEY'
),
$memberinfo
[
'id'
]);
session(
'email'
,
$memberinfo
[
'email'
] );
session(
'loginUserName'
,
$memberinfo
[
'loginUserName'
]);
session(
'lastLoginTime'
,
$memberinfo
[
'lastLoginTime'
]);
session(
'loginnum'
,
$memberinfo
[
'loginnum'
]);
session(
'lastloginip'
,
$memberinfo
[
'lastloginip'
]);
//保存登录信息(相当于更新信息)
$data
=
array
();
$data
[
'id'
] =
$memberinfo
[
'id'
];
$data
[
'lastlogintime'
] = time();
$data
[
'loginnum'
] =
array
(
'exp'
,
'loginnum+1'
);
$data
[
'lastloginip'
] = get_client_ip();
//$data['verify'] = $authInfo['verify'];
$this
->Member->save(
$data
);
$this
->success(
'登录成功!'
,U(
'Member/index'
));
}
}
}
|
我们来看一下checkLogin()方法的执行过程。
在项目W3note注册的一个帐号,然后在项目W3note提交登录表单后,首先执行UCenter的登录,前面我们写了两个UCenter的登录方法,在调用之前需要使用“import("@.ORG.UcService");”把UcService.class.php文件加载进来,实例化后得到$ucService,然后就可以使用用$ucService访问UCenterr的登录方法uc_login,返回一个$uidarray值,$uidarray包函什么数据?使用“dump($uidarray);”打印出来,以便下一步的操作,打印结果如下:
1
2
3
4
5
6
|
array
(4) {
[
"uid"
] => string(1)
"1"
[
"username"
] => string(5)
"qqabc"
[
"password"
] => string(6)
"123456"
[
"email"
] => string(9)
"qq@qq.com"
}
|
下一步就是以此$uidarray作为参数传给同步登录方法uc_synlogin($uidarray),最后echo 一下uc_synlogin($uidarray)的返回值$loginurl,就可以实现帐号"qqabc"在UCenter登录了。帐号"qqabc"在UCenter登录成功后程序将继续往下执行项目W3note的登录,这里就不多说了。最后的结果是,帐号"qqabc"实现了在UCenter和项目W3note的同步登录!