大约半年多没碰康盛的东西了,年前在DZ7.2开发了几个插件,我们这边的开发任务就停止了,现在又有项目需要做dzx2.5的开发,于是开始搞特殊主题。
尼玛我参照开发手册(http://dev.discuz.org/wiki/)写的开始开发,结果就是在论坛的设置处可以看到自定义的特殊主题,发帖的时候却没有这个选项。蛋疼。断断续续折腾了两天,蛋疼,直接翻DZ相关源码,终于找到问题所在:尼玛。。。弄个特殊主题光在论坛设置里面设置还不够,还特么要在用户组给用户使用这个特殊主题的权限。。。
0x01这特么是怎么个情况?
断断续续两天时间,太纠结了。找了个不靠谱的人问了问,毛也没给解决,这些事还是得自力更生。反复测试了很久也没找到问题,索性直接翻DZ相关源码。 入口看URL:
http://dzx/forum.php?mod=post&action=newthread&specialextra=dabing&fid=2&cedit=yes&extra=
,这里以随便找了个安装了特殊主题的插件为例。
首先看forum.php,最后一句required了mod,如下
require DISCUZ_ROOT.'./source/module/forum/forum_'.$mod.'.php';
mod=post,于是找source/module/forum/forum_post.php。
连个注释也没有,这特么蛋疼,在看action=newthread,直接搜newthread。
在347行找到了newthread的具体处理流程。首先加载缓存处理数据什么的,然后用了libfile函数。
/** * * @param string $libname lib的名字,依靠是否有/来判断引用路径 * @param string $folder 指定引用的二级目录,默认没有 * @return Ambigous <boolean, string> 如果路径正确则返回包含文件位置,否则返回false */ function libfile($libname, $folder = '') { $libpath = '/source/'.$folder; //处理引用的位置 if(strstr($libname, '/')) { list($pre, $name) = explode('/', $libname); $path = "{$libpath}/{$pre}/{$pre}_{$name}"; } else { $path = "{$libpath}/{$libname}"; } //判断是否是合法引用 return preg_match('/^[\w\d\/_]+$/i', $path) ? realpath(DISCUZ_ROOT.$path.'.php') : false; }
根据提交的参数libfile('post/newthread', 'include');,打开source/include/post/post_newthread.php。
.... //从第84行开始 } elseif($specialextra) { //开始调用特殊主题 $threadpluginclass = null; if(isset($_G['setting']['threadplugins'][$specialextra]['module'])) { //module是特殊主题的类名,就是在模块-特殊主题-名字的地方填写的,这里是preview $threadpluginfile = DISCUZ_ROOT.'./source/plugin/'.$_G['setting']['threadplugins'][$specialextra]['module'].'.class.php'; //可以直接echo出来看看:F:\PHP_Work\DZX\./source/plugin/dabing/preview.class.php echo DISCUZ_ROOT.'./source/plugin/'.$_G['setting']['threadplugins'][$specialextra]['module'].'.class.php'; //开始引用 if(file_exists($threadpluginfile)) { @include_once $threadpluginfile; $classname = 'threadplugin_'.$specialextra;//$specialextra这个?应该返回去搜索了。这里是插件的ID //在文件存在,类存在,方法存在的情况下,就开始调用该类的newthread方法了。 if(class_exists($classname) && method_exists($threadpluginclass = new $classname, 'newthread')) { $threadplughtml = $threadpluginclass->newthread($_G['fid']); $buttontext = lang('plugin/'.$specialextra, $threadpluginclass->buttontext); $iconfile = $threadpluginclass->iconfile; $iconsflip = array_flip($_G['cache']['icons']); $thread['iconid'] = $iconsflip[$iconfile]; } } }
顿时觉得特殊主题的逻辑和实现其实超级简单,呵呵。
然后切换成我们的主题,发现就是不显示,哪怕你手动指定了specialextra也会跳转到发表普通帖子的页面。
于是回到forum_post.php,肯定对specialextra参数进行了处理。
在第236行让我吃了一惊,亲,听说过圈复杂度么。。。。莫不是发行版本是经过压缩优化过的?尼玛啊。。。
if($specialextra && $_G['group']['allowpost'] && $_G['setting']['threadplugins'] && (!array_key_exists($specialextra, $_G['setting']['threadplugins']) || !@in_array($specialextra, is_array($_G['forum']['threadplugin']) ? $_G['forum']['threadplugin'] : dunserialize($_G['forum']['threadplugin'])) || !@in_array($specialextra, $_G['group']['allowthreadplugin']))) { $specialextra = ''; }
$specialextra:dabing,非空值,true。
$_G['group']['allowpost']:1,看名字应该是组权限允许发帖),true。
$_G['setting']['threadplugins']:Array,非空,打印出来是所有的特殊主题的数组,表明存在特殊主题,true。
!array_key_exists($specialextra, $_G['setting']['threadplugins']):判断URL输入的特殊主题ID是否真的存在,存在取反,为false。
三目运算符:is_array($_G['forum']['threadplugin']) ? $_G['forum']['threadplugin'] : dunserialize($_G['forum']['threadplugin'])) :判断该论坛的允许使用的特殊主题列表的保存形式,如果是数组则不变,如果是序列化果断反序列化之,返回数组。这里本来就是数组,无所谓。
!@in_array($specialextra, $_G['forum']['threadplugin']):这个特殊主题是否在这个论坛中允许使用,这个在论坛的帖子相关设置过,存在取反为false。
!@in_array($specialextra, $_G['group']['allowthreadplugin']):问题出现了,尼玛这个 $_G['group']['allowthreadplugin']没有刚才自己写的插件的ID,看名字应该是组允许使用的特殊主题列表,这里是false,取反为true。
则以上为
if(true && true && true && (false || false || true)) { $specialextra = ''; }
最终为true,于是$specialextra被赋空值了。
根据名字猜测是用户组/管理组权限问题,马上翻后台去看看,果然有这个选项。。。蛋疼。。。看来做DZ二次开发,要同时配备开发手册和使用手册。。。
到此为止找到原因,突然觉得特殊主题的逻辑好简单:)是否可以山寨一个呢亲?
呵呵,问题很好解决,关键是又复习了~
0x02DZ特殊主题简单开发教程
首先开启开发者模式,在 config_global.php 后边填一行$_config['plugindeveloper'] = 1;值为1表示开启开发者模式,为2则表示同时开启潜入点提示。写上之后再应用的地方就能看到设计新插件的链接了。
特殊主题后边有个向下的箭头,点击就可以下载模板,其实可以自己写,写法在手册上。然后返回之前的应用界面,把新插件启用。
然后在source/plugin下建立dabing目录,然后建立preview.class.php,名字都是上边设置好的,根据自己设置的填写。 然后在preview.class.php写入如下代码:
<?php class threadplugin_dabing { var $name = '测试主题'; //主题类型名称 var $iconfile = 'icon.gif'; //发布主题链接中的前缀图标 var $buttontext = '发布测试主题'; //发帖时按钮文字 function newthread($fid) { return "newthread"; } function newthread_submit($fid) { } function newthread_submit_end($fid, $tid) { } function editpost($fid, $tid) { return "editpost"; } function editpost_submit($fid, $tid) { } function editpost_submit_end($fid, $tid) { } function newreply_submit_end($fid, $tid) { } function viewthread($tid) { return "viewthread"; } }
注意类名,必须是"threadplugin_"加上你的插件的ID名字,这里是dabing。上边的方法名看名字就能猜个七七八八,具体干啥的看手册(http://dev.discuz.org/wiki/index.php?title=%E7%89%B9%E6%AE%8A%E4%B8%BB%E9%A2%98%E6%A8%A1%E5%9D%97%E5%BC%80%E5%8F%91)。
然后到工具菜单清理下缓存,再到论坛设置里面,选择帖子设置,就能看到我们的“测试主题”了。
勾选测试主题,OK,这个版块就可以发布测试主题了。赶紧去前台看看。
(图片丢失。。。)
结果在发帖的时候却特么看不到特殊主题,坑爹了,就这个问题,我特么折腾了两天。
OK,其实还没设置完,来到用户组和管理员组(管理组是基本权限那个设置链接),打开论坛相关的特殊主题,勾选刚才的“测试主题”,赶紧到前台刷新看看,尼玛终于出来了。。。蛋疼
(图片丢失。。。)
当年在学校图书馆看到本DZ7.2论坛使用的书,直接震惊了,现在发现玩好DZ确实需要多熟悉一下这个玩意。。。很奇怪这个问题在网上搜不到,难道只有我遇到了么。。。囧
留言交流