现在注册赶紧抢单赚钱,刷单预约赚钱哦!
您需要 登录 才可以下载或查看,没有账号?立即注册
x
[color=#000][font="][size=3][table=98%]
[tr][td][table=98%]
[tr][td][color=#444444][font=Tahoma, "][size=12px]为了能让更多的人加入到编写插件的队伍中来,避免由于编写不规范而引起论坛安全问题.写了这么一个文档,希望对插件作者和对插件有浓厚兴趣的有多帮助。前面泡哥已经写过一个关于怎么写插件的帖子了([url]http://www.discuz.net/thread-315307-1-1.html[/url]),当时写的是Discuz4.x的,关于Discuz5一直没更新,我就补上我这篇.有什么建议欢迎大家讨论.
也不罗嗦了,马上就开始写插件吧,都说光看不练是不行的.这次我就拿怎么重新编写规范的<<斑竹申请>>这个插件来给大家讲解一下,写插件的流程.当然应该还是要感谢原作者的创意.
NO.1.
一个好的插件来源于好的想法和好的结构设计.一个程序的开发,50%的时间不是用在代码开发上,而在设计和分析上。插件也是,第一步当然是分析插件的功能需要用到什么,怎么实现,怎么设计了.这里原作者已经给帮我们想好了。我们就按他的思路来走一边吧.
在开始之前,我先简单的说一下变量的命名尽量使用能一目了然的英文意思,不要拼音,英文合用.
先找到与Discuz相关联的地方
申请斑竹的要求:
会员最多能申请次数: applycount int
注册时间不少于几天: lowestregdates int
最低要求积分数 : integral int
相关的积分扩展 : extcredit text
最低发贴数 : lowestposts int
和Discuz相关联的地方我们已经设计好了。这样就可以先去后台把相关的地方设置好了.
扩展设置->插件管理
http://image.edbiji.com/doccon/20150115/20150115164448_352769_847.jpg
添加以后,选右边的详情在进行设置.在设置之前,我们先来介绍一个标准的插件的文件和目录结构.这个在泡哥的帖子里已经说过一次了,我再重复一次吧.
D:\WWW\Discuz\plugins
└─ apply ------插件整体目录
├─images ------插件图片目录
│ └─img_apply
├─apply -------插件程序存放目录
└─templates -------插件模块存放目录
└─defaults
|------apply.lang.php -------语言包(这个是可选的)
|------apply.htm -------模版文件用htm结尾
|------adminapply.htm
|----apply.inc.php --------插件程序配置文件
|----discuz_plugin_apply.txt --------这个是生成的.
|----apply.sql --------数据库表文件
|-----readme.txt
http://image.edbiji.com/doccon/20150115/20150115164448_636271_847.jpg
http://image.edbiji.com/doccon/20150115/20150115164449_415618_847.jpg
http://image.edbiji.com/doccon/20150115/20150115164449_883897_847.jpg
http://image.edbiji.com/doccon/20150115/20150115164450_777923_847.jpg
NO.2设计数据库
这里我就不多复述了。给出我的表结构:
表名:cdb_plugin_apply
[color=Red]appid 申请ID
uid 用户ID
username 用户名
fid 版块ID
fname 版块名
suggest 申请建议
description 自我介绍
nettime 上网时间
dateline 申请时间
agreeapply 是否同意[/color]
前期的设计到这里就结束了.
NO.3 程序的开发--程序不但要考虑安全,效率,也要考虑代码的编写规范和美观.
Discuz调用插件的过程是先访问plugins/apply/apply.inc.php(这里的apply目录名是上面我们自己指定好的),所有的插件访问过程都是从apply.inc.php开始的.那我们的程序编写也从这个开始.[/size][/font][/color][color=rgb(102, 102, 102)][list=1]
[*]
[*][color=#444444][font=Tahoma, "]<?php[/font][/color]
[*][color=#444444][font=Tahoma, "]If(!defined('IN_DISCUZ')) {[/font][/color]
[*][color=#444444][font=Tahoma, "] Exit('Access Deined');[/font][/color]
[*][color=#444444][font=Tahoma, "]}[/font][/color]
[*]
[/list]
[color=#444444][font=Tahoma, "][size=12px]复制代码[/size][/font][/color][/color]
[color=#444444][font=Tahoma, "][size=12px][color=Red]建议:在每个插件程序的开头加上上面的代码.这是为了防止禁止直接外部访问文件[/color][/size][/font][/color][color=rgb(102, 102, 102)][list=1]
[*]
[*][color=#444444][font=Tahoma, "]@include_once DISCUZ_ROOT.'./forumdata/cache/plugin_apply.php';[/font][/color]
[*]
[/list]
[color=#444444][font=Tahoma, "][size=12px]复制代码[/size][/font][/color][/color]
[color=#444444][font=Tahoma, "][size=12px][color=Red]调用DISCUZ生成的插件参数的缓存文件.调用缓存文件以后,就可以调用里面的变量了.
Discuz生成的插件参数的配置文件是保存在一个二维的数组里的。$_DPLUGIN[‘apply’][‘vars’];[/color]
这里我们为了美观,对这个二维数组进行一下简化[/size][/font][/color][color=rgb(102, 102, 102)][list=1]
[*]
[*][color=#444444][font=Tahoma, "]$applycount = $_DPLUGIN['apply']['vars']['applycount'];[/font][/color]
[*][color=#444444][font=Tahoma, "]$lowestregdates = $_DPLUGIN['apply']['vars']['lowestregdates'];[/font][/color]
[*][color=#444444][font=Tahoma, "]$integral = $_DPLUGIN['apply']['vars']['integral'];[/font][/color]
[*][color=#444444][font=Tahoma, "]$extcredit = $_DPLUGIN['apply']['vars']['extcredit'];[/font][/color]
[*][color=#444444][font=Tahoma, "]$lowestposts = $_DPLUGIN['apply']['vars']['lowestposts'];[/font][/color]
[*]
[/list]
[color=#444444][font=Tahoma, "][size=12px]复制代码[/size][/font][/color][/color]
[color=#444444][font=Tahoma, "][size=12px]到这里插件的初始化就完成了.在继续我们的插件编写之前.我先介绍一下Discuz对变量是怎么处理,怎样才写出安全的插件.
大家可以先看一下Discuz的include/目录下的common.inc.php文件的第31行和global.func.php的111行.这个Discuz在进行数据处理之前,首先进行的初始化功能,[/size][/font][/color][color=rgb(102, 102, 102)][list=1]
[*]
[*][color=#444444][font=Tahoma, "]$magic_quotes_gpc = get_magic_quotes_gpc();[/font][/color]
[*][color=#444444][font=Tahoma, "]@extract(daddslashes($_COOKIE));[/font][/color]
[*][color=#444444][font=Tahoma, "]@extract(daddslashes($_POST));[/font][/color]
[*][color=#444444][font=Tahoma, "]@extract(daddslashes($_GET));[/font][/color]
[*][color=#444444][font=Tahoma, "]if(!$magic_quotes_gpc) {[/font][/color]
[*][color=#444444][font=Tahoma, "] $_FILES = daddslashes($_FILES);[/font][/color]
[*][color=#444444][font=Tahoma, "]}[/font][/color]
[*]
[*][color=#444444][font=Tahoma, "]function daddslashes($string, $force = 0) {[/font][/color]
[*][color=#444444][font=Tahoma, "] if(!$GLOBALS['magic_quotes_gpc'] || $force) {[/font][/color]
[*][color=#444444][font=Tahoma, "] if(is_array($string)) {[/font][/color]
[*][color=#444444][font=Tahoma, "] foreach($string as $key => $val) {[/font][/color]
[*][color=#444444][font=Tahoma, "] $string[$key] = daddslashes($val, $force);[/font][/color]
[*][color=#444444][font=Tahoma, "] }[/font][/color]
[*][color=#444444][font=Tahoma, "] } else {[/font][/color]
[*][color=#444444][font=Tahoma, "] $string = addslashes($string);[/font][/color]
[*][color=#444444][font=Tahoma, "] }[/font][/color]
[*][color=#444444][font=Tahoma, "] }[/font][/color]
[*][color=#444444][font=Tahoma, "] return $string;[/font][/color]
[*][color=#444444][font=Tahoma, "]}[/font][/color]
[*]
[/list]
[color=#444444][font=Tahoma, "][size=12px]复制代码[/size][/font][/color][/color]
[color=#444444][font=Tahoma, "][size=12px]这两段的代码功能就是在magic_quotes_gpc为off的情况,对$_GET,$_POST,$_COOKIE的值以及数组里面的每个值都进行转义,因为在magic_quotes_gpc为On时PHP本身自动会对这几个全局的变量进行转义,这些具体的内容介绍,可以看一下PHP相关的资料.
从这里可以看出Discuz本身已经对变量做了一个安全的处理.在编写插件时就应该尽量使用Discuz处理过的变量.
因为我们在开头使用了defined(‘IN_DISCUZ’)进行判断.现在所有想访问此文件的都必须从Discuz过来,也就会经过common.inc.php对变量进行处理.
[color=Red]这里需要强调的一点:
Discuz是对提交过来的变量的值进行了转义,我们可以认为他过来的值就是一个字符串,那么在使用他的时候,要尽量放在一个不会解析变量的单引号内.这样无论是安全还是效率都会有所提高.尤其是在SQL语句中.一定要把变量放在单引号呢。例如
$db->query("SELECT * FROM cdb_members WHERE uid='$discuz_uid'");[/color]
再说几个写插件时经常要用到的函数,其实有很多东西Discuz已经帮大家做好了,大家可以拿来就用.具体的使用可以查找Discuz的代码
常用的函数:
include template('apply') 调用模版 (模版名一定要以htm结束,如apply.htm)
include language('apply') 调用语言包 (语言包的命名上面已经说了,apply.lang.php)
showmessage 提示信息
例如:showmessage('not_loggedin','logging.php?action=login');
[color=Red]dhtmlspecialchars 对html标签进行转义
FORMHASH 生成表单唯一的标识
ispage() 判断页号是否是数字
multi() 分页函数
sendpm 发送短消息
forumselect()[/color]
数据库操作类
$db->query();
$db->result();
$db->fetch_array();
常用的常量:
$discuz_uid,$discuz_user,$adminid[/size][/font][/color][/td][/tr]
[/table]
[/td][/tr]
[/table]
[/size][/font][/color]
[color=#000][font="][size=3][table=98%]
[tr][td][table=98%]
[tr][td][color=#444444][font=Tahoma, "][size=12px]OK,现在可以进行核心代码的编写了.
先来判断是否已经登陆,如果你想允许游客也可以访问去掉这个就可以了。但一定要分清楚那些是必须要登陆才有权限操作的
'not_loggedin'这个是已经在discuz语言包里定义好的内容[/size][/font][/color][color=rgb(102, 102, 102)][list=1]
[*]
[*][color=#444444][font=Tahoma, "]if(!$discuz_uid) {[/font][/color]
[*][color=#444444][font=Tahoma, "] showmessage('not_loggedin','logging.php?action=login');[/font][/color]
[*][color=#444444][font=Tahoma, "]}[/font][/color]
[*]
[/list]
[color=#444444][font=Tahoma, "][size=12px]复制代码[/size][/font][/color][/color]
[color=rgb(102, 102, 102)][list=1]
[*]
[*][color=#444444][font=Tahoma, "]$applys = $apply = $applylist = '';[/font][/color]
[*]
[*][color=#444444][font=Tahoma, "]$page = !ispage($page) ? 1 : $page;[/font][/color]
[*][color=#444444][font=Tahoma, "]$start_limit = ($page - 1) * 10;[/font][/color]
[*]
[/list]
[color=#444444][font=Tahoma, "][size=12px]复制代码[/size][/font][/color][/color]
[color=#444444][font=Tahoma, "][size=12px]这是将要用到的变量的初始化和分页的处理,你可以搜索一下DZ处理分页的函数ispage(),multi(),他会生成一个分页的代码,
填上相应的参数以后就可以直接放在模块了使用了。
[color=Red]注意:记得对变量初始化,这是一个好的习惯,也可以避免安全问题。[/color]
下面是处理申请的流程。你可以先画个流程图,把一些情况先考虑清楚了。这样写程序会比较清晰,也不会容易犯错。[/size][/font][/color][color=rgb(102, 102, 102)][list=1]
[*]
[*][color=#444444][font=Tahoma, "]if($action == 'apply') { //申请斑竹[/font][/color]
[*][color=#444444][font=Tahoma, "] $query = $db->query("SELECT count(appid) FROM cdb_plugin_apply WHERE uid='$discuz_uid'"); //查看申请用户的申请次数[/font][/color]
[*][color=#444444][font=Tahoma, "] $applys = $db->result($query,0); //$db->result($query,0)可以用来取得一个记录值[/font][/color]
[*][color=#444444][font=Tahoma, "] if($applys >= $applycount) { //判断是否申请次数[/font][/color]
[*][color=#444444][font=Tahoma, "] showmessage('你已经到达了申请的最多次数,请耐心等待管理员的审核','plugin.php?identifier=apply&module=apply');[/font][/color]
[*][color=#444444][font=Tahoma, "] } else {[/font][/color]
[*][color=#444444][font=Tahoma, "] require_once DISCUZ_ROOT.'./include/forum.func.php'; //包含相关与论坛帖子相关的文件。这里因为下面的forumselect()函数需要用到[/font][/color]
[*][color=#444444][font=Tahoma, "] require_once DISCUZ_ROOT.'./forumdata/cache/cache_forums.php';[/font][/color]
[*][color=#444444][font=Tahoma, "] $forumselect = "<select name=\"fid\">\n<option value=\"\"> >请选择版块</option><option value=\"\"> </option>".str_replace('%', '%%', forumselect()).'</select>'; //这里是生成下拉采单式的版块选择,你可以看看DZ的操作方式[/font][/color]
[*][color=#444444][font=Tahoma, "] include_once DISCUZ_ROOT . './plugins/apply/apply/apply.php'; //到apply目录下用对应的程序来处理申请的过程[/font][/color]
[*][color=#444444][font=Tahoma, "] }[/font][/color]
[*][color=#444444][font=Tahoma, "]} elseif ($action == 'del') { //这里是删除用户申请的过程[/font][/color]
[*][color=#444444][font=Tahoma, "] if($discuz_uid == $uid || $admin == 1 && $formhash == FORMHASH) { //只有用户和管理员才有权限删除[/font][/color]
[*][color=#444444][font=Tahoma, "] $db->query("DELETE FROM cdb_plugin_apply WHERE uid='$discuz_uid' AND fid='$fid'");[/font][/color]
[*][color=#444444][font=Tahoma, "] showmessage('操作成功','plugin.php?identifier=apply&module=apply');[/font][/color]
[*][color=#444444][font=Tahoma, "] } else {[/font][/color]
[*][color=#444444][font=Tahoma, "] showmessage('禁止非法操作');[/font][/color]
[*][color=#444444][font=Tahoma, "] }[/font][/color]
[*][color=#444444][font=Tahoma, "]} else {[/font][/color]
[*][color=#444444][font=Tahoma, "] $query = $db->query("SELECT * FROM cdb_plugin_apply LIMIT $start_limit,10"); //取得记录,并格式化时间[/font][/color]
[*][color=#444444][font=Tahoma, "] while($apply = $db->fetch_array($query)) {[/font][/color]
[*][color=#444444][font=Tahoma, "] $apply['dateline'] = gmdate("$dateformat $timeformat", $apply['dateline'] + $timeoffset * 3600);[/font][/color]
[*][color=#444444][font=Tahoma, "] $applylist[] = $apply;[/font][/color]
[*][color=#444444][font=Tahoma, "] }[/font][/color]
[*][color=#444444][font=Tahoma, "] $query = $db->query("SELECT COUNT(*) FROM cdb_plugin_apply"); //分页显示[/font][/color]
[*][color=#444444][font=Tahoma, "] $applynum = $db->result($query,0);[/font][/color]
[*][color=#444444][font=Tahoma, "] $multipage = multi($applynum, 10, $page, "plugin.php?identifier=apply&module=apply");[/font][/color]
[*][color=#444444][font=Tahoma, "] include template('apply');[/font][/color]
[*][color=#444444][font=Tahoma, "]}[/font][/color]
[*]
[/list]
[color=#444444][font=Tahoma, "][size=12px]复制代码[/size][/font][/color][/color]
[color=#444444][font=Tahoma, "][size=12px]到这里apply.inc.php文件已经可以说是写完了。有什么问题,跟贴提问吧。[/size][/font][/color][/td][/tr]
[/table]
[/td][/tr]
[/table]
[/size][/font][/color]
[color=#000][font="][size=3][table=98%]
[tr][td][table=98%]
[tr][td][color=#444444][font=Tahoma, "][size=12px]上面当你访问插件的时候,初始化文件已经写完了
下面就是具体功能的实现了。[/size][/font][/color][color=rgb(102, 102, 102)][list=1]
[*]
[*][color=#444444][font=Tahoma, "]<?php[/font][/color]
[*][color=#444444][font=Tahoma, "]if(!defined('IN_DISCUZ')) {[/font][/color]
[*][color=#444444][font=Tahoma, "] exit('ACCESS Diened');[/font][/color]
[*][color=#444444][font=Tahoma, "]}[/font][/color]
[*]
[*][color=#444444][font=Tahoma, "]$total = $userinfo = '';[/font][/color]
[*]
[*][color=#444444][font=Tahoma, "]$query = $db->query("SELECT count(uid) FROM cdb_plugin_apply WHERE uid='$discuz_uid'");[/font][/color]
[*][color=#444444][font=Tahoma, "]$total = $db->result($query,0);[/font][/color]
[*]
[*][color=#444444][font=Tahoma, "]$query = $db->query("SELECT posts,$extcredit,regdate FROM {$tablepre}members WHERE uid='$discuz_uid'");[/font][/color]
[*][color=#444444][font=Tahoma, "]$userinfo = $db->fetch_array($query);[/font][/color]
[*][color=#444444][font=Tahoma, "]$userinfo['regdate'] = $timestamp - $userinfo['regdate'];[/font][/color]
[*][color=#444444][font=Tahoma, "]$userinfo['regdate'] = ceil($userinfo['regdate'] / (3600*24));[/font][/color]
[*]
[*][color=#444444][font=Tahoma, "]if(submitcheck('forumsubmit')) {[/font][/color]
[*][color=#444444][font=Tahoma, "] if($userinfo['regdate'] < $lowestregdates || $userinfo[$extcredit] < $integral || $userinfo['posts'] < $lowestposts) {[/font][/color]
[*][color=#444444][font=Tahoma, "] showmessage('请仔细查看申请斑竹的条件','plugin.php?identifier=apply&module=apply&action=apply');[/font][/color]
[*][color=#444444][font=Tahoma, "] }[/font][/color]
[*][color=#444444][font=Tahoma, "] [/font][/color]
[*][color=#444444][font=Tahoma, "] $query = $db->query("SELECT name FROM {$tablepre}forums WHERE fid='$fid'");[/font][/color]
[*][color=#444444][font=Tahoma, "] $fname = $db->result($query,0);[/font][/color]
[*][color=#444444][font=Tahoma, "] if(empty($fname)){[/font][/color]
[*][color=#444444][font=Tahoma, "] showmessage('请选择正确的版块','javascript:history.go(-1)');[/font][/color]
[*][color=#444444][font=Tahoma, "] } else {[/font][/color]
[*][color=#444444][font=Tahoma, "] $query = $db->query("SELECT COUNT(*) FROM cdb_plugin_apply WHERE uid='$discuz_uid' AND fid='$fid'");[/font][/color]
[*][color=#444444][font=Tahoma, "] if($db->result($query,0)) {[/font][/color]
[*][color=#444444][font=Tahoma, "] showmessage('请不要重复申请相同的版块','javascript:history.go(-1)');[/font][/color]
[*][color=#444444][font=Tahoma, "] }[/font][/color]
[*][color=#444444][font=Tahoma, "] }[/font][/color]
[*][color=#444444][font=Tahoma, "] [/font][/color]
[*][color=#444444][font=Tahoma, "] if(empty($nettime)) {[/font][/color]
[*][color=#444444][font=Tahoma, "] showmessage('上网时间不能为空','javascript:history.go(-1)');[/font][/color]
[*][color=#444444][font=Tahoma, "] } else {[/font][/color]
[*][color=#444444][font=Tahoma, "] $nettime = intval($nettime);[/font][/color]
[*][color=#444444][font=Tahoma, "] }[/font][/color]
[*][color=#444444][font=Tahoma, "] [/font][/color]
[*][color=#444444][font=Tahoma, "] if(!empty($description) && strlen($description) >= 16) {[/font][/color]
[*][color=#444444][font=Tahoma, "] $description = nl2br(dhtmlspecialchars($description));[/font][/color]
[*][color=#444444][font=Tahoma, "] } else {[/font][/color]
[*][color=#444444][font=Tahoma, "] showmessage('自我介绍不能为空,或者少与16个字','javascript:history.go(-1)');[/font][/color]
[*][color=#444444][font=Tahoma, "] }[/font][/color]
[*][color=#444444][font=Tahoma, "] [/font][/color]
[*][color=#444444][font=Tahoma, "] if(!(empty($suggest) && strlen($suggest) >= 16)) {[/font][/color]
[*][color=#444444][font=Tahoma, "] $suggest = nl2br(dhtmlspecialchars($suggest));[/font][/color]
[*][color=#444444][font=Tahoma, "] } else {[/font][/color]
[*][color=#444444][font=Tahoma, "] showmessage('建议不能为空,或者少于16个字','javascript:history.go(-1)');[/font][/color]
[*][color=#444444][font=Tahoma, "] }[/font][/color]
[*][color=#444444][font=Tahoma, "] [/font][/color]
[*][color=#444444][font=Tahoma, "] $db->query("INSERT INTO cdb_plugin_apply (`uid`,`username`,`fid`,`fname`,`suggest`,`description`,`nettime`,`dateline`,`agreeapply`) [/font][/color]
[*][color=#444444][font=Tahoma, "] VALUES ('$discuz_uid','$discuz_user','$fid','$fname','$suggest','$description','$nettime','$timestamp','$agreeapply')");[/font][/color]
[*][color=#444444][font=Tahoma, "] showmessage('请耐心等待管理的审核','plugin.php?identifier=apply&module=apply');[/font][/color]
[*][color=#444444][font=Tahoma, "]} [/font][/color]
[*]
[*][color=#444444][font=Tahoma, "]include template('apply');[/font][/color]
[*][color=#444444][font=Tahoma, "]?>[/font][/color]
[*]
[/list]
[color=#444444][font=Tahoma, "][size=12px]复制代码[/size][/font][/color][/color]
[color=#444444][font=Tahoma, "][size=12px]这次先不加注释,大家先自己看看,看看常用的函数会不会使用了。哪里不懂的。提问,我会及时回复的。[/size][/font][/color][/td][/tr]
[/table]
[/td][/tr]
[/table]
[/size][/font][/color]
|