Discuz 与 UCenter 通信失败的解决方案

快速解决

编辑应用里的 应用 IP应用的主 URL 里的域名,不要带开头的 https:// 和结尾的 /

问题分析

本文在 前人 的基础上继续分析。

审查元素通信失败四个字,右键链接 Open in new tab 新窗口打开:

找到 ucenter 目录下 ./control/admin/app.phponping 方法,源码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
function onping() {
$ip = getgpc('ip');
$url = getgpc('url');
$appid = intval(getgpc('appid'));
$app = $_ENV['app']->get_app_by_appid($appid);
$status = '';
if($app['extra']['apppath'] && @include $app['extra']['apppath'].'./api/'.$app['apifilename']) {
$uc_note = new uc_note();
$status = $uc_note->test($note['getdata'], $note['postdata']);
} else {
$this->load('note');
$url = $_ENV['note']->get_url_code('test', '', $appid);
$status = $_ENV['app']->test_api($url, $ip);
}
if($status == '1') {
echo 'document.getElementById(\'status_'.$appid.'\').innerHTML = "<img src=\'images/correct.gif\' border=\'0\' class=\'statimg\' \/><span class=\'green\'>'.$this->lang['app_connent_ok'].'</span>";testlink();';
} else {
echo 'document.getElementById(\'status_'.$appid.'\').innerHTML = "<img src=\'images/error.gif\' border=\'0\' class=\'statimg\' \/><span class=\'red\'>'.$this->lang['app_connent_false'].'</span>";testlink();';
}
}

if($status == '1') { 前面打印下 $url$status

1
echo "\$url = $url <br />\n \$status = $status<br />\n";

和原文不同的是,我的没有报权限问题和数据库问题!?$status 就是空字符串!?

继续分析上面的 if 条件,发现 $status 走的是:$status = $_ENV['app']->test_api($url, $ip);

找到 ucenter 目录下 ./model/app.phptest_api 方法,源码如下:

1
2
3
4
5
6
7
8
9
10
11
function test_api($url, $ip = '') {
$this->base->load('misc');
if(!$ip) {
$ip = $_ENV['misc']->get_host_by_url($url);
}

if($ip < 0) {
return FALSE;
}
return $_ENV['misc']->dfopen($url, 0, '', '', 1, $ip);
}

发现走的是:return $_ENV['misc']->dfopen($url, 0, '', '', 1, $ip);

找到 ucenter 目录下 ./model/misc.phpdfopen 方法,源码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
.
.
.
if(function_exists('curl_init') && function_exists('curl_exec') && $allowcurl) {
$ch = curl_init();
$ip && curl_setopt($ch, CURLOPT_HTTPHEADER, array("Host: ".$host));
curl_setopt($ch, CURLOPT_USERAGENT, $_SERVER['HTTP_USER_AGENT']);
curl_setopt($ch, CURLOPT_URL, $scheme.'://'.($ip ? $ip : $host).':'.$port.$path);
.
.
.
if($errno || $status['http_code'] != 200) {
return;
} else {
return !$limit ? $data : substr($data, 0, $limit);
}
.
.
.
}
.
.
.

发现 if($errno || $status['http_code'] != 200) { 判定生效直接 return 了!

往上看看 CURLOPT_URL 的值:

1
2
3
4
5
6
7
var_dump($ip);
var_dump($host);
var_dump($scheme.'://'.($ip ? $ip : $host).':'.$port.$path);

// 127.0.0.1
// xc.cool
// https://127.0.0.1:443/api/uc.php?code=d20bmu...

因为我 ip 不止一个网站,所以后台配置里我没写 应用 IP,程序在没有写 应用 IP 的时候把这个值生成了 127.0.0.1,而 127.0.0.1/api/uc.php 找不到(写了 ip 也找不到,而 xc.cool/api/uc.php 找的到),所以上面的 if($errno || $status['http_code'] != 200) { 判定生效导致直接 return 了!

找到问题以后就好解决了,让 ($ip ? $ip : $host) 这里直接为 $host 的值就可以了,所以后台的 应用 IP应用的主 URL 里的域名,不要带开头的 https:// 和结尾的 / 即可!