Discuz 7.2坑爹集錦-PHP篇 update 20120525

Discuz 7.2坑爹集錦-PHP篇

ucc表明uc_client目錄
ucs表明uc_server目錄


類型:        代碼風格
坑爹指數:     ☆
點評:        DZ代碼不錯,不過其代碼風格對於維護來講比較痛苦。
原本應該儘可能避免在判斷中賦值表達式避免習慣以後本意的邏輯比較操做誤寫成賦值操做符而加大debug困難,而DZ偏偏相反不喜歡使用中間變量每每是變量賦值表達式直接用於IF判斷。估計康盛幸福的程序猿用的都是寬屏顯示器,因此他們至關吝嗇換行,人類已經已經阻止不了一條語句能夠超出19寸16:9寬屏液晶許多許多猶如黃河氾濫一發不可收拾直達長江入海口~
對於小括號使用不嚴格,IF/ELSEIF/WHILE/FOREACH後面緊接小括號而沒有加空格,雖然絕不影響執行結果,但對於非函數調用仍是在關鍵字和括號之間留個空吧。

 

----------------------------------------------------------------------------------------------------------------------------php


類型:        表情符號
坑爹指數:    ☆
代碼:        http://yourdomain/faq.php?action=faq&id=5&messageid=32
點評:        cry的表情符號代碼 :\'(,正確應該是 :'( ,建表SQL插入數據時代碼有問題。

----------------------------------------------------------------------------------------------------------------------------

類型:        代碼風格
坑爹指數:    ☆

代碼:        include/global.func.php ~400html

function forumperm($permstr) {
    global $groupid, $extgroupids;

    $groupidarray = array($groupid);
    foreach(explode("\t", $extgroupids) as $extgroupid) {
        if($extgroupid = intval(trim($extgroupid))) {    <------賦值仍是判斷? 太容易混淆人了
            $groupidarray[] = $extgroupid;
        }
    }
}
點評:    賦值仍是判斷? 太容易混淆人了
FIX:
foreach(explode("\t", $extgroupids) as $extgroupid) {
        $extgroupid = intval($extgroupid);
        $extgroupid > 0 && $groupidarray[] = $extgroupid;
    }

----------------------------------------------------------------------------------------------------------------------------

類型:        變量類型
坑爹指數:    ★
代碼:       
include/newreply.inc.php=240
    $parseurloff = !empty($parseurloff);
include/newthreads.inc.php~375
    $parseurloff = !empty($parseurloff);

點評:        會致使變量爲空字符串非int類型。由於mysql比較寬鬆對SQL標準支持不佳,對於字段類型輸入值校檢不嚴格:若是是int類型字段,你輸入的是空字符那麼會自動給你轉換成0。但這對之後的移植不利,對於我的之後在技術上的發展未必好。相似的是mysql LIMIT的寫法,既支持LIMIT {[offset,] row_count}格式也支持LIMIT {row_count OFFSET offset}標準,但大部分人就只知道使用前者而不知道後者標準格式。 mysql

FIX: linux

$parseurloff = empty($parseurloff) ? 0 : 1;


----------------------------------------------------------------------------------------------------------------------------

類型:        未定義變量(Undefined Variable/Index)
坑爹指數:    ★★
代碼:        多處。以 ucs/view/default下htm模板文件居多。
Undefined index: allowadminlog
----
Modified : ucs/view/default/admin_admin.htm
Modified : ucs/view/default/admin_feed.htm
Modified : ucs/view/default/admin_mail.htm
Modified : ucs/view/default/admin_note.htm

<li><input type="checkbox" name="allowadminlog" value="1" class="checkbox" {if $admin[allowadminlog]} checked="checked" {/if}/>{lang admin_allow_log}</li>
點評:        PHP弱類型語言,變量不預聲明便可使用,方便。但對未定義變量進行操做時會致使PHP拋出一個Notice,這在PHP中不算啥錯誤,但會給DZ調試帶來一些意想不到的問題:DZ採用XML做爲ajax交流格式,不知道是js代碼編寫問題仍是XML自己問題,若是php.ini中打開display_error開關,當前臺頁面調用ajax操做趕上PHP拋出日誌信息時前臺將會出錯,firebug中每每不是提示XML錯誤而是顯示common.js某行錯誤(好比 Error:s is NULL, $ is not exists之類的)。不熟悉的還覺得是JS代碼有問題,其實根源在於PHP代碼不嚴謹,而XML格式複雜嚴格。我的以爲網站ajax使用JSON比XML更佳,不管是後臺程序處理輸出代碼仍是前臺JS解析數據。對於PHP數組,一條echo json_encode($array)便可快捷返回JSON格式信息給前臺;而前臺JS一條eval "{data}"命令便可馬上解析成JS變量對象(處於安全考慮,如今不推薦使用eval來解析,若是使用jQuery那麼可使用$.ajax()的dataType:json或者直接$.getJSON()來直接得到數組變量)。

FIX:    關閉php.ini中display_error選項。或者修改DZ代碼使用isset()或者!empty()判斷變量,好比  nginx

{if isset($admin[allowadminlog]) && $admin[allowadminlog]} 或者 {if !empty($admin[allowadminlog])}

 

----------------------------------------------------------------------------------------------------------------------------程序員

類型:        未定義變量
坑爹指數:    ★★
代碼:        pm.php=47
$pmstatus = uc_pm_checknew($discuz_uid, 4);
    $filter = !empty($filter) && in_array($filter, array('newpm', 'privatepm', 'announcepm')) ? $filter : ($pmstatus['newpm'] ? 'newpm' : 'privatepm');
點評:         未對返回值$pmstatus['newpm']有效性進行判斷

 

----------------------------------------------------------------------------------------------------------------------------web

類型:        未定義變量
坑爹指數:    ★★
代碼:        pm.php=61
foreach($ucdata['data'] as $pm) {
    ....
    }
點評:        未對 $ucdata變量'data'鍵有效作判斷就直接開始循環,至關於對一個可能不存在的變量進行訪問並迭代。問題出在line49調用uc_pm_list()對$ucdata賦值,而ucc/control/pm.php: onls() 函數返回值$result未初始化'data'鍵名。
雖然PHP是弱類型,但好歹對函數返回值先作個判斷再操做吧。偷懶也就少些幾行代碼,可調試維護時花的時間就多了。

----------------------------------------------------------------------------------------------------------------------------

類型:        變量錯誤
坑爹指數:    ★★
代碼:        memcp.php line264.
        
$styleid = empty($styleidnew) ? $styleid : $styleidnew;
點評:    這位兄弟是否是求加薪不成功,沒有新生活致使見new就失望因而也不給變量new生活。
FIX:    $styleidnew = empty($styleidnew) ? $styleid : $styleidnew;

----------------------------------------------------------------------------------------------------------------------------ajax

 

類型:        變量使用
坑爹指數:    ★★
代碼:        include/global.func.php 1514
updateprompt()函數中$db->query("UPDATE {$tablepre}members SET prompt=prompt^1 WHERE uid='$discuz_uid' AND prompt=prompt|1", 'UNBUFFERED');
點評:        函數並未global聲明$discuz_uid變量
FIX:        使用$uid替代

----------------------------------------------------------------------------------------------------------------------------sql

 

類型:        變量使用
坑爹指數:    ★★★★
代碼:        admin/member=990:
$db->query("INSERT INTO {$tablepre}medallog (uid, medalid, type, dateline, expiration, status) VALUES ('$uid', '".$modmedal[medalid]."', '0', '$timestamp', '".$modmedal['expiration']."', '$medalstatus')");
點評:        $modmedal[medalid]缺乏單引號。在雙引號中使用數組變量DZ都採用不帶單引號的方式,好比 "... $modmedal[medalid] "而不使用繁瑣但更安全的大括號方式 "... {$modmedal['medalid']} ",不多使用例子中拼接字符串方式。此次難道用一次拼接,結果習慣的力量那麼大仍是用了不帶單引號的訪問方式。也許,也許小哥加班熬夜,眼花,沒看到先後的兩個小點還覺得是在雙引號的範圍內。
好的代碼習慣有時候能減小很多錯誤,也便於快速debug。好比儘可能少在判斷中使用賦值表達式,好比用.號拼接字符串時在其後或其前加個空格。後者還有個小好處就是用鼠標雙擊變量時能夠正確選按期望的範圍。


FIX:        把變量鍵名加上單引號 $modmedal['medalid']shell


----------------------------------------------------------------------------------------------------------------------------

類型:        變量類型
坑爹指數:    ★★★
代碼:        include/global.func.php=1339
$db->query("UPDATE {$tablepre}sessions SET uid='$discuz_uid', username='$discuz_user', 
groupid='$groupid', styleid='$styleid', invisible='$invisible', action='$discuz_action', 
lastactivity='$timestamp', lastolupdate='$lastolupdate', seccode='$seccode', fid='$fid',
 tid='$tid' $pageviewsadd WHERE sid='$sid'");
點評:        更新狀態時seccode值有時會出現驗證碼字符串而非int。寫入失敗,後臺時常有此日誌。問題出在那兒一直沒找到,算一個懸疑歷史問題坑
FIX:        暫時解決辦法判斷類型,使用is_numberic($seccode)判斷是否執行SQL

----------------------------------------------------------------------------------------------------------------------------


類型:        輸入錯誤
坑爹指數:    ★★
位置:        members.inc.php~1900
$db->query("UPDATE {$tablepre}members set uid=uid $updatesql WHERE $conditions", 'UNBUFFTERED');
點評:        俺自從用上gVim以後寫代碼完全拋棄龐大臃腫的zend statio了,emeditor用得也不多。感受vim用熟悉以後實在太舒服,不但提升速度而且更加高效,難怪對於VIM和Emacs,一條經典評價「VIM是編輯器之神,Emacs是神之編輯器」。對於「假裝成文本編輯器而實際乾的是操做系統活的Emacs」,我不想買腳踏板因此仍是安心用VIM吧。常常出現用j下移鼠標時文字排版大幅度變化或者進入莫名其妙的Ex模式一時退不出去,後來才發現是大寫鎖定了————之前輸入大寫習慣是使用Caps Locks鎖定大寫而後再輸入字符,不過有時候忘記解除大寫鎖定有時候解除操做卻按到大寫上的帽子上……哦是Tab上,因而j變成了<S-j>刪除段尾回車讓下一行併入當前行。因此後來我就改變習慣,除非特定狀況,大寫字符使用Shift組合鍵來輸入。但這又產生一個新問題,由於輸入時手掌形態改變,肌肉還沒習慣新的活動範圍因此之前順手的敲擊活動多少帶點彆扭,結果就是有些長字符串輸入錯誤。寫代碼的這位兄弟估計沒彈過鋼琴,一激情下蹦噠出一個不和諧音符。不過還好沒嚴重危害。

修改DZ時我使用TC進行了全文搜索替換,但後來又見着UNBUFFERED這位老哥。心中還奇怪難道TC沒搜索到麼,仔細一看,原來中間帶了個套~

FIX: UNBUFFTERED 修改成 UNBUFFERED

對於愛好Totalcommand的,右手腕下老繭厚的極力這兒插隊推薦VIM:
【簡明 Vim 練級攻略】
http://coolshell.cn/articles/5426.html 
http://www.oschina.net/question/55577_27380

對於嫌鼠標多餘的鍵盤控推薦Emacs:
【爲什麼Emacs和Vim被稱爲兩大神器】
http://www.oschina.net/question/12_15010

 

 

----------------------------------------------------------------------------------------------------------------------------

類型:        除零錯誤
坑爹指數:    ★★★★
代碼:        topicadmin.php 330
$db->query("UPDATE {$tablepre}threads SET .... rate='".intval(@($fpost['rate'] / abs($fpost['rate'])))."', moderated='1' WHERE tid='$newtid'");
代碼:        topicadmin.php~240    
@$firstpost['rate'] = $firstpost['rate'] / abs($firstpost['rate']);
代碼:        space.php 95
@$percent = round($member['posts'] * 100 / $db->result_first("SELECT COUNT(*) FROM {$tablepre}posts"), 2);
代碼:        stats.php~260
$pageviewavg = sprintf ("%01.2f", ($stats_total['visitors'] ? $stats_total['hits'] / $stats_total['visitors'] : 0));
    !$post && $post = 1;
    $activeindex = round(($membersaddavg / $members + $postsaddavg / $posts) * 1500 + $threadreplyavg * 10 + $mempostavg * 1 + $mempostpercent / 10 + $pageviewavg);
代碼:        stats.php 多處
$avgmodactioncount = @($totalmodactioncount / count($members));
    @$width = intval(370 * $count / $max);
    @$percent = sprintf ("%01.1f", 100 * $count / $sum);
    $membersaddavg = round($members / $runtime);
代碼:        admin/forums.inc.php~640
$forum['autoclose'] = $forum['autoclose'] / abs($forum['autoclose']);
代碼:        stats.php~550
foreach($extendedcredit as $i => $members) {
                @$width = intval(370 * $members['credits'] / $max);
                $width += 2;
代碼:        stats.php~750:
'avgoffdays' => @($totaloffdays / count($members)),
        'avgthismonthposts' => @($totalthismonthposts / count($members)),
        'avgtotalol' => @($totalol / count($members)),
        'avgthismonthol' => @($totalthismonthol / count($members)),
        'avgmodactions' => @($totalmodactions / count($members)),
                'avgthismonthposts' => @($totalthismonthposts / count($members)),
                'avgtotalol' => @($totalol / count($members)),
                'avgthismonthol' => @($totalthismonthol / count($members)),
                'avgmodactions' => @($totalmodactions / count($members)),


代碼:    misc.php~720
$threadrate = @intval(@($post['rate'] + $rate) / abs($post['rate'] + $rate));
點評:    避免除零錯誤是學習編程時的基本概念,沒想到在DZ中還能挖出這麼多來。某些問題除零錯誤是在建站初始無對應數據時發生,待正常運做以後就不會發生。而多數將伴隨你網站終身,不斷充實你的error-log文件~ 若是說某位程序大猿數學很差不知道除零錯誤還能夠理解,但惡劣的是有些人明知道這個問題卻使用@來抑制錯誤,這就屬於有意找抽的……

----------------------------------------------------------------------------------------------------------------------------

類型:        字段名錯誤
坑爹指數:    ★★★
代碼:        include/global.func.php 1622-1623
//$sql = "SELECT * FROM {$tablepre}feeds WHERE $where ORDER BY feed_id DESC LIMIT $start_limit, $conf[num]"; // DZ本身註釋掉的
$sql = "SELECT * FROM {$tablepre}feeds WHERE $where ORDER BY feedid DESC LIMIT $start_limit, $conf[num]";
點評:        dz.cdb_feeds這個表的主鍵是feed_id, ucenter.feeds表的主鍵是feedid.大家程序員經過註釋把feed_id改爲feedid,可是dz數據表沒升級啊。難道我補丁沒下全?這個坑不影響結果集,但對feed讀取時的排序有影響(使用在ORDER BY中)

 

FIX:        修改feed_id 爲 feedid



----------------------------------------------------------------------------------------------------------------------------
類型:        流程錯誤
坑爹指數:    ★
代碼:        my.php~710
if($db->result_first("SELECT COUNT(*) FROM {$tablepre}favoritethreads WHERE tid='$tid' AND uid='$discuz_uid'")) {
showmessage('favoritethreads_exists', dreferer());
}
$timestamp = time();
$attention_exists = $db->result_first("SELECT COUNT(*) FROM {$tablepre}favoritethreads WHERE tid='$tid' AND uid='$discuz_uid'");  // <===
點評:        前面查詢若是存在結果(即有收藏)就已經退出執行流程並提示用戶 'favoritethreads_exists',下面幹嗎又執行一次呢,難道真會再次運行?

 

---------------------------------------------------------------------------------------------------------------------------

類型:        流程錯誤
坑爹指數:    ★★
代碼:        admin/cpanel.share.php 29 adminsession()函數
$session = $this->_loadsession($uid, $ip, $GLOBALS['admincp']['checkip']);   
            $this->errorcount = $session['errorcount'];        // <----
            $this->storage = $session['storage'];
            if(empty($session)) {                // <------
                $this->creatsession($uid, $adminid, $ip);
                $cpaccess = 1;
            } elseif($session['errorcount'] == -1) {
點評:        對$this->errorcount賦值先於 if (empty($session)) 判斷,會致使 update()方法SQL錯誤($this->errorcount非數字)

FIX:        先判斷再賦值

} elseif($session['errorcount'] == -1) {
                $this->errorcount = $session['errorcount'];    // must before exec $this->update() !!
                $this->storage = $session['storage'];
                $this->update();
                $cpaccess = 3;
            } elseif($session['errorcount'] <= 3) {




----------------------------------------------------------------------------------------------------------------------------

類型:        流程錯誤
坑爹指數:    ★★★
代碼:        include/magic/magic_del.inc.php 29
if($post['first']) {
        foreach(array('threads', 'threadsmod', ... 'attachments', ...) as $value) {
            $db->query("DELETE FROM {$tablepre}$value WHERE tid='$post[tid]'", 'UNBUFFERED');
        }

        $query = $db->query("SELECT uid, attachment, dateline, thumb, remote FROM {$tablepre}attachments WHERE tid='$post[tid]'");
        while($attach = $db->fetch_array($query)) {
            dunlink($attach['attachment'], $attach['thumb'], $attach['remote']);
        }
點評:        attachments的記錄都被刪除了還能再取出記錄去unlinke麼?雖然再次操做取不出記錄但不表明數據庫沒工做啊,它仍是會傻傻地去查詢索引的。


----------------------------------------------------------------------------------------------------------------------------

類型:        重複執行
坑爹指數:    ★★
代碼:        admin/forums.inc.php 52-78
for($i = 0; $i < count($forums); $i++) {        // <-----
            if($forums[$i]['type'] == 'group') {
                echo showforum($i, 'group');
                for($j = 0; $j < count($forums); $j++) {    // <-----
                    if($forums[$j]['fup'] == $forums[$i]['fid'] && $forums[$j]['type'] == 'forum') {
                    ....
                    }
                }
                echo showforum($i, '', 'lastboard');
            } elseif(!$forums[$i]['fup'] && $forums[$i]['type'] == 'forum') {
                echo showforum($i);
                for($j = 0; $j < count($forums); $j++) {    // <-----
                ....
                }
                echo showforum($i, '', 'lastchildboard');
            }
        }
點評:        內外兩層for循環使用的count($forums)條件判斷能夠在循環開始前就計算出個結果賦值給一個變量而後之後就訪問該變量。可能DZ認爲一個論壇版塊不會太多因此吃多點也不會噎着~

----------------------------------------------------------------------------------------------------------------------------

類型:        數值類型
坑爹指數:    ★★★★
代碼:        stats.php 548 在線時間統計
if(isset($statvars['thismonth'])) {
        $thismonth = unserialize($statvars['thismonth']);
    } else {
        $dateline = strtotime(gmdate('Y-n-01', $timestamp));
        $query = $db->query("SELECT o.uid, m.username, o.thismonth AS time .....
        while($online = $db->fetch_array($query)) {
            $online['time'] = round($online['time'] / 60, 2); // <------
            $thismonth[] = $online;
        }
        $newstatvars[] = "'onlines', 'thismonth', '".addslashes(serialize($thismonth))."'";
    }
點評:    雖然 round($online['time'] / 60, 2) 限定了小數位數2位,但超過1位小數的數字在serialize()時將會變成近似值!獲得相似的結果 a:2:{i:0;a:3:{s:3:"uid";i:1;s:8:"username";s:3:"root";s:4:"time";d:36.8299999999999982946974341757595539093017578125;}i:1;
看到36.82以後跟隨的那麼一長串數字吧,過長的字符串將會影響cdb_statvars.(onlines total)的寫入速度。不過由於論壇統計頻率比較低因此對性能影響不會太明顯或者很差查到
一樣問題存在於接下來的 thismonth 處理。此坑之精巧在於serialize()與unserialize()對於數字都取近似值,保存進去是近似值但取出來unserialize()結果還就是原來的值~
FIX: 把此值做爲字符串類型處理便可



----------------------------------------------------------------------------------------------------------------------------

類型:        函數調用
坑爹指數:    ★★★
代碼:        memcp.php 544,615
$query = $db->query("SELECT COUNT(*) FROM {$tablepre}paymentlog WHERE uid='$discuz_uid'");
        $totalamount = $db->result($query, 1);
點評:         第二個參數1致使不會有結果,前面的查詢條件只可能返回一行記錄,而不會有第二行因此指定1是錯誤的。不是說程序猿數數都從0開始;日子9號過了是A號;向程序員朋友借錢1K他會給你1024塊。難道這也是臨時工代碼……



----------------------------------------------------------------------------------------------------------------------------

類型:        重複執行
坑爹指數:    ★★★★
代碼:        admin/prune.inc.php 144,146
$db->query("DELETE FROM {$tablepre}rewardlog WHERE tid IN ($tidsdelete)", 'UNBUFFERED');
代碼:        modcp/threads.inc.php 232,233
$db->query("DELETE FROM {$tablepre}threadsmod WHERE tid IN ($tidsdelete)", 'UNBUFFERED');
點評:        當第一次刪除以後執行第二次時雖然不會有實際刪除操做但同樣要作索引查找以匹配記錄給數據庫帶來多餘的負擔。難道DZ程序員之前玩過linux,關機重啓以前要輸入sync && sync重複來確保緩衝寫入磁盤。mysql好像沒這個特性也不健忘吧,它但是數據庫耶,不須要你一個命令重複n次纔會磨磨蹭蹭去作的呀。

----------------------------------------------------------------------------------------------------------------------------

類型:        變量使用
坑爹指數:    ★
代碼:        ucs/avatar.php
define('UC_API', strtolower(($_SERVER['HTTPS'] == 'on' ? 'https' : 'http').'://'.$_SERVER['HTTP_HOST'].substr($_SERVER['PHP_SELF'], 0, strrpos($_SERVER['PHP_SELF'], '/'))));
點評:        未檢測 $_SERVER['HTTPS']變量存在就直接使用,$_SERVER['PHP_SELF']在nginx下可能爲空。如今Apache雖然依舊是webserver份額老大,但linux已經不是它的天下,nginx異軍突起,增加迅速。top1000網站中已經佔據25%的份額超過了IIS成了第二。Nginx+PHP-FPM(fastcgi)的搭配已經被愈來愈多的網站採用。而且nginx的配置文件簡潔,比如程序代碼,易讀性可配置性要比httpd.conf好很多。不過nginx對HTTP1.1標準支持不完整,致使PHP_INFO/PHP_SELF變量可能爲空。鑑於DZ7.2代碼比較老,Nginx又很新,康盛也懶得爲此打補丁吧。

FIX:    在nginx.conf中正確配置SCRIPT_NAME變量傳遞給後臺,PHP中使用$_SERVER['SCRIPT_NAME']
define('UC_API',
    (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on' ? 'https' : 'http'). '://'. $_SERVER['HTTP_HOST'].
    ($_SERVER['PHP_SELF']
        ?  substr($_SERVER['PHP_SELF'], 0, strrpos($_SERVER['PHP_SELF'], '/'))
        :  substr($_SERVER['SCRIPT_NAME'], 0, strrpos($_SERVER['SCRIPT_NAME'], '/')))
);

----------------------------------------------------------------------------------------------------------------------------

類型:        變量使用
坑爹指數:    ★★
代碼:        include/post.func.php 468 updateattach()
$anew['perm'] = $allowsetattachperm ? $anew['perm'] : 0;
點評:        $anew數組中並無 'perm'這個鍵名.下面SQL插入時也未使用此鍵名變量!難道是個彩蛋?可怎麼調出來呢,↑↑↓↓←→←→AB沒效果耶~

 

----------------------------------------------------------------------------------------------------------------------------

類型:        變量使用
坑爹指數:    ★★★
代碼:        include/post.func.php=468 updateattach()
$anew['perm'] = $allowsetattachperm ? $anew['perm'] : 0;
代碼:        include/post.func.php=472
$db->query("UPDATE {$tablepre}attachments SET readperm='$anew[readperm]',
點評:        未作鍵名檢查————發帖或修改時若是用戶刪除了附件讀取權限值(默認0)爲空則頁面表單中 name="attachnew[aid][readperm]"這個input對象不會提交,後臺接收到的POST變量無此鍵名。SQL執行無效。

FIX:       

$anew['readperm'] = $allowsetattachperm && isset($anew['readperm']) ? intval($anew['readperm']) : 0;

 

----------------------------------------------------------------------------------------------------------------------------

類型:        變量使用
坑爹指數:    ★★★
代碼:        include/post.func.php=216
$anew['perm'] = $allowsetattachperm ? $anew['perm'] : 0;
代碼:        include/post.func.php=472
$attach['perm'] = $allowsetattachperm ? intval($attachperm[$key]) : 0;
點評:        同上

----------------------------------------------------------------------------------------------------------------------------

類型:        變量使用
坑爹指數:    ★★
代碼:        pm.php=47
$pmstatus = uc_pm_checknew($discuz_uid, 4);
    $filter = !empty($filter) && in_array($filter, array('newpm', 'privatepm', 'announcepm')) ? $filter : ($pmstatus['newpm'] ? 'newpm' : 'privatepm');
點評:         未對返回值$pmstatus['newpm']有效性進行判斷

 

----------------------------------------------------------------------------------------------------------------------------

類型:        變量使用
坑爹指數:    ★★
代碼:        pm.php=61
foreach($ucdata['data'] as $pm) {
    ....
    }
點評:        未對 $ucdata變量'data'鍵有效作判斷就直接開始循環,至關於對一個可能不存在的變量進行訪問並迭代。問題出在line49調用uc_pm_list()對$ucdata賦值,而ucc/control/pm.php: onls() 函數返回值$result未初始化'data'鍵名。
雖然PHP是若類型,但好歹對函數返回值先作個判斷再操做吧。偷懶也就少些幾行代碼,可調試維護時花的時間就多了。

----------------------------------------------------------------------------------------------------------------------------



類型:        字符處理
坑爹指數:    ★★★★
症狀:        邊欄模塊最新帖最新回覆對標題中單引號顯示爲&#39;
點評:        不知道爲什麼一直沒修復這個bug,難道是我修改其餘代碼關聯影響到這兒?反正根源是DZ在入庫時htmlspecialchars()只對雙引號處理而未對單引號轉義
FIX:        修改以下文件調用帶ENT_QUOTES參數的htmlspecialchars()函數來替代str_replace()函數處理
include/request.func.php
$datalist[$data['tid']]['subject'] = isset($data['subject']) ? str_replace('\\\'', '&#39;', addslashes($data['subject'])) : NULL;
FIXTO:
$datalist[$data['tid']]['subject'] = isset($data['subject']) ? htmlspecialchars(htmlspecialchars_decode($data['subject']), ENT_QUOTES) : NULL;
而後修改global.func.php, ucs/mode/base.php, ucclient/mode/base.php的cutstr()函數:
//$string = str_replace(array('&amp;', '&quot;', '&lt;', '&gt;', '&#39;'), array('&', '"', '<', '>', '\''), $string);
    $string = htmlspecialchars_decode($string, ENT_QUOTES);
....
    //$strcut = str_replace(array('&', '"', '<', '>', '\''), array('&amp;', '&quot;', '&lt;', '&gt;', '&#39;'), $strcut);
    $strcut = htmlspecialchars($strcut, ENT_QUOTES);


----------------------------------------------------------------------------------------------------------------------------

類型:        頁面效果
坑爹指數:    ★
症狀:        當bbcodeoff時帖子中‘最後修改’的標籤混亂
FIX:        include/discuzcode.func.php: 添加一段判斷
line126開始的判斷拆分開
if(!$bbcodeoff && $allowbbcode) {// line126
        ....
    }            // line201
修改爲
    if($allowbbcode) {        // line126
        if (!$bbcodeoff) {
            .....
        }               
        // 添加開始
        elseif ($bbcodeoff && substr($message, 0, 5) === '[i=s]') {        // allow parse '[i=s]last modified by [/i]' even if bbcodeoff
            $message = preg_replace('/^\[i=s\](.*)\[\/i\]/', '<i class="pstatus">\\1</i>', $message );
        } //添加結束
    }        // line201+n




----------------------------------------------------------------------------------------------------------------------------

類型:        邏輯錯誤
坑爹指數:    ★★★★
代碼:        topicadmin.php ~320    分割主題
$db->query("UPDATE {$tablepre}posts SET first='1', subject='$subject' WHERE fid='$waiting_fid' AND pid='".$splitauthors[0]['pid']."'" );
點評:        first='1'只設置了一次,若是分割主題時選擇包含了1樓那麼原主題內變成1樓的帖子的first依然爲0. 原本在不支持事務的MyISAM引擎上作分隔主題這種操做就具備必定危險性,不過DZ更直接增長了這個這個機率。提醒你分割主題時不要把頂樓分割出去喲,否則剩下變成1樓的帖子將會成爲孤兒。多來幾回你就會明確記住這個準則了,也不會由於數據庫偶爾非原子性操做帶來的隨機故障而煩惱。這多麼簡單啊。呵呵
FIX:        line327   
$db->query("UPDATE {$tablepre}posts SET subject='".addslashes($thread['subject'])."' WHERE pid='$fpost[pid]'");
修改成
$db->query("UPDATE {$tablepre}posts SET first=1, subject='".addslashes($thread['subject'])."' WHERE pid='$fpost[pid]'");




----------------------------------------------------------------------------------------------------------------------------

類型:        執行流程
坑爹指數:    ★★★
代碼:        include/common.inc.php 349
$forum = $db->fetch_first("SELECT t.tid, t.closed,".(defined('SQL_ADD_THREAD') ? SQL_ADD_THREAD : '')." f.*, ff.* $accessadd1 $modadd1, f.fid AS fid
            FROM {$tablepre}threads t ....
        $tid = $forum['tid'];
點評:        若是查詢結果空$forum將會false,不作判斷而直接賦值給$tid會出錯,不然就可能要繼續執行到後繼的viewthreads.php中的判斷,浪費系統資源。另外viewthreads.php 也未對$tid判斷即以此爲條件直接查詢,徒增DB負擔(MySQL會有 ‘Impossible WHERE noticed after reading const tables’ )
FIX:        應該查詢結束後當即對$forum作判斷並設置一個變量做標誌再考慮給$tid賦值而後在當前頁面最底部判斷,若是標誌真則當即輸出404頭直接退出。

----------------------------------------------------------------------------------------------------------------------------

 

類型:        未知
坑爹指數:    ★★★★
代碼:        uc_client/model/note.php=64
foreach((array)$this->apps as $appid => $app) {
            $appid = $app['appid'];        <---------??
            if($appid == intval($appid)) {
                if($appids && !in_array($appid, $appids)) {
                    $appadd[] = 'app'.$appid."='1'";
                } else {
                    $varadd[] = "('noteexists{$appid}', '1')";
                }
            }
        }
點評:        一直沒研究明白這個賦值要表達什麼意思。難道這位當時正在韓大嘴語錄,看到「瞄的是A,想的是B,解說的是C,觀衆覺得是D,其實指的是E」這一段,頓悟,遂看到是代碼,想的是妹妹,說的是工資,同事覺得是八卦,領導覺得是抽風~
FIX:    以我類人猿的智商估計多是這樣:
foreach((array)$this->apps as $appid => $app) {
            if(intval($appid) == $app['appid']) {        // 幫你精簡一行代碼
                if($appids && !in_array($appid, $appids)) {
                    $appadd[] = 'app'.$appid."='1'";
                } else {
                    $varadd[] = "('noteexists{$appid}', '1')";
                }
            }
        }

-------------------------------------------------------------------------------------------------------------------------

類型:        代碼錯誤
坑爹指數:    ★★
代碼:        include/request.func.php=372

case 'hourposts';

點評:        這個芝麻坑真難發現啊
FIX:       

case 'hourposts':

 

-------------------------------------------------------------------------------------------------------------------------

類型:        安全漏洞
坑爹指數:    ★★★
代碼:        include/newreply.inc.php~381

if($modnewreplies) {
        $db->query("UPDATE {$tablepre}forums SET todayposts=todayposts+1 WHERE fid='$fid'", 'UNBUFFERED');
        showmessage('post_reply_mod_succeed', "forumdisplay.php?fid=$fid");
    } else {

代碼:        include/newthread.inc.php~440

if($modnewthreads) {
        $db->query("UPDATE {$tablepre}forums SET todayposts=todayposts+1 WHERE fid='$fid'", 'UNBUFFERED' );
        ...
    } else {

點評:        若是此帖發佈須要審覈,那麼這段代碼將會形成一個漏洞:此用戶就能夠發帖而不受發帖間隔時間的限制!若是「會員每小時發帖數限制」也無限制那麼雖然帖子不會直接顯示出來但將會形成數據庫增大給後臺管理形成麻煩。
FIX:        在showmessage()以前更新用戶最近發帖時間戳

$db->exec("UPDATE {$tablepre}members SET lastpost='$timestamp' WHERE uid='$discuz_uid'", 'UNBUFFERED');



-------------------------------------------------------------------------------------------------------------------------

 類型:        代碼錯誤
坑爹指數:    ★
代碼:        admin/db.inc.php=82

showtablerow('', '', '<input class="checkbox" name="chkall" onclick="checkAll(\'prefix\', this.form, \'customtables\', \'chkall\', true)" checked="checked" type="checkbox" id="chkalltables" /><label for="chkalltables"> '.lang('db_export_custom_select_all').' - '.lang('db_export_discuz_table')).'</label>';


點評:        老眼昏花括弧沒包好喲
FIX:        

showtablerow('', '', '<input class="checkbox" name="chkall" onclick="checkAll(\'prefix\', this.form, \'customtables\', \'chkall\', true)" checked="checked" type="checkbox" id="chkalltables" /><label for="chkalltables"> '.lang('db_export_custom_select_all').' - '.lang('db_export_discuz_table').'</label>');

 

原本計劃單獨開一PHP優化篇。後來發現下面坑爹代碼多數會影響性能(PHP以及數據庫執行),修復了bug即優化。故合併爲一篇。

補充個優化PHP的:
若是你的服務器http server支持Gzip/deflate壓縮,那麼就使用http serer提供的功能,併到後臺,全局-優化設置-服務器優化把「頁面 Gzip 壓縮」選項設定爲否。
若是設定「是」,那麼將使用DZ提供的一個gzip PHP插件來實現壓縮頁面。缺點是耗費PHP腳本執行時間,對於nginx+php-fpm模式運行更容易出現502錯誤。

 


版權曾經擁有,歡迎網上分享

轉載請保留連接 http://my.oschina.net/u/126398/blog/38873

相關文章
相關標籤/搜索