多站点与discuz同步登陆,整合uc/ucenter/discuz

市场就是力量,discuz是国内人气最高,使用最广泛的论坛系统,发展到今天它已经整合了论坛、门户、博客、CMS等版块,内容丰富,深受用户的喜爱,一直以来很多用户用它来整合自己的应用。由于discuz版块众多,系统相对封装,源代码缺少注释,api资料不够丰富,官方对discuz用户的咨询也并非卖力,而网上资料不是版本陈旧就是鱼龙混杂。对于想整合discuz论坛的朋友存在一定的难度。因此,如果你想美好整合discuz的话,不妨耐心看完以下提示。

一、准备工作

1、uc api说明书,通读全文。参考http://faq.comsenz.com/library/UCenter/introduction/introduction_list.htm(官方),了解同步登陆机制

2、uc 后台添加应用说明。参考http://faq.comsenz.com/viewnews-506(官方) http://wenku.baidu.com/view/3790fdd7195f312b3169a588.html(草根)

3、uc client客户端必要代码,这里下载

4、如果是x3后面的版本,请先更改bug,参见http://www.discuz.net/thread-3505581-1-1.html

解决方案如下:
\source\class\discuz的discuz_application.php 查找

 

<?php
        private function _xss_check() {
		static $check = array(\'"\', \'>\', \'<\', \'\\'\', \'(\', \')\', \'CONTENT-TRANSFER-ENCODING\');
			
		if(isset($_GET[\'formhash\']) && $_GET[\'formhash\'] !== formhash()) {
			system_error(\'request_tainting\');
		}

		if($_SERVER[\'REQUEST_METHOD\'] == \'GET\' ) {
			$temp = $_SERVER[\'REQUEST_URI\'];
		} elseif(empty ($_GET[\'formhash\'])) {
			$temp = $_SERVER[\'REQUEST_URI\'].file_get_contents(\'php://input\');
		} else {
			$temp = \'\';
		}

		if(!empty($temp)) {
			$temp = strtoupper(urldecode(urldecode($temp)));
			foreach ($check as $str) {
				if(strpos($temp, $str) !== false) {
					system_error(\'request_tainting\');
				}
			}
		}

		return true;

	}

 

二、示例

我们学习一门技术时,看看它的技术说明就足够了,但discuz远非如此。discuz不是zend frame、dedecms、ci这些白开水的东西,没有一点钻研精神和爱折腾的气质是无法理解它深奥的内涵,更不用说驾驭它。要达到成功,我们需要有详尽的说明文字,另外还需要配备必要的图片,虽然有了这些你也未必能够成功。

先看一下我的项目结构

1

tanahk 是真正的项目地址,x3.2是我的discuz论坛,打开它

2

可以看到这个discuz x3.2已经整合了Ucenter,其中uc_server是uc服务器,uc_client是客户端,uc_client这个文件夹在discuz x、discuz home、discuz xspace等产品中都是已经捆绑好的。需要记住的一点,在整个共用站点系统中,我们只需要一个uc_client,因为uc_server只会在它定义的uc_client路径中寻找data文件中的apps数组。

因此在多站点同步登陆登出的关键文件只有两个,一个是config.ini.php,另一个是uc.php。前者告诉uc_server我们这个应用的配置,后者供uc_server调用。

把examples/api/uc.php文件复制到我们的tanahk/api/uc.php,examples/config.inc.php和examples/include也添加进来。目录结构变为

6

code文件夹我用来查看一些源码。

好了,现在可以在UCenter后台添加我们的项目应用了。uc的后台一般为http://www.xxx.com/x3.2/uc_server/admin.php

7

选择“应用管理”–“添加新应用”

参考上面准备工作中2。

应用类型:其它

应用名称:Tanahk,这里只能填写英文

通信密钥:随意一串不多于64位的字母数字。

应用的物理路径:可以为空,只要应用主url填写正确

应用接口文件名称:保留,uc.php,不用填api/uc.php

是否开启同步登陆:是,这是关键,以后多个项目共用一个uc就行了,不用自己新建一套用户系统。

提交。

提交后一般是通信错误的。

我们先修改tanahk/api/config.inc.php 。这里的数据非常重要,如果安装了discuz x或其它discuz产品,最好对照discuz root/config下面的配置文件修改。

<?php

define(\'UC_CONNECT\', null);                // 连接 UCenter 的方式: mysql/NULL, 默认为空时为 fscoketopen()
                            // mysql 是直接连接的数据库, 经实践,还是填写null好。mysql有时无法执行

//数据库相关 (mysql 连接时, 并且没有设置 UC_DBLINK 时, 需要配置以下变量)
define(\'UC_DBHOST\', \'localhost\');            // UCenter 数据库主机
define(\'UC_DBUSER\', \'root\');                // UCenter 数据库用户名
define(\'UC_DBPW\', \'111111\');                    // UCenter 数据库密码
define(\'UC_DBNAME\', \'ultrax\');                // UCenter 数据库名称
define(\'UC_DBCHARSET\', \'utf8\');                // UCenter 数据库字符集
define(\'UC_DBTABLEPRE\', \'`ultrax`.pre_ucenter_\');            // UCenter 数据库表前缀
define(\'UC_DBCONNECT\', 0);                    // 是否持久化链接

//通信相关
define(\'UC_KEY\', \'…\');                // 与 UCenter 的通信密钥, 要与注册应用时填写的保持一致
define(\'UC_API\', \'http://www.xxx.com/x3.2/uc_server\');    // UCenter 的 URL 地址, 在调用头像时依赖此常量
define(\'UC_CHARSET\', \'utf-8\');                // UCenter 的字符集
define(\'UC_IP\', \'\');                    // UCenter 的 IP, 当 UC_CONNECT 为非 mysql 方式时, 并且当前应用服务器解析域名有问题时, 请设置此值
define(\'UC_APPID\', 2);                    // 当前应用的 ID

define(\'UC_PPP\', 20);

//ucexample_2.php 用到的应用程序数据库连接参数
$dbhost = \'localhost\';            // 数据库服务器
$dbuser = \'root\';            // 数据库用户名
$dbpw = \'111111\';                // 数据库密码
$dbname = \'ultrax\';            // 数据库名
$pconnect = 0;                // 数据库持久连接 0=关闭, 1=打开
$tablepre = \'`ultrax`.pre_ucenter_\';           // 表名前缀, 同一数据库安装多个论坛请修改此处
$dbcharset = \'utf8\';        // MySQL 字符集, 可选 \'gbk\', \'big5\', \'utf8\', \'latin1\', 留空为按照论坛字符集设定

//同步登录 Cookie 设置
$cookiepre = \'jt_\';           // cookie 前缀
$cookiedomain = \'\';         // cookie 作用域
$cookiepath = \'/\';        // cookie 作用路径

认真对照,特别是UC_KEY与UC_APPID,id一般为2以后的数字,查看uc后台,1被discuz x霸占了。 上面的配置不能遗漏。 UC_DBHOST,如果填写mysql,最好带port,可以包括端口号,例如 “hostname:port”,或者到本地套接字的路径,例如对于 localhost 的 “:/path/to/socket”。UC_PPP:默认值为 20,与 UCenter 日志显示的条数和通知管理显示的条数有关系。

在上述配置最后加上一句 :

$cookiename = \'tanahk\';        // 用户自定义的cookie名

它用来贮存用户登陆成功后的cookie值。

我们现在需要花大力气修改uc.php。首先是修改开头的常量定义

error_reporting(0);

define(\'IN_DISCUZ\', TRUE);

define(\'UC_CLIENT_VERSION\', \'1.5.0\');    //note UCenter 版本标识
define(\'UC_CLIENT_RELEASE\', \'20081031\');

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\');

// 改你真实的discuz地址
define(\'DISCUZ_ROOT\', realpath(dirname(__FILE__) . \'/../../x3.2/\'));
// 本应用配置路径
define(\'DISCUZ_UC_CONFIG\', realpath(dirname(__FILE__)));

然后是修改下面的note通知方式

//note 普通的 http 通知方式
if(!defined(\'IN_UC\')) {
    
    if (!defined(\'PHP_VERSION_ID\'))
    {
        $version = explode(\'.\', PHP_VERSION);
        define(\'PHP_VERSION_ID\', ($version[0] * 10000 + $version[1] * 100 + $version[2]));
    }
    
    // set_magic_quotes_runtime 5.3.0版本不赞成使用,5.4.0废弃
    if (PHP_VERSION_ID < 530)
        set_magic_quotes_runtime(0);
    
    // 修改常量MAGIC_QUOTES_GPC,与php5.4接地气,让它一直为false
    define(\'MAGIC_QUOTES_GPC\', false);
    require_once DISCUZ_UC_CONFIG . \'/config.inc.php\';
    
    $GLOBALS[\'cookiename\'] = $cookiename;
    $_DCACHE = $get = $post = array();

    $code = isset($_GET[\'code\']) ? $_GET[\'code\'] : \'\';
    parse_str(_authcode($code, \'DECODE\', UC_KEY), $get);
    
    $timestamp = time();
    if($timestamp - $get[\'time\'] > 3600) 
        exit(\'Authracation has expiried\');
        
    if(empty($get)) 
        exit(\'Invalid Request\');
        
    $action = $get[\'action\'];

    require_once  DISCUZ_ROOT . \'/uc_client/lib/xml.class.php\';
    $post = xml_unserialize(file_get_contents(\'php://input\'));
    
    if(in_array($get[\'action\'], array(\'test\', \'deleteuser\', \'renameuser\', \'gettag\', \'synlogin\', \'synlogout\', \'updatepw\', \'updatebadwords\', \'updatehosts\', \'updateapps\', \'updateclient\', \'updatecredit\', \'getcreditsettings\', \'updatecreditsettings\'))) {
        require_once DISCUZ_UC_CONFIG . \'/include/db_mysql.class.php\';
        $GLOBALS[\'db\'] = new dbstuff;
        $GLOBALS[\'db\']->connect($dbhost, $dbuser, $dbpw, $dbname, $pconnect, true, $dbcharset);
        $GLOBALS[\'tablepre\'] = $tablepre;
        unset($dbhost, $dbuser, $dbpw, $dbname, $pconnect);
        $uc_note = new uc_note();
        exit($uc_note->$get[\'action\']($get, $post));
    } else {
        exit(API_RETURN_FAILED);
    }

//note include 通知方式
} else {
    
    require_once DISCUZ_UC_CONFIG . \'/config.inc.php\';
    require_once DISCUZ_UC_CONFIG . \'/include/db_mysql.class.php\';
    $GLOBALS[\'cookiename\'] = $cookiename;
    $GLOBALS[\'db\'] = new dbstuff;    
    $GLOBALS[\'db\']->connect($dbhost, $dbuser, $dbpw, $dbname, $pconnect, true, $dbcharset);
    $GLOBALS[\'tablepre\'] = $tablepre;
    unset($dbhost, $dbuser, $dbpw, $dbname, $pconnect);
}

上面把我们的$cookiename参数引进来,留给同步登陆函数使用。

$GLOBALS[\'cookiename\'] = $cookiename;

修改function uc_note,它其实就是uc_note类的的构造函数。当ucenter有相关举动时通知我们的应用。

function uc_note() {
        $this->appdir = DISCUZ_ROOT;        
        $this->dbconfig = DISCUZ_UC_CONFIG.\'/config.inc.php\';
        $this->db = $GLOBALS[\'db\'];
        $this->tablepre = $GLOBALS[\'tablepre\'];
    }

把uc_client客户端指向discuz X3.2的路径,而配置文件指向我们api/目录。

然后修改synlogin/synlogout同步论坛的登入登出函数,把我们的$cookiename引进来

function synlogin($get, $post) {
        $uid = $get[\'uid\'];
        $username = $get[\'username\'];
        if(!API_SYNLOGIN) {
            return API_RETURN_FORBIDDEN;
        }

        header(\'P3P: CP="CURa ADMa DEVa PSAo PSDo OUR BUS UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR"\');
        _setcookie($GLOBALS[\'cookiename\'], _authcode($uid."\t".$username, \'ENCODE\'));
    }

    function synlogout($get, $post) {
        if(!API_SYNLOGOUT) {
            return 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"\');
        _setcookie($GLOBALS[\'cookiename\'], \'\', -86400 * 365);
    }

如上。当用户在论坛中登陆时,它会通知更新我们设定的名为$cookiename的cookie值,而当用户在其它地方退出时,会清除我们的cookie。

因为_setcookie函数要引用全局变量,discuz在uc.php默认把它屏蔽了,因此我们要加进来。

//note 使用该函数前需要 require_once $this->appdir.\'/config.inc.php\';
function _setcookie($var, $value, $life = 0, $prefix = 1) {
    require_once DISCUZ_UC_CONFIG . \'/config.inc.php\';
    global $cookiepre, $cookiedomain, $cookiepath, $timestamp, $_SERVER;
    setcookie(($prefix ? $cookiepre : \'\').$var, $value,
        $life ? $timestamp + $life : 0, $cookiepath,
        $cookiedomain, $_SERVER[\'SERVER_PORT\'] == 443 ? 1 : 0);
}

discuz在uc.php后面定义了三个函数,一个_setcookie,它贮存cookie,_authcode加密解密用户cookie或其它文本值,_stripslashes转义字符串。

_authcode是一个使用频率很高,用途广泛的明文加解密函数,在discuz产品或其它php产品中非常常见,我们有必要了解一下。下面是以其原版authcode为例

<?php
// 参数解释
// $string: 明文 或 密文
// $operation:DECODE表示解密,其它表示加密
// $key: 密匙
// $expiry:密文有效期
function authcode($string, $operation = \'DECODE\', $key = \'\', $expiry = 0) {
    // 动态密匙长度,相同的明文会生成不同密文就是依靠动态密匙
    // 加入随机密钥,可以令密文无任何规律,即便是原文和密钥完全相同,加密结果也会每次不同,增大破解难度。
    // 取值越大,密文变动规律越大,密文变化 = 16 的 $ckey_length 次方
    // 当此值为 0 时,则不产生随机密钥
    $ckey_length = 4;
 
    // 密匙
    $key = md5($key ? $key : $GLOBALS[\'discuz_auth_key\']);
 
    // 密匙a会参与加解密
    $keya = md5(substr($key, 0, 16));
    // 密匙b会用来做数据完整性验证
    $keyb = md5(substr($key, 16, 16));
    // 密匙c用于变化生成的密文
    $keyc = $ckey_length ? ($operation == \'DECODE\' ? substr($string, 0, $ckey_length): substr(md5(microtime()), -$ckey_length)) : \'\';
    // 参与运算的密匙
    $cryptkey = $keya.md5($keya.$keyc);
    $key_length = strlen($cryptkey);
    // 明文,前10位用来保存时间戳,解密时验证数据有效性,10到26位用来保存$keyb(密匙b),解密时会通过这个密匙验证数据完整性
    // 如果是解码的话,会从第$ckey_length位开始,因为密文前$ckey_length位保存 动态密匙,以保证解密正确
    $string = $operation == \'DECODE\' ? base64_decode(substr($string, $ckey_length)) : sprintf(\'0d\', $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\') {
        // substr($result, 0, 10) == 0 验证数据有效性
        // substr($result, 0, 10) - time() > 0 验证数据有效性
        // substr($result, 10, 16) == substr(md5(substr($result, 26).$keyb), 0, 16) 验证数据完整性
        // 验证数据有效性,请看未加密明文的格式
        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 {
        // 把动态密匙保存在密文里,这也是为什么同样的明文,生产不同密文后能解密的原因
        // 因为加密后的密文可能是一些特殊字符,复制过程可能会丢失,所以用base64编码
        return $keyc.str_replace(\'=\', \'\', base64_encode($result));
    }
}

// 加密
echo authcode("www.nowamagic.net", \'ENCODE\');
// 解密
echo authcode(authcode("www.nowamagic.net", \'ENCODE\'));
//echo authcode("55e5OxJ5zjgFuqTjFRPdt9ag+fC+GKP9Efq6yWeAAvdQFq+D");
?>

如果配置全部正确,再回到uc后台,点击“应用管理”,应该能显示通信成功了。

8

到这步预防万一,我们再次点击应用2的编辑,进入,复制最下面的“应用的 UCenter 配置信息”,再次对照config.ini.php。这样写法更规范。

9

至此,所有配置都结束。

现在再来分析一下。discuz root/uc_client/client.php是我们第三方网站操纵discuz ucenter的入口,里面定义了很多全局api函数,通过这些函数我们可以实现用户的登陆、退出、获取用户信息等等功能。具体查看官方接口函数这一章节。而tanahk/api/uc.php文件则相反,它是ucenter与我们的网站交互的接口,ucenter的相关动作可以通知到我们的应用。比如用户在论坛的登陆、退出、修改用户密码、修改昵称等。那么它是怎样通知uc.php呢,打开discuz root/uc_server/control/user.php,查看30-52行。

// -1 未开启
    function onsynlogin() {
        $this->init_input();
        $uid = $this->input(\'uid\');

        if($this->app[\'synlogin\']) {
            if($this->user = $_ENV[\'user\']->get_user_by_uid($uid)) {
                $synstr = \'\';
                foreach($this->cache[\'apps\'] as $appid => $app) {
                    if($app[\'synlogin\']) {
                        $synstr .= \'<script type="text/javascript" src="\'.$app[\'url\'].\'/api/\'.$app[\'apifilename\'].\'?time=\'.$this->time.\'&code=\'.urlencode($this->authcode(\'action=synlogin&username=\'.$this->user[\'username\'].\'&uid=\'.$this->user[\'uid\'].\'&password=\'.$this->user[\'password\']."&time=".$this->time, \'ENCODE\', $app[\'authkey\'])).\'" reload="1"></script>\';
                        if(is_array($app[\'extra\'][\'extraurl\'])) foreach($app[\'extra\'][\'extraurl\'] as $extraurl) {
                            $synstr .= \'<script type="text/javascript" src="\'.$extraurl.\'/api/\'.$app[\'apifilename\'].\'?time=\'.$this->time.\'&code=\'.urlencode($this->authcode(\'action=synlogin&username=\'.$this->user[\'username\'].\'&uid=\'.$this->user[\'uid\'].\'&password=\'.$this->user[\'password\']."&time=".$this->time, \'ENCODE\', $app[\'authkey\'])).\'" reload="1"></script>\';
                        }
                    }
                }
                return $synstr;
            }
        }
        return \'\';
    }

这个是同步登陆函数,注意

if($this->app[\'synlogin\'])

是判断我们后台添加的discuz x、discuz home….甚至是我们的第三方应用是否开启了同步登陆。如果在uc后台编辑了“是”那么会在discuz root/uc_server/data/cache/apps.php,及在discuz root/uc_client/data/cache/apps.php下面分别贮存数据。

<?php
$_CACHE[\'apps\'] = array (
  1 => 
  array (
    \'appid\' => \'1\',
    \'type\' => \'DISCUZX\',
    \'name\' => \'Discuz! Board\',
    \'url\' => \'http://www.xxx.com/x3.2\',
    \'ip\' => \'\',
    \'viewprourl\' => \'\',
    \'apifilename\' => \'uc.php\',
    \'charset\' => \'\',
    \'dbcharset\' => \'\',
    \'synlogin\' => \'1\',
    \'recvnote\' => \'1\',
    \'extra\' => false,
    \'tagtemplates\' => \'\',
    \'allowips\' => \'\'
  ),
  2 => 
  array (
    \'appid\' => \'2\',
    \'type\' => \'OTHER\',
    \'name\' => \'TANAHK\',
    \'url\' => \'http://www.xxx.com/tanahk\',
    \'ip\' => \'\',
    \'viewprourl\' => \'/space.php?uid=%s\',
    \'apifilename\' => \'uc.php\',
    \'charset\' => \'\',
    \'synlogin\' => \'1\',
    \'extra\' => 
        array (
          \'apppath\' => \'/…/tanahk/\',
          \'extraurl\' => \'\'
        ),
    \'recvnote\' => \'1\'
  ),
  \'UC_API\' => \'http://www.xxx.com/x3.2/uc_server\'
);

?>

如果在对应数组设置了’synlogin’=>1,那么它就是同步,它是在后台点击“应用管理”的时候自动添加进来的。但如果我们前面的设置有错,没有看到上面的$_CACHE[\’apps\’][2],那么,我们只能照上面的1,复制一份下来。不然在onsynlogin() 函数

foreach($this->cache[\'apps\'] as $appid => $app) {
    ...
}

循环时没有找到我们的应用,它就不会发送js通知。

对于使用mvc的应用来说,我们可能还需要把client.php的功能集成到我们的model层,规范我们的行为。以我自己的TinyMVC为例,model层完全是我们自己实现的。

/**
 * 本model是对discuz uc_client/client.php全局函数的再包装
*/

class Discuz_Uc_Model extends TinyMVC_Model {

    private static $cookie_name = null;

    protected static $_global_functions = array();

    public function __construct()
    {
        // 下面两个常量在单入口定义
        include TMVC_MY_UC_API_DIR . \'config.inc.php\';
        include TMVC_DISCUZDIR . \'uc_client\' . DS . \'client.php\';
        
        // if uc cookie name is empty
        if (empty(self::$cookie_name))
            self::$cookie_name = !empty($cookiepre) ?  $cookiepre . $cookiename : $cookiename;
        
        // 收集自定义函数
        $functions = get_defined_functions();
        unset($functions[\'internal\']);
        self::$_global_functions = & $functions[\'user\'];
    }
    
    /**
     * 将discuz uc client 的api函数转为本类方法
     *
     * @access public
     * @param $fun string discuz UCenter API function name
     * @param $args array the params that transmited to $fun
    */
    public function __call($fun, $args)
    {
        if ( in_array($fun, self::$_global_functions) )
        {
            return call_user_func_array($fun, $args);
        }
        else
        {
            throw new Exception("The discuz uc api function \'{$fun}\' had not found.");
        }
    }
    
    /**
     * 获取我们在uc api中设置的cookiename,解密,返回带用户id和用户名的数组
     *
     * @access public
     * @return array  if $cookie_name is empty return null
     *        array(0=>uid, 1=>username)
    */
    public function fetch_discuz_uc_by_cookie()
    {
        return !empty($_COOKIE[self::$cookie_name]) ? explode("\t", $this->uc_authcode($_COOKIE[self::$cookie_name], \'DECODE\')) : array();
    }    
  
}

这样,当在controller使用$this->model->uc_user_login()时,实际上是调用uc api的uc_user_login函数,比如上面代码最后的$this->authcode()方法就是调用uc_client/client.php里面的同名函数,使用方法参考官方api。至此,我们就可以随心所欲地在control里面读取ucenter里面的数据。

–完–

版权声明:本文为sumsung753原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/sumsung753/p/3856239.html