免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 2275 | 回复: 1
打印 上一主题 下一主题

Discuz 7.2坑爹集锦-PHP篇 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2012-01-13 10:47 |只看该作者 |倒序浏览
Discuz 7.2坑爹集锦-PHP篇





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插入数据时代码有问题。


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

类型:        代码风格
坑爹指数:    ☆
代码:
  1. include/global.func.php ~400
复制代码
Php代码
  1. function forumperm($permstr) {   
  2.     global $groupid, $extgroupids;   
  3.   
  4.     $groupidarray = array($groupid);   
  5.     foreach(explode("\t", $extgroupids) as $extgroupid) {   
  6.         if($extgroupid = intval(trim($extgroupid))) {    <------------赋值还是判断? 太容易混淆人了   
  7.             $groupidarray[] = $extgroupid;   
  8.         }   
  9.     }   
  10. }  

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

  13.     $groupidarray = array($groupid);
  14.     foreach(explode("\t", $extgroupids) as $extgroupid) {
  15.         if($extgroupid = intval(trim($extgroupid))) {    <------------赋值还是判断? 太容易混淆人了
  16.             $groupidarray[] = $extgroupid;
  17.         }
  18.     }
  19. }  
复制代码
点评:    赋值还是判断? 太容易混淆人了
FIX:

Php代码
  1. foreach(explode("\t", $extgroupids) as $extgroupid) {   
  2.     $extgroupid = intval($extgroupid);   
  3.     $extgroupid > 0 && $groupidarray[] = $extgroupid;   
  4. }  

  5.     foreach(explode("\t", $extgroupids) as $extgroupid) {
  6.         $extgroupid = intval($extgroupid);
  7.         $extgroupid > 0 && $groupidarray[] = $extgroupid;
  8.     }  
复制代码
-------------------------------------------------------------------------------------------------------------------------

类型:        变量类型
坑爹指数:    ★
代码:
  1. include/newreply.inc.php 240
复制代码
Php代码
  1. $parseurloff = !emptyempty($parseurloff);  

  2.     $parseurloff = !empty($parseurloff);  
  3. include/newthreads.inc.php~375
复制代码
Php代码
  1. $parseurloff = !emptyempty($parseurloff);  

  2.     $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模板文件居多。

Php代码
  1. Undefined index: allowadminlog   
  2. ----   
  3. Modified : ucs/view/default/admin_admin.htm   
  4. Modified : ucs/view/default/admin_feed.htm   
  5. Modified : ucs/view/default/admin_mail.htm   
  6. Modified : ucs/view/default/admin_note.htm   
  7.                                 <li><input type="checkbox" name="allowadminlog" value="1" class="checkbox" {if $admin[allowadminlog]} checked="checked" {/if}/>{lang admin_allow_log}</li>  

  8. Undefined index: allowadminlog
  9. ----
  10. Modified : ucs/view/default/admin_admin.htm
  11. Modified : ucs/view/default/admin_feed.htm
  12. Modified : ucs/view/default/admin_mail.htm
  13. Modified : ucs/view/default/admin_note.htm
  14.                                 <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()判断变量,比如

Php代码
  1. {if isset($admin[allowadminlog]) && $admin[allowadminlog]} 或者 {if !emptyempty($admin[allowadminlog])}  

  2. {if isset($admin[allowadminlog]) && $admin[allowadminlog]} 或者 {if !empty($admin[allowadminlog])}  
复制代码
-------------------------------------------------------------------------------------------------------------------------

类型:        未定义变量
坑爹指数:    ★★
代码:        pm.php=47

Php代码
  1. $pmstatus = uc_pm_checknew($discuz_uid, 4);   
  2. $filter = !emptyempty($filter) && in_array($filter, array('newpm', 'privatepm', 'announcepm')) ? $filter : ($pmstatus['newpm'] ? 'newpm' : 'privatepm');  

  3.     $pmstatus = uc_pm_checknew($discuz_uid, 4);
  4.     $filter = !empty($filter) && in_array($filter, array('newpm', 'privatepm', 'announcepm')) ? $filter : ($pmstatus['newpm'] ? 'newpm' : 'privatepm');  
复制代码
点评:         未对返回值$pmstatus['newpm']有效性进行判断

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


类型:        未定义变量
坑爹指数:    ★★
代码:        pm.php=61

Php代码
  1. foreach($ucdata['data'] as $pm) {   
  2. ....   
  3. }   

  4.     foreach($ucdata['data'] as $pm) {
  5.     ....
  6.     }   
复制代码
点评:        未对 $ucdata变量'data'键有效做判断就直接开始循环,相当于对一个可能不存在的变量进行访问并迭代。问题出在line49调用uc_pm_list()对$ucdata赋值,而ucc/control/pm.php: onls() 函数返回值$result未初始化'data'键名。
虽然PHP是若类型,但好歹对函数返回值先做个判断再操作吧。偷懒也就少些几行代码,可调试维护时花的时间就多了。

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


类型:        变量错误
坑爹指数:    ★★
代码:        memcp.php line264.

Php代码
  1. $styleid = emptyempty($styleidnew) ? $styleid : $styleidnew;  

  2.             $styleid = empty($styleidnew) ? $styleid : $styleidnew;
复制代码
点评:    这位兄弟是不是求加薪不成功,没有新生活导致见new就失望于是也不给变量new生活。
FIX:

Php代码
  1. $styleidnew = emptyempty($styleidnew) ? $styleid : $styleidnew;  

  2. $styleidnew = empty($styleidnew) ? $styleid : $styleidnew;  
复制代码
-------------------------------------------------------------------------------------------------------------------------

类型:        变量使用
坑爹指数:    ★★
代码:        include/global.func.php 1514

Php代码
  1. updateprompt()函数中$db->query("UPDATE {$tablepre}members SET prompt=prompt^1 WHERE uid='$discuz_uid' AND prompt=prompt|1", 'UNBUFFERED');  

  2. 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:

Php代码
  1. $db->query("INSERT INTO {$tablepre}medallog (uid, medalid, type, dateline, expiration, status) VALUES ('$uid', '".$modmedal[medalid]."', '0', '$timestamp', '".$modmedal['expiration']."', '$medalstatus')");  

  2.     $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

Php代码
  1. $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'");  

  2.         $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

Php代码
  1. $db->query("UPDATE {$tablepre}members set uid=uid $updatesql WHERE $conditions", 'UNBUFFTERED');  

  2.     $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

Php代码
  1. $db->query("UPDATE {$tablepre}threads SET .... rate='".intval(@($fpost['rate'] / abs($fpost['rate'])))."', moderated='1' WHERE tid='$newtid'");  

  2. $db->query("UPDATE {$tablepre}threads SET .... rate='".intval(@($fpost['rate'] / abs($fpost['rate'])))."', moderated='1' WHERE tid='$newtid'");  
复制代码
代码:
  1. topicadmin.php~240
复制代码
Php代码
  1. @$firstpost['rate'] = $firstpost['rate'] / abs($firstpost['rate']);  

  2. @$firstpost['rate'] = $firstpost['rate'] / abs($firstpost['rate']);
复制代码
代码:
  1. space.php=95
复制代码
Php代码
  1. @$percent = round($member['posts'] * 100 / $db->result_first("SELECT COUNT(*) FROM {$tablepre}posts"), 2);  

  2. @$percent = round($member['posts'] * 100 / $db->result_first("SELECT COUNT(*) FROM {$tablepre}posts"), 2);  
复制代码
代码:
  1. stats.php~260
复制代码
Php代码
  1. $pageviewavg = sprintf ("%01.2f", ($stats_total['visitors'] ? $stats_total['hits'] / $stats_total['visitors'] : 0));   
  2. !$post && $post = 1;   
  3. $activeindex = round(($membersaddavg / $members + $postsaddavg / $posts) * 1500 + $threadreplyavg * 10 + $mempostavg * 1 + $mempostpercent / 10 + $pageviewavg);  

  4.     $pageviewavg = sprintf ("%01.2f", ($stats_total['visitors'] ? $stats_total['hits'] / $stats_total['visitors'] : 0));
  5.     !$post && $post = 1;
  6.     $activeindex = round(($membersaddavg / $members + $postsaddavg / $posts) * 1500 + $threadreplyavg * 10 + $mempostavg * 1 + $mempostpercent / 10 + $pageviewavg);
复制代码
代码:
  1. stats.php 多处
复制代码
Php代码
  1. $avgmodactioncount = @($totalmodactioncount / count($members));   
  2. @$width = intval(370 * $count / $max);   
  3. @$percent = sprintf ("%01.1f", 100 * $count / $sum);   
  4. $membersaddavg = round($members / $runtime);   

  5.     $avgmodactioncount = @($totalmodactioncount / count($members));
  6.     @$width = intval(370 * $count / $max);
  7.     @$percent = sprintf ("%01.1f", 100 * $count / $sum);
  8.     $membersaddavg = round($members / $runtime);
复制代码
代码:
  1.    admin/forums.inc.php~640
复制代码
Php代码
  1. $forum['autoclose'] = $forum['autoclose'] / abs($forum['autoclose']);  

  2.     $forum['autoclose'] = $forum['autoclose'] / abs($forum['autoclose']);  
复制代码
代码:        stats.php~550

Php代码
  1. foreach($extendedcredit as $i => $members) {   
  2.             @$width = intval(370 * $members['credits'] / $max);   
  3.             $width += 2;  

  4.     foreach($extendedcredit as $i => $members) {
  5.                 @$width = intval(370 * $members['credits'] / $max);
  6.                 $width += 2;
复制代码
代码:        stats.php~750:

Php代码
  1. 'avgoffdays' => @($totaloffdays / count($members)),   
  2. 'avgthismonthposts' => @($totalthismonthposts / count($members)),   
  3. 'avgtotalol' => @($totalol / count($members)),   
  4. 'avgthismonthol' => @($totalthismonthol / count($members)),   
  5. 'avgmodactions' => @($totalmodactions / count($members)),   
  6.         'avgthismonthposts' => @($totalthismonthposts / count($members)),   
  7.         'avgtotalol' => @($totalol / count($members)),   
  8.         'avgthismonthol' => @($totalthismonthol / count($members)),   
  9.         'avgmodactions' => @($totalmodactions / count($members)),  

  10.         'avgoffdays' => @($totaloffdays / count($members)),
  11.         'avgthismonthposts' => @($totalthismonthposts / count($members)),
  12.         'avgtotalol' => @($totalol / count($members)),
  13.         'avgthismonthol' => @($totalthismonthol / count($members)),
  14.         'avgmodactions' => @($totalmodactions / count($members)),
  15.                 'avgthismonthposts' => @($totalthismonthposts / count($members)),
  16.                 'avgtotalol' => @($totalol / count($members)),
  17.                 'avgthismonthol' => @($totalthismonthol / count($members)),
  18.                 'avgmodactions' => @($totalmodactions / count($members)),  
复制代码
代码:    misc.php~720

Php代码
  1. $threadrate = @intval(@($post['rate'] + $rate) / abs($post['rate'] + $rate));  

  2.         $threadrate = @intval(@($post['rate'] + $rate) / abs($post['rate'] + $rate));  
复制代码
点评:    避免除零错误是学习编程时的基本概念,没想到在DZ中还能挖出这么多来。某些问题除零错误是在建站初始无对应数据时发生,待正常运作之后就不会发生。而多数将伴随你网站终身,不断充实你的error-log文件~ 如果说某位程序大猿数学不好不知道除零错误还可以理解,但恶劣的是有些人明知道这个问题却使用@来抑制错误,这就属于有意找抽的……


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


类型:        字段名错误
坑爹指数:    ★★★
代码:        include/global.func.php 1622-1623

Php代码
  1. //$sql = "SELECT * FROM {$tablepre}feeds WHERE $where ORDER BY feed_id DESC LIMIT $start_limit, $conf[num]"; // DZ自己注释掉的   
  2. $sql = "SELECT * FROM {$tablepre}feeds WHERE $where ORDER BY feedid DESC LIMIT $start_limit, $conf[num]";  

  3. //$sql = "SELECT * FROM {$tablepre}feeds WHERE $where ORDER BY feed_id DESC LIMIT $start_limit, $conf[num]"; // DZ自己注释掉的
  4. $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

Php代码
  1. if($db->result_first("SELECT COUNT(*) FROM {$tablepre}favoritethreads WHERE tid='$tid' AND uid='$discuz_uid'")) {   
  2. showmessage('favoritethreads_exists', dreferer());   
  3. }   
  4. $timestamp = time();   
  5. $attention_exists = $db->result_first("SELECT COUNT(*) FROM {$tablepre}favoritethreads WHERE tid='$tid' AND uid='$discuz_uid'");  // <===   

  6. if($db->result_first("SELECT COUNT(*) FROM {$tablepre}favoritethreads WHERE tid='$tid' AND uid='$discuz_uid'")) {
  7. showmessage('favoritethreads_exists', dreferer());
  8. }
  9. $timestamp = time();
  10. $attention_exists = $db->result_first("SELECT COUNT(*) FROM {$tablepre}favoritethreads WHERE tid='$tid' AND uid='$discuz_uid'");  // <===   
复制代码
点评:        前面查询如果存在结果(即有收藏)就已经退出执行流程并提示用户 'favoritethreads_exists',下面干嘛又执行一次呢,难道真会再次运行?

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


论坛徽章:
0
2 [报告]
发表于 2012-01-13 10:48 |只看该作者
谢谢分享
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP