記一次艱苦卓絕的Discuz x3 論壇升級過程


首先吐槽一下discuz 的官方論壇. 你要想下載到正確版本的discuz實在不容易找到. 有興趣自己去看吧. 就是因為這個原因, 我本來想要安裝x2.5版本(那時x3 還是Beta版本), 結果不小心下載成了x2.  也就是不久前, x3才發布正式版.   我最近想要安裝幾個插件,和皮膚, 但是打開插件中心, 發現我所有的插件都安裝不了, 說我的版本不支持.

我確信是x2.5 的插件, 語言版本也沒問題(我一直以為自己的論壇是x2.5), 這就奇怪了. 我也覺得discuz不會有這么明顯的bug啊.網上搜了很多,都說是版本不對, 請仔細核對版本. 這問題一直困然了我很久.  當時沒有緊急的需求,也就放下了.

直到今天, 我想安裝插件和皮膚, 我決定把這個安裝不了插件的問題搞定. 最終還是要核對版本, 我突然想到好像在別人的論壇下面看到過 類似 “x2.5″ 的版權申明(就是在論壇首頁的下面聲明的).  再看看我自己的是 “x2″, 所以我猜測可能是我的版本安裝錯了.  所以本地搭建php環境(wamp server), 去discuz官方仔細找到2.5的下載地址. 本地安裝.  證實我的猜測是對的. 我的論壇裝錯了.  現在查件中心絕大部分插件和皮膚都只支持2.5和3, 所以要想裝查件, 只能升級了.

我的論壇已經有很多用戶和數據了, 不能重裝, 現在只能選擇升級了. 好吧, 要升就直接升到最新x3吧.  好在官方的升級腳本還是比較詳細的, 而且我也相信discuz的實力, 官方說支持從x2直接升到x3.

為了確保萬無一失, 我先把服務器上的文件和數據庫都備份到本地的php環境. 在本地”預升級”一次.  按照官方給的步驟,很簡單就完成了.  打開頁面看了一下,也沒有發現問題. 放心了. 現在可以正式升級了.  歡迎大家訪問我的獨立博客交流: http://byNeil.com

第一步: 備份服務器的所有文件 和 數據庫.

按照官方的說明把文件都拷貝上去: http://www.discuz.net/thread-3265731-1-1.html

因為我是用root身份登錄到vps上去的,  所以拷貝上去的文件都是屬於root的,  nginx 運行所使用的”www”用戶是沒有權限訪問的. 所以要把權限都改對了,進入網站的根目錄:

?
1
2
chown www -R *
chgrp www -R *

 

把網站的文件都改到 用戶 “www” 用戶的名下.

此時可以開始升級了. 運行: http://xxxxxxxx.com/install/update.php

問題出現了, 剛才預升級的時候, 這里就可以點下一步升級了. 但是此時提示 :

“請先升級 UCenter 到 1.6.0 以上版本。如果使用為Discuz! X自帶UCenter,請先下載 UCenter 1.6.0, 在 utilities 目錄下找到對應的升級程序,復制或上傳到 Discuz! X 的 uc_server 目錄下,運行該程序進行升級”

(當時沒顧上截圖)

什么? ucenter版本不對?  不可能啊, 我已經預升級一次了.  不會啊.   於是把服務器上的文件和數據庫都恢復到升級前的狀態, 進ucenter看, 發現版本號的確是1.6.  所以沒問題.

然后又重復官方的教程.

最后運行: http://xxxxxxxx.com/install/update.php.   還是出現一樣的提示.

反復按照官方的教程做了三次, 到這都是這個提示, 我確信我沒有哪一步做錯了. 這就奇怪了.

於是打開update.php文件, 找到這個提示的位置:

1

是這里在比版本號.

上面的code是我改過的, $oldversion 這個變量是我加的, 就是想把版本號顯示出來, 看看到底是多少.

重新運行:  http://xxxxxxxx.com/install/update.php.

發現顯示出來的版本號是空白. 什么也沒有.

繼續追蹤: “uc_check_version” 函數, 因為版本號是從這的出來的.

搜索到uc_client/client.php

?
1
2
3
4
5
function uc_check_version() {
     $return = uc_api_post( 'version' , 'check' , array ());
     $data = uc_unserialize( $return );
     return is_array ( $data ) ? $data : $return ;
}

到了這里還是看不出來.

還是把服務器恢復原樣, 和本地比看有什么卻別.

恢復服務器文件和數據.

問題出在ucenter, 當然打開后台ucenter看看.

赫然發現: 通信失敗

2

 

我很清楚的記得,  原來這里是綠色的通信成功的.

難道是因為和ucenter的通信失敗了,  才導致update.php 文件獲得ucenter的版本號失敗, 所以導致我升級不成功的?

想到這里, 就要跟蹤為啥通信會失敗了.   (百度搜ucenter 通信失敗, 很多人都說是論壇和ucenter之間的設置不一致導致的. 我也反復確認了很多次,設置沒有問題.)

我們打開chrome的調試面板, 找到檢查通信失敗的地址:

點擊左側的 “應用管理”, 會發現下面這一條ajax的調用:

3

把這個地址在瀏覽器中打開:

4

 

發現他果然返回了通信失敗的字樣.

從上面的url 我們依次找到: uc_server/control/admin/app.php 文件, 並定位到 onping函數:

5

圖中可以看到我注掉的調試代碼, 都是我自己加的,為了跟蹤代碼的流程. 我發現流程是 進入了 “else” 塊, 然后出來之后 $status就是空白.  下面在判斷如果status是1表示成功. 否則就是失敗.

我在本地成功的環境下, 重現類似的場景, 發現也是進入了else塊, 但是出來的時候 status是1.

那就繼續追蹤 test_api() 這個函數.

搜索 “test_api”, 發現有兩處定義, 分別在uc_client\model\misc.php  和 \uc_server\model\app.php.

第一處是空實現, 所以只能看第二處了.

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function test_api( $url , $ip = '' ) {
     echo "in test pi" . '<br>' ;
     $this ->base->load( 'misc' );
     if (! $ip ) {
         $ip = $_ENV [ 'misc' ]->get_host_by_url( $url );
     }
             echo "line1:" . $ip . "<br>" ;
     if ( $ip < 0) {
         return FALSE;
     }
     echo "line2:" . $ip . "<br>" ;
     echo "line3:" . $url . "<br>" ;
     $ret = $_ENV [ 'misc' ]->dfopen( $url , 0, '' , '' , 1, $ip );
     echo "line4 ret value is:" . $ret . "<br>" ;
     return $ret ;
}

 

上面, 我加了一些調試代碼.

發現 $ret是空白.

那就是dfopen的問題了.

搜索dfopen. 他有多處實現, 但是有兩處比較可疑:

\uc_client\model\misc.php 和 \uc_server\model\misc.php

我現在兩個實現的入口處都設置echo語句. 發現時走的第二處.

於是進一步跟蹤第二處實現:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
     function dfopen($url, $limit = 0 , $post = '' , $cookie = '' , $bysocket = FALSE   , $ip = '' , $timeout = 15 , $block = TRUE, $encodetype  = 'URLENCODE' ) {
         echo "server model misc dfopen:" . "<br>" ;
         //error_log("[uc_server]\r\nurl: $url\r\npost: $post\r\n\r\n", 3, 'c:/log/php_fopen.txt');
         $ return = '' ;
         $matches = parse_url($url);
         $host = $matches[ 'host' ];
 
............
 
         if (function_exists( 'fsockopen' )) {
             echo "server model misc dfopen:fsockopen" . "<br>" ;
             $fp = @fsockopen(($ip ? $ip : $host), $port, $errno, $errstr, $timeout);
         } elseif (function_exists( 'pfsockopen' )) {
             echo "server model misc dfopen:pfsockopen" . "<br>" ;
             $fp = @pfsockopen(($ip ? $ip : $host), $port, $errno, $errstr, $timeout);
         } else {
             echo "server model misc dfopen:false" . "<br>" ;
             $fp = false ;
         }
 
................

 

我加了一些調試語句在里面.

當加到這里的時候,  想到,是不是 服務器的fsockopen函數被禁用了呢. 於是就沒再繼續加了. 趕快試. 上傳文件, 刷新url.

果然輸出了 “server model misc dfopen:false”

 

我擦, 原來是 fsockopen函數被禁用了啊.  趕快上傳php的探針,  發現fsockopen果然被禁用了.

6

我這是才想起來,  前幾天更換vps的時候, 沒注意, 可能忘了打開fsockopen 函數了.

趕快去服務器:/usr/local/php/etc 中 打開php.ini  找到disable_functions這一行. 從中把fsockopen和pfsockopen都刪掉.

然后重啟php:  service php-fpm restart

然后刷新上面的url, 返回通信成功了.

好了,現在再回到開頭.

把文件還原成升級前的樣子, 再按照官方說明, 升級文件.

運行: http://xxxxxxxx.com/install/update.php

這次終於正常了, 顯示准備完成,可以升級.

后面就比較順利了. 自動升級數據庫, 然后手動去吧緩存更新一下. 就好了.

就到這.

其中還省略了無數的彎路啊.

再次證明一個真理,  看似復雜的問題, 一定是由一個比較愚蠢的原因造成的.


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM