`
waiting
  • 浏览: 234789 次
  • 性别: Icon_minigender_1
  • 来自: cq
社区版块
存档分类
最新评论

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后面紧接小括号而没有加空格,虽然毫不影响执行结果,但对于非函数调用还是在关键字和括号之间留个空吧。

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

类型:        表情符号
坑爹指数:    ☆
代码:        http://yourdomain/faq.php?action=faq&id=5&messageid=32
点评:        cry的表情符号代码 :\'(,正确应该是 :'( ,建表SQL插入数据时代码有问题。


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

类型:        代码风格
坑爹指数:    ☆
代码:        include/global.func.php ~400

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}标准,但大部分人就只知道使用前者而不知道后者标准格式。

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

类型:        未定义变量(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()判断变量,比如

{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']有效性进行判断

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


类型:        未定义变量
坑爹指数:    ★★
代码:        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;
 


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

类型:        变量使用
坑爹指数:    ★★
代码:        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替代

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


类型:        变量使用
坑爹指数:    ★★★★
代码:        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']

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


类型:        变量类型
坑爹指数:    ★★★
代码:        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没搜索到么,仔细一看,原来中间带了个套~
对于爱好Totalcommand的,右手腕下老茧厚的极力这儿插队推荐VIM:
【简明 Vim 练级攻略】
http://coolshell.cn/articles/5426.html or
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://waiting.iteye.com/blog/1343665

 

 

0
0
分享到:
评论

相关推荐

    QQ互联插件版 for Discuz! 7.2 v1.0-源码.zip

    7.2 v1.0"的源码可以让我们深入了解如何将QQ开放API与Discuz! 系统进行对接,以及如何处理用户授权、登录状态同步等问题。源码中可能包含了以下几个关键部分: 1. **接口调用**:源码会包含与QQ服务器交互的接口...

    礼品兑换插件for Discuz7.2 utf-8版-修改安装出错

    标题中的“礼品兑换插件for Discuz7.2 utf-8版-修改安装出错”表明这是一个针对Discuz 7.2版本论坛系统的礼品兑换功能的插件,且该插件在原始状态下可能存在安装问题。Discuz是一款广泛使用的开源社区论坛软件,utf-...

    discuz 7.2-UTF8(人人连接组件)

    7.2 版本是 Discuz! 发展历程中的一个重要里程碑,提供了更加完善的社区管理工具和用户体验。而 UTF8 编码的引入,则使得 Discuz! 能够支持更多语言,特别是中文环境,确保了多语言内容的正常显示。 人人连接组件则...

    discuz 7.2-GBK(人人连接组件)

    7.2-GBK是一款基于GBK编码的社区论坛系统,它由Discuz!官方推出,旨在为用户提供一个高效、稳定的在线交流平台。其中,人人连接组件是Discuz! 7.2的一个特色功能,它实现了Discuz! 论坛与人人网(原校内网)的无缝...

    DISCUZ7.2英文版

    1. **下载与解压**:首先从官方或可靠渠道下载DISCUZ7.2ENGLISHBYCOOBY.rar文件,解压缩后得到完整的程序包。 2. **服务器环境准备**:确保服务器运行PHP和MySQL,符合Discuz! 7.2的系统需求。 3. **安装向导**:...

    德国php空间安装dz7.2论坛方法

    ### 德国PHP空间安装Discuz! 7.2论坛详解 #### 一、前言 在当前互联网时代,建立论坛社区是很多个人站长或企业的首选。Discuz! 是一款非常受欢迎的开源社区软件,其丰富的功能和强大的扩展性使得它成为搭建论坛的...

    discuz7.2注入漏洞faq.php

    复现discuz7.2注入漏洞

    最新discuz模板discuz7.2用的

    7.2用的”指的是适用于Discuz! 7.2版本的一个新的界面设计,也就是我们常说的论坛皮肤或主题。这个模板采用了红色风格,可能旨在为用户带来更加醒目和热情的视觉体验。 首先,我们需要理解Discuz!模板的作用。模板...

    DIscuz7.2蓝色社区模板插件

    《DIscuz7.2蓝色社区模板插件详解及应用》 DIscuz7.2是一款备受推崇的社区论坛软件,其强大的功能和灵活的扩展性使得它在互联网上拥有广泛的用户基础。其中,蓝色社区模板插件是DIscuz7.2中的一款重要组件,它的...

    Discuz_7.2_UTF8环境.rar

    《Discuz!7.2 UTF8环境搭建与数据库结构解析》 Discuz!7.2是一款深受广大站长喜爱的开源论坛系统,它以其强大的社区功能和灵活的扩展性,在中文互联网环境中占据了重要的地位。该系统支持UTF8编码,能够处理各种...

    Discuz7.2 Water3风格

    Discuz7.2 Water3风格 1. 1、将附件下载后解压缩到当前文件夹,得到一个“water7.2”文件夹; 2. 2、将这个文件夹拷贝到你的论坛的“templates”目录下; 3. 3、登录到论坛后台,到“界面”→“风格管理”,在...

    Discuz_7.2 Ucenter整合

    《Discuz! 7.2与Ucenter整合详解》 Discuz! 7.2是一款由康盛创想(Comsenz)公司开发的社区论坛软件,它以其强大的功能和易用性深受广大站长喜爱。而Ucenter是康盛创想推出的一个统一用户管理平台,能够实现多个...

    PHP实例开发源码-php Xweibo for Discuz! 6.0-7.2 插件.zip

    PHP实例开发源码—php Xweibo for Discuz! 6.0-7.2 插件.zip PHP实例开发源码—php Xweibo for Discuz! 6.0-7.2 插件.zip PHP实例开发源码—php Xweibo for Discuz! 6.0-7.2 插件.zip

    discuz 7.2 utf8.zip

    4. 解压安装文件:将`discuz 7.2 utf8.zip`解压到Web服务器的根目录,确保所有文件都能被正确访问。 5. 初始化安装:通过浏览器访问论坛安装地址,按照页面提示进行数据库连接设置、管理员账号创建等步骤,完成初始...

    Discuz!7.2源码分析[郭鑫版]

    本篇文章将深入剖析《Discuz!7.2源码分析》中的关键代码片段及其背后的逻辑,帮助读者理解其内部机制。 #### 二、初始化设置 **1. 错误报告与安全设置** - `error_reporting(0);`:禁用所有的错误报告。 - `set...

    Discuz_7.2_FULL_SC_UTF8.zip

    《Discuz 7.2 完全安装指南》 Discuz!是一款广泛应用于互联网的社区论坛软件,以其强大的功能和易用性深受广大站长喜爱。本文将详细介绍如何使用"Discuz_7.2_FULL_SC_UTF8.zip"这个压缩包进行安装,让读者能够在...

    Discuz! 7.2

    《Discuz! 7.2:社区论坛运营的利器》 Discuz! 7.2是社区论坛软件的里程碑式版本,它在原有基础上进行了大量的更新和优化,旨在提升用户体验和社区管理效率。这一版本的核心目标是打造一个更加便捷、高效、个性化的...

    完全版-官方UCenter1.5 UCHome2.0 Discuz7.2集成安装包简体GBK.zip

    UCenter/UCenter Home/Discuz! 集成安装包 本集成包集成了以下Comsenz正式版产品: UCenter 1.5 (用户中心) UCenter Home 2.0 (个人空间) Discuz! 7.2 (论坛) 通过本集成安装包,您可以立即全新安装上述...

    Discuz!_7.2使用详细说明

    - **升级**:从旧版本升级到7.2,可以通过Discuz! 提供的在线升级工具进行,确保数据安全迁移并更新所有文件。 2. **界面与管理** - **后台管理**:Discuz! 7.2拥有强大的后台管理系统,包括会员管理、版块管理、...

    discuz7.2数据字典

    dz 7.2的数据字典。有了它还怕不懂dz吗?

Global site tag (gtag.js) - Google Analytics