Don 发布的文章

Discuz! 版主已阅插件更新

版主已阅插件为本人接触Discuz!来的第一款插件,地址见http://addon.discuz.com/?@dst_read.plugin.

V2.0版本更新内容(2014/07/21):

1. 代码完全重写,优化插件的数据库查询。
2. 增加自定义已阅文字功能。
3. 增加自定义已阅文字颜色功能。
4. 记录已阅用户,已阅楼层显示标记已阅的用户名,以便后续查阅。
5. 增加跳转页面,解决已阅楼层被删除后无法跳转到已阅楼层的问题。

现在看早期写的代码简直不忍直视,一个页面十几次数据库查询...
好吧,新版全部重写了,快来更新吧~

Discuz! 应用开发中遇到的两个坑

坑一:common()方法并不是所有类都会执行的。

这是Discuz!插件开发文档里的描述:

common() 所有模块执行前被调用 全局嵌入点类

代码如下:

class plugin_test {
    
    function common() {
        echo 123;
    }
}

class plugin_test_forum extends plugin_test {
    
    function viewthread_top_output() {
        echo 234;
    }
}

访问论坛页面,并不会触发到父类plugin_test的common方法执行。

坑二:系统函数updatetable()存在bug。

先看函数定义(代码较多,中间部分省略只做注释):

if(!$query = DB::query("SHOW CREATE TABLE ".DB::table($newtable), 'SILENT')) {
    // 创建表逻辑
} else {
    $value = DB::fetch($query);
    $oldcols = updatetable_getcolumn($value['Create Table']);

    $updates = array();
    $allfileds =array_keys($newcols);
    foreach ($newcols as $key => $value) {
        if($key == 'PRIMARY') {
            // 添加主键
        } elseif ($key == 'KEY') {
            // 添加索引
        } elseif ($key == 'UNIQUE') {
            // 添加索引
        } else {
            // 添加字段
        }
    }

    if(!empty($updates)) {
        $usql = "ALTER TABLE ".DB::table($newtable)." ".implode(', ', $updates);
        if(!DB::query($usql, 'SILENT')) {
            return array(-1, $newtable);
        }
    }
}

通过代码能够看出,这个方法是可以根据表中的结构决定是否需要添加字段。
由于本人需要往post表添加字段,所以需要判断是否已有字段才进行添加。
实际使用中发现,永远不会执行到添加字段的逻辑,if(!$query = DB::query("SHOW CREATE TABLE ".DB::table($newtable), 'SILENT'))这个判断永远成立。

问题的根源在install的sql本身,代码如下:

CREATE TABLE IF NOT EXISTS `pre_forum_post` (
`extstring` varchar(15) NOT NULL,
) ENGINE=MyISAM;

注意上面这里的这个匹配

preg_match_all("/CREATE\s+TABLE.+?pre\_(.+?)\s*\((.+?)\)\s*(ENGINE|TYPE)\s*=\s*(\w+)/is", $sql, $matches);
$newtables = empty($matches[1])?array():$matches[1];

会导致newtables = forum_post`,执行的结果当然是false。
所以sql里不要写`,这里算是考虑不严的一个bug吧。

遇到106575585266的诈骗短信

今天上午收到一条106575585266的短信,提示我有一个顺风速运的快件。

Alt 诈骗短信

查了下快递号,确实有这么个快递,但是显示为已签收。

Alt 快递信息

感觉很是奇怪,我没买东西呀。难道是自己的资料泄漏了?

搜索了一下,发现这个号码顺风早已经就停用了。

温馨提示:为便于您识记,2011年12月20日起,我司短信查单接收号码由原106575585266变更为106980001111,请您惠存新号码。
http://www.sf-express.com/cn/sc/dynamic_functions/waybill/cms_search.html

另附上网上关于这个电话的评论:

Alt 网上的评论
评论来自于:http://www.soudianhua.com/Phone.aspx?number=106575585266

开启了OAuth2.0的Discuz站点不能同步到微博的问题排查

今天排查了一例Discuz站点不能同步到微博的问题,问题表现如下:

  1. 发帖勾选同步到微博,同步失败
  2. 在详情页点击分享到微博,同步成功

分享到微博使用的是一套接口,怎么会出现这种情况呢?

发帖自动同步代码:

$response = $connectOAuthClient->$method($_G['member']['conopenid'], $_G['member']['conuin'], $_G['member']['conuinsecret'], $t_params);

点击分享,同步到微博代码:

if(!$_G['setting']['connect']['oauth2'] || !$_G['member']['conuintoken']) {
    try {
        $response = $connectOAuthClient->$method($_G['member']['conopenid'], $_G['member']['conuin'], $_G['member']['conuinsecret'], $t_params);
    } catch(Exception $e) {
        $errorCode = $e->getCode();
    }
} else {
    try {
        $method = $method.'_V2';
        $response = $connectOAuthClient->$method($_G['member']['conopenid'], $_G['member']['conuintoken'], $t_params);
    } catch(Exception $e) {
        $errorCode = $e->getCode();
    }
}

一目了然了吧,发帖自动同步的代码没有做OAuth2.0的兼容,使用的还是OAuth1.0的分享接口,但是会失败了。
把上面的代码替换成下面的,同步成功。
回帖自动同步的问题同理。

PHP运算符优先级

if ($sId && $sId != $sId2) {
    ... do something
}

昨天Code Review时,提到这个表达式哪个先执行的问题,今天特意查了下手册。
按PHP手册上的优先级定义,!= 的优先级要大于 &&。

所以上面的代码其实应该是这样:

if ($sId && ($sId != $sId2)) {
    ... do something
}

不建议使用上面第一种写法,容易产生困惑,直接使用下面这个逻辑清晰一些。