Bug重现:
任意勾选一个未被屏蔽的帖子,点击 管理-屏蔽 ,然后选择“解除”并确定,会发现这个帖子被屏蔽了。也就是说,对未被屏蔽的帖子无论进行“屏蔽”还是“解除”屏蔽,结果都一样——该帖被屏蔽。
对正常状态的帖子解除屏蔽明显是误操作,系统不应该进行相反的屏蔽处理。
问题严重吗?何时会出现这个问题?
如果你对某个主题下的多个回帖进行批量解除屏蔽,但误勾选了其中并未被屏蔽的某个回帖,这个回帖会被错误屏蔽。此误操作极少可能出现,也不会造成严重后果,大家可以考虑是否修复。
错误原因和解决方法:
首先我们要了解,帖子状态记录于 pre_forum_post 表中的 status 字段中,这个字段存储的是 位运算(二进制转十进制) 后的结果。
二进制 0000 0001 帖子被屏蔽
二进制 0000 0010 帖子被警告
二进制 0000 0100 帖子审核后再编辑标记,用于防止重复加分
二进制 0000 1000 手机版发帖标示
例(为方便和上文比对理解,下文中的二进制数字前面同样用0补位了):
如果一个回帖通过手机发布,那么这个帖子的状态应该是 0000 1000 ,status 字段中记录的是其对应的十进制数 8 。
接下来如果这个帖子被屏蔽,那么应该用 0000 0001 加上原来的状态 0000 1000 ,得到新的状态 0000 1001 (十进制 9)。
怎样实现这个增加状态的操作呢?大概了解一下“位运算”:
接下来说出错的原因了。
1、首先打开 source/include/topicadmin/topicadmin_banpost.php 文件,查找:
C::t('forum_post')->increase_status_by_pid('tid:'.$_G['tid'], $post['pid'], 1, '^', true);
我们可以看到解除屏蔽时使用的位运算符是 ^ (作用:将原状态和新状态中一个为 1 另一个为 0 的位设为 1),这个运算符有什么问题呢?
当帖子未被屏蔽时,假设其当前状态为 8 (二进制 0000 1000),要“去掉”状态 1 (0000 0001),我们看看使用“^”得到什么结果:
8^1=9 (0000 1001)
问题出现了,0000 1001 的状态含义是通过手机发布、被屏蔽!而正常结果应该是保持原有状态 8 (0000 1000)。
我们可以用以下方法得到正常结果:
原状态:
0000 1000 (8)
去掉状态:
0000 0001 (1)
使用 ~ 运算符将要去掉的状态取反:
1111 1110
最后用 & 运算符将两个值中都为1的保持为1,其它为0:
0000 1000 (8)
8&~1=8
是否会影响正常操作?验证:
原状态:
0000 1001 (9)
去掉状态:
0000 0001 (1)
使用 ~ 运算符将要去掉的状态取反:
1111 1110
最后用 & 运算符将两个值中都为1的保持为1,其它为0:
0000 1000 (8)
9&~1=8
成功去掉了屏蔽状态!
因此,我们将代码中的 ^ 运算符替换为 &~ :
C::t('forum_post')->increase_status_by_pid('tid:'.$_G['tid'], $post['pid'], 1, '&~', true);
2、替换后发现无论屏蔽还是解除屏蔽都没反应了,检查 increase_status_by_pid 函数(位于 source/class/table/table_forum_post.php ):
public function increase_status_by_pid($tableid, $pid, $status, $glue, $unbuffered = false) { $return = DB::query('UPDATE %t SET %i WHERE %i', array(self::get_tablename($tableid), DB::field('status', $status, $glue), DB::field('pid', $pid)), $unbuffered); if($return && $this->_allowmem) { $this->update_cache($tableid, $pid, 'pid', array('status' => $status), array(), $glue); } return $return; }
其中运算符 $glue 通过 DB::field 静态类进行了某些处理,检查 DB::field 所在的文件 source/class/discuz/discuz_database.php ,查找:
case '^':
在其下方插入一行:
case '&~':
若您喜欢这篇文章,欢迎订阅老张小站以获得最新内容。 / 欢迎交流探讨,请发电子邮件至 mail[at]vdazhang.com 。
欢迎谈谈你的看法(无须登录) *正文中请勿包含"http://"否则将被拦截