最近幫論壇裡的會員解決了一個問題。就是 DIY 裡面,模組沒有,顯示空白。下面我就簡述下,如何排查的這個問題。大家的問題可能與這個問題一樣,也可能不一樣。但是,檢查問題的思路是一樣的。希望有能力的站長出現這個問題後檢查一下。

首先進入 DIY 後。點選模組的連結是

  1. <a id="hd_mod" onclick="spaceDiy.getdiy('blockclass');this.blur();return false;" href=""> 模組</a>

在這裡呼叫了 js 函式 getdiy() 並且傳進一個引數 'blockclass' ,在 portal_diy.js 中我找到了這個函式。 997 行。
其中流程執行的程式段是

  1.     getdiy : function (type) {
  2.         if (type) {
  3.             var nav = $('controlnav').children;
  4.             for (var i in nav) {
  5.                 if (nav[i].className == 'current') {
  6.                     nav[i].className = '';
  7.                     var contentid = 'content'+nav[i].id.replace('nav', '');
  8.                     if ($(contentid)) $(contentid).style.display = 'none';
  9.                 }
  10.             }
  11.             $('nav'+type).className = 'current';
  12.             if (type == 'start' || type == 'frame') {
  13.                 $('content'+type).style.display = 'block';
  14.                 return true;
  15.             }
  16.             if(type == 'blockclass' && $('content'+type).innerHTML !='') {
  17.                 $('content'+type).style.display = 'block';
  18.                 return true;
  19.             }
  20.             var para = '&op='+type;
  21.             if (arguments.length > 1) {
  22.                 for (var i = 1; i < arguments.length; i++) {
  23.                     para += '&' + arguments[i] + '=' + arguments[++i];
  24.                 }
  25.             }
  26.             var ajaxtarget = type == 'diy' ? 'diyimages' : '';
  27.             var x = new Ajax();
  28.             x.showId = ajaxtarget;
  29.             x.get('portal.php?mod=portalcp&ac=diy'+para+'&inajax=1&ajaxtarget='+ajaxtarget,function(s, x) {
  30.                 if (s) {
  31.                     if (typeof cpb_frame == 'object' && !BROWSER.ie) {delete cpb_frame;}
  32.                     if (!$('content'+type)) {
  33.                         var dom = document.createElement('div');
  34.                         dom.id = 'content'+type;
  35.                         $('controlcontent').appendChild(dom);
  36.                     }
  37.                     $('content'+type).innerHTML = s;
  38.                     $('content'+type).style.display = 'block';
  39.                     if (type == 'diy') {
  40.                         spaceDiy.setCurrentDiy(spaceDiy.currentDiy);
  41.                         if (spaceDiy.styleSheet.rules.length > 0) {
  42.                             Util.show('recover_button');
  43.                         }
  44.                     }
  45.                     var evaled = false;
  46.                     if(s.indexOf('ajaxerror') != -1) {
  47.                         evalscript(s);
  48.                         evaled = true;
  49.                     }
  50.                     if(!evaled && (typeof ajaxerror == 'undefined' || !ajaxerror)) {
  51.                         if(x.showId) {
  52.                             ajaxupdateevents($(x.showId));
  53.                         }
  54.                     }
  55.                     if(!evaled) evalscript(s);
  56.                 }
  57.             });
  58.         }
  59.     }

看到這裡我們會看到程式會請求一個地址

  1. http://x2/portal.php?mod=portalcp&ac=diy&op=blockclass&inajax=1&ajaxtarget=

看到這個之後,我們先放一邊,在 portalcp_diy.htm 中我們找到了生成 diy 模組選項的這塊程式碼

  1.         <!--{loop $_G['cache']['blockclass'] $key $value}-->
  2.         <!--{if $isfirst}-->
  3.         <!--{eval $isfirst=0;}-->
  4.         <ul id="contentblockclass_$key">
  5.         <!--{else}-->
  6.         <ul id="contentblockclass_$key" >
  7.         <!--{/if}-->
  8.                 <li >
  9.                         <ol>
  10.                         <!--{loop $value[subs] $skey $svalue}-->
  11.                                 <li
    ><label onmousedown="drag.createObj
    (event,'block','$skey');" onmouseover="className='hover';"
    onmouseout="this.className='';">$svalue[name]</label></li>
  12.                         <!--{/loop}-->
  13.                         </ol>
  14.                 </li>
  15.         </ul>
  16.         <!--{/loop}-->

在這裡使用了 dz 中的模板語法 loop 與 /loop 間迴圈把 $_G['cache']['blockclass'] 中的值以 html 形式輸出。好了,我們知道了問題的上一個根源。 $_G 是 dx 中的全域性變數,那我們在 dx 中把它輸出出來看看,裡面有沒有內容。在

  1. http://x2/portal.php?mod=portalcp&ac=diy&op=blockclass&inajax=1&ajaxtarget=

根據這個地址,找到 portal_portalcp.php,其中還包含了比較重要的一個檔案是 portalcp_diy.php
其中的

  1. if($op == 'blockclass') {

這段對我們上面 js 中的請求進行了處理。

  1. loadcache('blockclass');

這段是讀取 blockclass 為名字的快取,讀到 $_G['cache']['blockclass'] 中。說到這裡,大家應該明白這之間的關係了吧。

滑鼠點選觸發 js 函式,js 函式中 get 一個 php 檔案,php 檔案中對這次請求進行了處理,讀取了 blockclass 快取,存到了 $_G['cache']['blockclass'] 中,然後在網站模板檔案中把它們迴圈顯示出來。就是這樣。

問題分析到這裡知道了流程,那麼這個問題就出在 $_G['cache']['blockclass'] 上。我嘗試列印了 $_G['cache']['blockclass'] 的值。

  1. <?php
  2. require './source/class/class_core.php';
  3. $discuz = & discuz_core::instance();
  4. $discuz->cachelist = $cachelist;
  5. $discuz->init();
  6. loadcache('blockclass');
  7. print_r($_G['cache']['blockclass']);
  8. ?>

這段程式就是讀下 blockclass 快取,然後把 $_G['cache']['blockclass'] 的值打出來,奇怪的是,我在這個站長的站上這個值列印出來是空的,只有結構沒有資料,所以當然顯示模組為空了。
沒辦法,只有繼續往上查。查什麼?查讀取快取的程式,讀取模組快取的函式是 blockclass_cache() 在 function_block.php 中
在這裡,我摘出了部分程式碼,然後讓它輸出我需要的東西。程式程式碼不在這裡貼了。上傳附件中了。

在這個函式中程式分別讀取 class/block 下面資料夾中的程式檔案,輸出結果如圖:

QQ截圖20110829192559.png

分別把它讀取 block 模組的檔案、類、方法的步驟讀出並且顯示出來。使用這個檔案,在站長的伺服器上發現了問題,輸出並沒有進行完,只輸出到了一半就停
止了。卡在了一個站長安裝的 dx 模組上。問題就在這裡了。我把在 block 資料夾中出問題的那個模組移出 block 目錄。在看一遍。輸出都正常了。這樣更
新一遍快取。首頁 DIY 模組就出來了。

總結來說。這個是因為第三方的程式碼植入了 dx 的快取體系中,在 loadcache('blockclass'); 的時候。這個第三方程式碼出現了問題。程式並沒有按照以往人們想象的那樣,會報錯?導致了所需要的快取沒有進行更新導致的錯誤。