這些日子,我們公司的論壇時有不正常之處,典型問題就是:無徵兆的,「最近訪問論壇"列表,突然丟失,不少人大呼不方便。如果去後台更新一下子緩存,又正常了。

反覆查對,發現:/forumdata/cache/cache_forumdisplay.php 這個文件,其中緩存了論壇列表信息。出現問題時,其中本來應該正常緩存的信息,丟失了。

而緩存更新,在/include/cache.inc.php 的 updatecache() 函數之中,cache_forumdisplay.php 通過統一的流程製造,實在是想不通,什麼地方產生了特殊狀況。

因為這個丟失,當時看起來,是沒有任何徵兆,無法重現的。

無奈之下,在/include/cache.inc.php 的 writetocache 函數中,埋了一段代碼:

function writetocache($script, $cachenames, $cachedata ='', $prefix ='cache_'){
global $authkey, $timestamp;
if(is_array($cachenames)&&!$cachedata){
foreach($cachenames as $name){
$cachedata .= getcachearray($name, $script);
}
}    $dir= DISCUZ_ROOT.'./forumdata/cache/';
if(!is_dir($dir)){
@mkdir($dir, 0777);
}
if($fp =@fopen("$dir$prefix$script.php",'wb')){
fwrite($fp,"<?phpn//Discuz! cache file, DO NOT modify me!".
"n//Created: ".date("M j, Y, G:i").
"n//Identify: ".md5($prefix.$script.'.php'.$cachedata.$authkey)."nn$cachedata?>");
fclose($fp);
//

 

埋的代碼
if($script==='forumdisplay')
{
$fps .="GDVS:".print_r(get_defined_vars(),true)."n";
$fps .="DBTS:".print_r(debug_backtrace(),true)."n";
$fps .="nnn";
$fps ="DLINE:".__LINE__ ."n"."timeis:".date("Y-m-d H:i:s")."n". $fps;
if(strpos($cachedata,"$_DCACHE['forums']"))
{
writelog('debug_forumdisplay_find',$fps);
}
else
{
writelog('debug_forumdisplay_notfound',$fps);
}
}
} else {
dexit('Can not write to cache files, please check directory ./forumdata/ and ./forumdata/cache/ .');
}
}

一天以後,在/forumdata/logs/裏面,*****_notfound.php 裏面,逮到了一次丟失的過程,基本流程是:

/admincp.php->/admin/prune.inc.php->updatecache()->/include/cache.func.php->writetocache()

對應的實際操作,就是在網站的後台,執行批量刪除帖子的操作,其中有一個更新:updatecache(『globalstick』);

最後,定位到了 getcachevars() 這個函數裏面,找到了問題所在。

先賣個關子,0818 的時候,Discuz 發了一個補丁,詳見 http://www.discuz.net/thread-1388523-1-1.html 。

恰好更新了/include/cache.func.php 這個文件,在 getcachevars() 裏面加了一段代碼:

if(!preg_match("/^[a-zA-Z_x7f-xff][a-zA-Z0-9_x7f-xff]*$/", $key)){
continue;
}

其作用在於過濾非法變量。

殊不知,就是這段代碼,變成了罪魁禍首,導致新的問題產生。

程序實際運行過程中,會有_DCACHE[『forums』] 等類似的變量名,需要通過這個關卡,結果就是掛掉,直接導致對應的信息為空,從而是的緩存文件丟失信息。有興趣的朋友,可以自己跟蹤測試一下子。

修正的代碼如下:

if(!preg_match("/^[a-zA-Z_x7f-xff][a-zA-Z0-9_x7f-xff]*$/", $key)&&!preg_match("/^[a-zA-Z_x7f-xff][a-zA-Z0-9_
x7f-xff]*['[a-zA-Z_x7f-xff][a-zA-Z0-9_x7f-xff]*']$/", $key)){
continue;
}

讓_DCACHE[『forums』] 等類似的變量名通過,至此問題解決。

經查代碼發現,Discuz4.1.0 到 Discuz7.0.0,均存在該問題,所以請使用 Discuz 的同學們,從速修改,以免出現莫名其妙的問題。

---------- 在文件中查找 ----------
"/dp20090818/4.1.0/admin/styles.inc.php"(316,28):                        } elseif(!preg_match("/^[a-zA-Z_x7f-xff][a-zA-Z0-9_x7f-xff]*$/", $newcvar)) {
"/dp20090818/4.1.0/include/cache.func.php"(664,21):                if(!preg_match("/^[a-zA-Z_x7f-xff][a-zA-Z0-9_x7f-xff]*$/", $key)) {
"/dp20090818/5.0.0/admin/styles.inc.php"(320,28):                        } elseif(!preg_match("/^[a-zA-Z_x7f-xff][a-zA-Z0-9_x7f-xff]*$/", $newcvar)) {
"/dp20090818/5.0.0/include/cache.func.php"(776,21):                if(!preg_match("/^[a-zA-Z_x7f-xff][a-zA-Z0-9_x7f-xff]*$/", $key)) {
"/dp20090818/5.5.0/admin/styles.inc.php"(328,28):                        } elseif(!preg_match("/^[a-zA-Z_x7f-xff][a-zA-Z0-9_x7f-xff]*$/", $newcvar)) {
"/dp20090818/5.5.0/include/cache.func.php"(1087,21):                if(!preg_match("/^[a-zA-Z_x7f-xff][a-zA-Z0-9_x7f-xff]*$/", $key)) {
"/dp20090818/6.0.0/admin/styles.inc.php"(314,28):                        } elseif(!preg_match("/^[a-zA-Z_x7f-xff][a-zA-Z0-9_x7f-xff]*$/", $newcvar)) {
"/dp20090818/6.0.0/include/cache.func.php"(1425,21):                if(!preg_match("/^[a-zA-Z_x7f-xff][a-zA-Z0-9_x7f-xff]*$/", $key)) {
"/dp20090818/6.1.0/admin/styles.inc.php"(332,28):                        } elseif(!preg_match("/^[a-zA-Z_x7f-xff][a-zA-Z0-9_x7f-xff]*$/", $newcvar)) {
"/dp20090818/6.1.0/include/cache.func.php"(1378,21):                if(!preg_match("/^[a-zA-Z_x7f-xff][a-zA-Z0-9_x7f-xff]*$/", $key)) {
"/dp20090818/6.1.0F/admin/styles.inc.php"(332,28):                        } elseif(!preg_match("/^[a-zA-Z_x7f-xff][a-zA-Z0-9_x7f-xff]*$/", $newcvar)) {
"/dp20090818/6.1.0F/include/cache.func.php"(1359,21):                if(!preg_match("/^[a-zA-Z_x7f-xff][a-zA-Z0-9_x7f-xff]*$/", $key)) {
"/dp20090818/7.0.0/admin/styles.inc.php"(736,28):                        } elseif(!preg_match("/^[a-zA-Z_x7f-xff][a-zA-Z0-9_x7f-xff]*$/", $newcvar)) {
"/dp20090818/7.0.0/include/cache.func.php"(1503,21):                if(!preg_match("/^[a-zA-Z_x7f-xff][a-zA-Z0-9_x7f-xff]*$/", $key)) {
找到 14 個事件 (在 14 個文件中) 。
輸出完成 (耗時 0 秒)

沒有打 0818 補丁的,請從速從 http://www.discuz.net/thread-1388523-1-1.html 打最新補丁,然後與打過補丁的同學,一起把 getcachevars() 的這個問題修正。