一、开发插件所需资料与工具 1、DiscuzX3 插件机制 插件机制Discuz! 拥有一套完整的插件机制。 合理使用插件机制,你可以更好的将自己的个性功能需求整合到Discuz!产品中的同时,保持代码独立,并且不受后续Discuz!产品版本升级的影响。 我们鼓励并推荐,使用插件机制进行个性需求定制和研发。 插件设计的准备工作 插件实现流程 开始编写社区插件,您应当首先对插件实现的流程有一个大致的了解,以下是我们推荐的插件编写流程: ∙ 熟练使用 Discuz! 社区系统后,对希望完善或补充的个性化功能进行评估,进而提出插件的功能需求。 ∙对插件做一个概括性的设计,例如:需要使用什么菜单、什么参数,配置哪些选项、数据结构如何设计、前后台实现哪些功能等等。 ∙阅读本文档并在系统设置中实际体验 Discuz! 插件接口所实现的功用,例如:您的插件应当如何设计才能良好的挂接到社区系统中来。插件接口能够实现哪些功能、不能实现哪些功能,插件为此而需要做的优化、改造和取舍。 ∙编写相应程序代码和模板语句,实现所需的功能并进行代码测试、兼容性测试和代码改进。 ∙如果需要公开您的插件,可以用插件导出的方式,将插件配置信息导出到一个 XML 文件中,连同相应的程序和模板文件一同打包。同时,编写一个适合新手的插件的说明书也是必不可少的,其中包括:插件适用的 Discuz! 版本、功能概述、兼容性声明、安装方法、使用方法、卸载方法等等。 ∙将插件提供给他人,或自己使用,根据使用者反馈,对插件进行完善。插件实现流程至此结束。 ∙ 文件命名规范 Discuz! 按照如下的规范对程序和模板进行命名,请在设计插件时尽量遵循此命名规范: ∙可以直接通过浏览器访问的普通程序文件,以 .php 后缀命名。 ∙被普通程序文件引用的程序文件,以 .inc.php 后缀命名。 ∙被普通程序文件,或引用程序文件引用的函数库或类库,以 .func.php(函数库) 或 .class.php(类库) 后缀命名。 ∙模板文件,以 .htm 后缀命名,插件模板文件存在于 source/plugin/identifier/template/ 目录中,手机版插件模板存在于 source/plugin/identifier/template/mobile/目录中 ∙模板语言包文件,以 .lang.php 后缀命名,插件语言包文件开发时存放于 data/plugindata/ 目录中,文件名为identifier.lang.php。 ∙动态缓存文件,存放于 ./data/cache 目录中,依据不同的功用进行独立的命名。 ∙使用后台数据备份功能生成的备份文件,通常以 .sql 为后缀,存放于 data/ 目录中。 ∙有些目录中存在内容为空白的 index.htm 文件,此类文件是为了避免 Web 服务器打开 Directory Index 时可能产生的安全问题。 ∙[X2.5新增内容] 从 Discuz! X2.5 开始,产品对数据表进行了封装,封装后的文件统一命名为 Table 类,通过“C::t(Table类文件名)”方式调用。插件如需封装自己的数据表,可将 Table 类文件存放于 source/plugin/identifier/table/ 目录下,并以 table_表名.php 格式命名,详见X2.5的新程序架构。 ∙ class_core.php 模块功能白皮书 source/class/class_core.php 是 Discuz! 的通用初始化模块程序,其几乎被所有的外部代码所引用,在您开始插件设计之前,可以先对该模块的大致功能做一定的了解。class_core.php 主要完成了以下任务: ∙对不同 PHP 及操作系统环境做了判断和兼容性处理,使得 Discuz! 可以运行于各种不同配置的服务器环境下。 ∙初始化常量 IN_DISCUZ 为 TRUE,用于 include 或 require 后续程序的判断,避免其他程序被非法引用。 ∙读取社区程序所在绝对路径,存放于常量 DISCUZ_ROOT 中。 ∙加载所需的基本函数库 source/function/function_core.php。 ∙通过 config/config_global.php 中提供的数据库账号信息,建立数据库连接。Discuz! 支持数据表的前缀,如需获得表的全名,可使用“DB::table('tablename')”方式。 ∙判断用户是否登录,如登录标记 $_G['uid'] 为非 0,同时将 $_G['username'](加了 addslashes 的用户名,可用于不加修改的插入数据库)、 $_G['member']['username'](原始的用户名,可用于页面显示)、$_G['member']['password'](用户密码的MD5串)等相应用户信息赋值,其他用户信息存放于 $_G['member'],更多信息可通过“getuserprofile()”获取。 ∙判断用户管理权限,将管理权限标记 $_G['adminid'] 为 1~3 中间的值。0 代表普通用户;1 代表论坛管理员;2 代表超级版主;3 代表论坛版主。 将用户权限按照其所在的主用户组 ID 标记为 $_G['groupid'],相关权限从该 $_G['groupid'] 所对应的系统缓存中读出,存放于 $_G['group']。 ∙预置读入了每个模块的各种设置变量。 ∙[X2.5变更内容] $_G['username'] 将不进行 addslashes 处理。 插件接口概述 使用管理员账号登录 Discuz! 管理中心,在顶部菜单将可以看到“插件”菜单。“插件列表”列出了所有已安装的插件,是控制插件打开与否、设计插件模块、菜单、参数和使用权限的地方,插件开发者可以依照设计意图,在此进行插件的初步设置,这里同时也提供插件导入和插件开关的功能,用于导入他人设计的插件和对插件的可用状态进行变更。 开始编写一个新插件,请首先打开 config/config_global.php 文件,在文件结尾添加以下代码开启插件设计者模式。 ∙$_config['plugindeveloper'] = 1; 在插件管理中选择“设计新插件”,填写插件名称,名称用于表明此插件的用途,例如设置为“虚拟银行插件”。惟一标识符用于在后续的插件模块中调用本插件,不可与现有插件重复,命名规则限制与 PHP 变量命名相同,虽然初次设置后仍可改动,但强烈建议一次性将此配置设置好,否则可能涉及到很多代码方面的变更,增加编码的麻烦。请注意:惟一标识符请不要设置的过短,或使用有可能与其他插件重复的命名,例如制作此插件的公司叫做 Comsenz Inc.,插件名称是“虚拟银行插件”,惟一标识符可设置为“comsenz_virtual_bank”。最后在 source/plugin/ 目录中创建与唯一标识符同名的目录名,如 source/plugin/comsenz_virtual_bank/。 在插件管理中添加插件后,仅仅是增加了一条插件记录,后面还需要很多相关的设计和设置。在列表中选择插件的“详情”进入插件的详细设置。插件设置分为三个部分: ∙ 插件模块 插件模块分为程序链接、扩展项目和程序脚本 3 类: 程序链接 主导航项目:可在主导航栏增加一个菜单项,可自主指派菜单链接的 URL,也可以调用插件的一个模块,模块文件名指派为 source/plugin/插件目录/插件模块名.inc.php”。注意:由于引用外部程序,因此即便设置了模块的使用等级,您的程序仍需进行判断使用等级是否合法。 ∙程序链接 主导航项目 - 插件菜单:可在主导航栏的插件子菜单中增加一个菜单项。 ∙程序链接 顶部导航项目、底部导航项目、快捷导航项目、家园导航项目:可在各个导航中增加一个菜单项。 ∙扩展项目 个人设置:可在个人设置中增加一个菜单项。 ∙扩展项目 个人设置 - 个人资料:可在个人设置的个人资料页上部增加一个菜单项。 ∙扩展项目 个人设置 - 积分:可在个人设置的积分页上部增加一个菜单项。 ∙扩展项目 站点帮助:可在站点帮助中增加一个菜单项。 ∙扩展项目 我的帖子:可在我的帖子中增加一个菜单项。 ∙扩展项目 门户管理:可在门户管理面板上部增加一个菜单项。 ∙扩展项目 论坛管理 - 基本:可在前台论坛管理面板侧边上部增加一个菜单项。 ∙扩展项目 论坛管理 - 工具:可在前台论坛管理面板侧边下部增加一个菜单项。 ∙扩展项目 管理中心:可在后台插件栏目中为此插件增添一个管理模块。 ∙程序脚本 页面嵌入 - 普通版:设置一个包含页面嵌入脚本的模块,该模块用于在普通电脑访问的页面显示。模块文件名指派为 source/plugin/插件目录/插件模块名.class.php”。(页面嵌入将在后面的《页面嵌入模块开发》中详细说明) ∙程序脚本 页面嵌入 - 手机版:设置一个包含页面嵌入脚本的模块,该模块用于在手机访问的页面显示。 ∙程序脚本 特殊主题:设置一个特殊主题脚本的模块,模块文件名指派为 source/plugin/插件目录/插件模块名.class.php”。(特殊主题将在后面的《特殊主题模块开发》中详细说明) ∙ 您可以为每个模块设置不同的使用等级,例如设置为“超级版主”,则超级版主及更高的管理者可以使用此模块。 扩展项目模块可以在社区的特定位置扩展出新的功能,通常用于扩展新的设置项目。项目的脚本文件以 .inc.php 结尾(如 test.inc.php),模版为固定文件名,位于插件目录的 template/ 子目录中,文件名与脚本名同名(如 test.htm),扩展名为 .htm。添加相应的扩展项目模块时,需注明程序模块、菜单名称。例如我们添加个人面板项目,程序模块为 test,菜单名称是“测试”,当插件启用后,个人面板即家园的设置中会出现“测试”拓展项目。 在新插件内核中,通过 plugin.php 方式访问的插件可直接通过 plugin.php?id=xxx:yyy 方式调用而无需再在后台定义为普通脚本模块,只要 source/plugin/xxx/yyy.inc.php 文件存在即可。如果 xxx 和 yyy 同名,可直接通过 plugin.php?id=xxx 方式访问。 插件变量配置 插件接口中提供了一个通用的插件配置管理程序,在大多数情况下可实现插件的参数配置,省却了插件开发者自行编写后台管理模块(即上面提到的“扩展项目 管理中心”模块)的麻烦。通常情况下,应优先使用通用插件配置管理程序来实现插件的参数配置,只有在通用程序确实无法实现时,才自行编写后台管理模块。输入配置名称和配置变量名、选择合适的配置类型后,即可为此插件增加一个配置变量,点“详情”可以编辑此配置变量的更多信息。为了方便插件程序调用使用者配置好的参数,配置变量同样被存放在了缓存文件中,读取方法将在后面的《插件的参数读取与缓存控制》中详细说明。 注意:您只有在插件管理中将插件设置为“可用”,以上设置才能生效。 插件的参数读取与缓存控制 ∙编写插件程序时,可能需要读取一些插件的信息,如果插件需要使用者进行配置,还需要读取使用者设置的参数值。Discuz! 允许插件程序使用数据库读取和缓存读取这两种方法获取插件信息和参数。Discuz! 的插件接口已经对插件信息进行了合理的缓存,使用缓存读取的方式,将比数据库读取速度更快,消耗的资源更是几乎可以忽略不计。缓存读取唯一的局限是需要插件使用插件接口提供的通用后台管理程序。如果使用自定义后台模块的方式,需要后台模块将参数存放到 pluginvars 数据表中,才能被系统正常缓存。我们强烈推荐您通过缓存读取插件信息和配置数据。 ∙ 由于调用系统缓存统一通过“loadcache()”函数调用,并存放于 $_G['cache'] 中,因此“loadcache('plugin')”后插件的变量缓会存放于 $_G['cache']['plugin'] 中。嵌入点插件和以 plugin.php 为主脚本调用的插件无需加载此缓存,系统已自动加载了缓存。变量配置类型为“版块/*”的变量会保存在 $_G['cache']['forums'][fid]['plugin'] 中。变量配置类型为“用户组/*”的变量会保存在 $_G['cache']['usergroup_groupid']['plugin'] 和 $_G['group']['plugin'] 中。 页面嵌入模块开发 页面嵌入类型脚本格式<?php//全局嵌入点类(必须存在)class plugin_identifier { function HookId_1() { ...... return ...; } function HookId_2() { ...... return ...; } ......}//脚本嵌入点类class plugin_identifier_CURSCRIPT extends plugin_identifier { function HookId_1() { ...... return ...; } function HookId_2() { ...... return ...; } ......}?> ∙plugin_ ∙普通版脚本中的类名以 plugin_ 开头。手机版脚本中的类名以 mobileplugin_ 开头。 ∙identifier ∙插件的唯一标识符,在插件设置中设置。 ∙CURSCRIPT ∙嵌入点位于的脚本名,如 forum.php 为 forum。 ∙HookId
要查看所有的预定义嵌入点,请打开 config/config_global.php 文件,将文件结尾添加的设计者模式值改成“2”,然后更新缓存即可。在页面源码中查"<hook>"可搜索到嵌入点。(详细内容可参阅的《插件嵌入点列表》) $_config['plugindeveloper'] = 2; 预定义的嵌入点会在页面预置好的位置输出函数返回的内容。函数返回值类型如果是 array 且是空值的,必须输出一个空数组,如: return array(); 函数名并不限于以上列表,您可以自定义,只要符合以下规则,函数就会在适当的地方被调用。 function CURMODULE_USERDEFINE[_output]() CURMODULE 指明了此函数在哪个模块执行,可通过常量 CURMODULE 得到当前页面的 CURMODULE 值。 USERDEFINE 可自定义,如果函数名以“_output”结尾则会在模板输出前调用,否则会在模块执行前调用。 如:attachment_test() 函数会在论坛的下载附件的时候执行。 “_output”结尾的函数的第一个参数为数组,含义为 array('template' => 要输出的模板名, 'message' => showmessage 的文字) 如:以下函数将在登录的时候输出调试文字 function logging_test_output($a) { print_r($a); print_r($_POST);} plugin_identifier 类中的其它函数为了便于阅读建议以“_”开头,如: <?phpclass plugin_sample { function _updatecache() { ...... return ...; }}class plugin_sample_forum extends plugin_sample { function viewthread_posttop() { ...... return ...; } ......}?> 插件嵌入点列表 · 全局(common/) extcredits.htm string spacecp_credit_extra faq.htm string faq_extra footer.htm string global_footer string global_footerlink header.htm string global_cpnav_top (X2.5) string global_cpnav_extra1 string global_cpnav_extra2 string global_qmenu_top (X3) string global_qmenu_bottom (X3) string global_nav_extra (X2.5) string global_header userabout.htm array global_userabout_top string userapp_menu_top string userapp_menu_middle array global_userabout_bottom userstatus.htm string global_usernav_extra1 string global_usernav_extra2 string global_usernav_extra3 string global_usernav_extra4 (X2.5) · 论坛(forum/) collection_all.htm (X2.5) string collection_index_top string collection_index_bottom collection_comment.htm (X2.5) string collection_nav_extra collection_index.htm (X2.5) string collection_index_top string collection_index_bottom collection_mycollection.htm (X2.5) string collection_index_top string collection_index_bottom collection_nav.htm (X2.5) string collection_nav_extra collection_view.htm (X2.5) string collection_viewoptions string collection_view_top string collection_threadlistbottom string collection_relatedop string collection_view_bottom string collection_side_bottom discuz.htm string index_status_extra string index_nav_extra (X2.5) string index_top string index_catlist_top (X2.5) array index_followcollection_extra (X3) array index_favforum_extra (X2.5) array index_favforum_extra (X3) array index_catlist (X2.5) array index_forum_extra (X2.5) array index_forum_extra (X2.5) array index_datacollection_extra (X3) string index_middle string index_bottom string index_side_top string index_side_bottom discuzcode.htm array viewthread_attach_extra (X2.5) editor_menu_forum.htm string post_image_btn_extra string post_image_tab_extra string post_attach_btn_extra string post_attach_tab_extra forumdisplay.htm string forumdisplay_leftside_top string forumdisplay_leftside_bottom string forumdisplay_forumaction string forumdisplay_modlink string forumdisplay_top string forumdisplay_middle string forumdisplay_postbutton_top string forumdisplay_threadtype_inner (X2.5) string forumdisplay_filter_extra (X2.5) string forumdisplay_threadtype_extra (X2.5) string forumdisplay_bottom string forumdisplay_side_top string forumdisplay_side_bottom forumdisplay_fastpost.htm string forumdisplay_fastpost_content string forumdisplay_fastpost_func_extra string forumdisplay_fastpost_ctrl_extra string global_login_text string forumdisplay_fastpost_upload_extend (X3) string forumdisplay_fastpost_btn_extra string forumdisplay_fastpost_sync_method forumdisplay_list.htm string forumdisplay_filter_extra array forumdisplay_thread array forumdisplay_thread_subject (X2.5) array forumdisplay_author array forumdisplay_thread (X2.5) array forumdisplay_author (X2.5) string forumdisplay_threadlist_bottom (X2.5) string forumdisplay_postbutton_bottom forumdisplay_sort.htm (X2.5) string forumdisplay_postbutton_bottom forumdisplay_subforum.htm (X2.5) array forumdisplay_subforum_extra array forumdisplay_subforum_extra guide.htm string guide_nav_extra string guide_top string guide_bottom index_navbar.htm string index_navbar post.htm string post_top string post_middle string post_btn_extra string post_sync_method string post_bottom string post_upload_extend (X3) post_activity.htm string post_activity_extra post_debate.htm string post_debate_extra post_editor_attribute.htm (X3) string post_attribute_extra string post_attribute_extra_body post_editor_body.htm string post_editorctrl_right string post_editorctrl_left string post_editorctrl_top string post_editorctrl_bottom post_infloat.htm string post_infloat_top string post_infloat_middle string post_infloat_btn_extra post_poll.htm string post_poll_extra string post_poll_upload_extend (X3) post_reward.htm string post_reward_extra post_trade.htm string post_trade_extra topicadmin_modlayer.htm string forumdisplay_modlayer string modcp_modlayer trade_info.htm string viewthread_tradeinfo_extra viewthread.htm string viewthread_top string viewthread_postbutton_top string viewthread_modoption string viewthread_beginline (X2.5) string viewthread_title_extra string viewthread_title_row string viewthread_middle string viewthread_bottom viewthread_activity.htm string viewthread_activity_extra1 string viewthread_activity_extra2 viewthread_album.htm (X3) string viewthread_beginline string viewthread_useraction_prefix string viewthread_useraction string viewthread_bottom viewthread_fastpost.htm string viewthread_fastpost_side string viewthread_fastpost_content string viewthread_fastpost_func_extra string viewthread_fastpost_ctrl_extra string global_login_text string viewthread_fastpost_upload_extend (X3) string viewthread_fastpost_btn_extra (X2.5) viewthread_from_node.htm array viewthread_postheader array viewthread_postheader array viewthread_postheader array viewthread_endline viewthread_node.htm array viewthread_profileside array viewthread_imicons array viewthread_magic_user array viewthread_avatar array viewthread_sidetop array viewthread_sidebottom array viewthread_postheader string viewthread_modaction (X2.5) string viewthread_share_method string viewthread_useraction array viewthread_postsightmlafter (X2.5) array viewthread_postfooter array viewthread_postaction (X2.5) string viewthread_magic_thread array viewthread_magic_post array viewthread_endline viewthread_node_body.htm array viewthread_posttop string global_login_text array viewthread_postbottom viewthread_poll.htm string viewthread_poll_top string viewthread_poll_bottom viewthread_portal.htm string viewthread_useraction_prefix string viewthread_useraction string viewthread_side_bottom viewthread_preview_node.htm (X3) array viewthread_postheader array viewthread_endline viewthread_trade.htm array viewthread_trade_extra · 组(group/) group.htm string group_navlink string forumdisplay_navlink string group_navlink string forumdisplay_navlink string group_top string forumdisplay_top string group_nav_extra string forumdisplay_nav_extra string group_bottom string forumdisplay_bottom string group_side_bottom string forumdisplay_side_bottom group_list.htm string forumdisplay_postbutton_top string forumdisplay_filter_extra array forumdisplay_thread string forumdisplay_postbutton_bottom group_my.htm string my_header string my_bottom string my_side_top string my_side_bottom group_right.htm string group_index_side string group_side_top string forumdisplay_side_top index.htm string index_header string index_top string index_bottom string index_side_top string index_side_bottom type.htm string index_top array index_grouplist string index_bottom string index_side_top string index_side_bottom · 家园(home/) editor_image_menu.htm (X3) string spacecp_blog_upload_extend string portalcp_top_upload_extend follow_feed.htm string follow_nav_extra string follow_top string follow_upload_extend (X3) string follow_nav_extra (X3) spacecp_avatar.htm string spacecp_avatar_top string spacecp_avatar_bottom spacecp_blog.htm string spacecp_blog_top string spacecp_blog_middle string spacecp_blog_bottom spacecp_credit_base.htm string spacecp_credit_top string spacecp_credit_extra string spacecp_credit_bottom spacecp_credit_log.htm string spacecp_credit_top string spacecp_credit_bottom spacecp_privacy.htm string spacecp_privacy_top string spacecp_privacy_base_extra string spacecp_privacy_feed_extra string spacecp_privacy_bottom spacecp_profile.htm string spacecp_profile_top string spacecp_profile_extra string spacecp_profile_bottom spacecp_promotion.htm string spacecp_promotion_top string spacecp_promotion_bottom spacecp_upload.htm (X3) string spacecp_upload_extend spacecp_usergroup.htm string spacecp_usergroup_top string spacecp_usergroup_bottom string spacecp_usergroup_top string spacecp_usergroup_bottom string spacecp_usergroup_top string spacecp_usergroup_bottom space_album_pic.htm string space_album_pic_top string space_album_pic_op_extra string space_album_pic_bottom string space_album_pic_face_extra space_album_view.htm string space_album_op_extra space_blog_list.htm array space_blog_list_status space_blog_view.htm string space_blog_title string space_blog_share_method (X2.5) string space_blog_op_extra string space_blog_face_extra space_card.htm string space_card_top string space_card_baseinfo_middle string space_card_baseinfo_bottom string space_card_option string space_card_magic_user string space_card_bottom space_comment_li.htm array global_space_comment_op (X3) string global_comment_bottom (X3) space_doing.htm string space_doing_top string space_doing_bottom space_favorite.htm string space_favorite_nav_extra space_friend.htm string space_interaction_extra space_header.htm string global_usernav_extra1 string global_usernav_extra2 space_home.htm string space_home_navlink (X3) string space_home_side_top (X2.5) string space_home_side_bottom string space_home_top string space_home_navlink string space_home_bottom space_magic.htm (X2.5) string magic_nav_extra space_medal.htm (X2.5) string medal_nav_extra space_menu.htm string space_menu_extra space_profile_body.htm string space_profile_baseinfo_top string follow_profile_baseinfo_top (X2.5) string space_profile_baseinfo_middle string follow_profile_baseinfo_middle (X2.5) string space_profile_baseinfo_bottom string follow_profile_baseinfo_bottom (X2.5) string space_profile_extrainfo string follow_profile_extrainfo (X2.5) space_share_li.htm array space_share_comment_op space_status.htm string space_home_doing_sync_method space_wall.htm string space_wall_face_extra · 注册/登录(member/) login.htm string logging_side_top string logging_top string logging_input string logging_method login_simple.htm string global_login_extra register.htm string register_side_top string register_top string register_input string register_logging_method string register_bottom · 门户(portal/) portalcp_article.htm string portalcp_top string portalcp_extend string portalcp_middle string portalcp_bottom view.htm string view_article_top (X2.5) string view_article_subtitle (X2.5) string view_article_summary (X2.5) string view_article_content (X2.5) string view_share_method string view_article_op_extra (X2.5) string view_article_side_top (X2.5) string view_article_side_bottom (X2.5) · 排行榜(ranklist/) side_left.htm string ranklist_nav_extra · 搜索(search/) album.htm string album_top string album_bottom blog.htm string blog_top string blog_bottom collection.htm (X3) string collection_top string collection_bottom footer.htm string global_footer string global_footerlink forum.htm string forum_top string forum_bottom group.htm string group_top string group_bottom header.htm string global_usernav_extra1 string global_usernav_extra2 portal.htm string portal_top string portal_bottom · 应用(userapp/) userapp_app.htm string userapp_app_top string userapp_app_bottom userapp_index.htm string userapp_index_top string userapp_index_bottom userapp_menu_list.htm string userapp_menu_top string userapp_menu_middle string userapp_menu_bottom · 手机全局(mobile/common/) footer.htm string global_footer_mobile header.htm string global_header_mobile · 手机论坛(mobile/forum/) discuz.htm string index_top_mobile string index_middle_mobile string index_bottom_mobile forumdisplay.htm string forumdisplay_top_mobile array forumdisplay_thread_mobile string forumdisplay_bottom_mobile viewthread.htm string viewthread_top_mobile array viewthread_posttop_mobile array viewthread_postbottom_mobile string viewthread_bottom_mobile · 手机论坛(wml/forum/) discuz.htm string index_top_mobile string index_middle_mobile forumdisplay.htm string forumdisplay_top_mobile array forumdisplay_thread_mobile string forumdisplay_bottom_mobile viewthread.htm string viewthread_top_mobile array viewthread_posttop_mobile array viewthread_postbottom_mobile string viewthread_bottom_mobile 特殊主题模块开发 ∙特殊主题模块用于创建一个特殊主题,特殊主题类型脚本格式 <?phpclass threadplugin_identifier { var $name = 'XX主题'; //主题类型名称 var $iconfile = 'icon.gif'; //发布主题链接中的前缀图标 var $buttontext = '发布xx主题'; //发帖时按钮文字 function newthread($fid) { return ...; } function newthread_submit($fid) { } function newthread_submit_end($fid, $tid) { } function editpost($fid, $tid) { return ...; } function editpost_submit($fid, $tid) { } function editpost_submit_end($fid, $tid) { } function newreply_submit_end($fid, $tid) { } function viewthread($tid) { return ...; }}?> identifier 插件的唯一标识符,在插件设置中设置。 函数名以及含义
第三方拓展类的开发
广告类 脚本位置:source/class/adv/adv_name.php 语言包位置:source/language/adv/lang_name.php 【Discuz! X3.0 新增】 脚本位置:source/plugin/插件目录/adv/adv_name.php 缩略图:source/plugin/插件目录/adv/adv_name.gif <?phpclass adv_name { var $version = '1.0';//脚本版本号 var $name = 'name';//广告类型名称 (可填写语言包项目) var $description = 'desc';//广告类型说明 (可填写语言包项目) var $copyright = 'Comsenz Inc.';//版权 (可填写语言包项目) var $targets = array('portal', 'home', 'member', 'forum', 'group', 'userapp', 'plugin', 'custom');//广告类型适用的投放范围 var $imagesizes = array('120x60', '120x240');//图片广告推荐大小 function getsetting() {//返回设置项目 $settings = array( 'text' => array( 'title' => 'text_title',//设置项目名称 (可填写语言项目) 'type' => 'mradio',//项目类型 'value' => array(),//项目选项 'default' => 0,//项目默认值 ) ); return $settings; } function setsetting(&$advnew, &$parameters) {//保存设置项目 } function evalcode() {//广告显示时的运行代码 return array( //检测广告是否投放时的代码 'check' => ' if(condition) { $checked = false; }', //广告显示时的代码 (随机调用投放的广告) 'create' => '$adcode = $codes[$adids[array_rand($adids)]];', ); }}?>道具类 脚本位置:source/class/magic/magic_name.php 语言包位置:source/language/magic/lang_name.php 【Discuz! X3.0 新增】 脚本位置:source/plugin/插件目录/magic/magic_name.php 图标:source/plugin/插件目录/magic/magic_name.small.gif、source/plugin/插件目录/magic/magic_name.gif <?phpclass magic_name { var $version = '1.0';//脚本版本号 var $name = 'name';//道具名称 (可填写语言包项目) var $description = 'desc';//道具说明 (可填写语言包项目) var $price = '10';//道具默认价格 var $weight = '10';//道具默认重量 var $copyright = 'Comsenz Inc.';//版权 (可填写语言包项目) function getsetting() {//返回设置项目 $settings = array( 'text' => array( 'title' => 'text_title',//设置项目名称 (可填写语言项目) 'type' => 'mradio',//项目类型 'value' => array(),//项目选项 'default' => 0,//项目默认值 ) ); return $settings; } function setsetting(&$advnew, &$parameters) {//保存设置项目 } function usesubmit($magic, $parameters) {//道具使用 } function show($magic) {//道具显示 }}?>任务类 脚本位置:source/class/task/task_name.php 语言包位置:source/language/task/lang_name.php 【Discuz! X3.0 新增】 脚本位置:source/plugin/插件目录/task/task_name.php 图标:source/plugin/插件目录/task/task_name.gif <?phpclass task_name { var $version = '1.0';//脚本版本号 var $name = 'name';//任务名称 (可填写语言包项目) var $description = 'desc';//任务说明 (可填写语言包项目) var $copyright = 'Comsenz Inc.';//版权 (可填写语言包项目) var $icon = '';//默认图标 var $period = '';//默认任务间隔周期 var $periodtype = 0;//默认任务间隔周期单位 var $conditions = array(//任务附加条件 'text' => array( 'title' => 'text_title',//设置项目名称 (可填写语言项目) 'type' => 'mradio',//项目类型 'value' => array(),//项目选项 'default' => 0,//项目默认值 'sort' => 'complete',//条件类型 (apply:申请任务条件 complete:完成任务条件) ), ); function preprocess($task) {//申请任务成功后的附加处理 } function csc($task = array()) {//判断任务是否完成 (返回 TRUE:成功 FALSE:失败 0:任务进行中进度未知或尚未开始 大于0的正数:任务进行中返回任务进度) } function sufprocess($task) {//完成任务后的附加处理 } function view($task, $taskvars) {//任务显示 } function install() {//任务安装的附加处理 } function uninstall() {//任务卸载的附加处理 } function upgrade() {//任务升级的附加处理 }}?>验证问答类 脚本位置:source/class/secqaa/secqaa_name.php 语言包位置:source/language/secqaa/lang_name.php 【Discuz! X3.0 新增】 脚本位置:source/plugin/插件目录/secqaa/secqaa_name.php <?phpclass secqaa_name { var $version = '1.0';//脚本版本号 var $name = 'name';//验证问答名称 (可填写语言包项目) var $description = 'desc';//验证问答说明 (可填写语言包项目) var $copyright = 'Comsenz Inc.';//版权 (可填写语言包项目) function make(&$question) {//返回安全问答的答案和问题 ($question 为问题,函数返回值为答案) }}?>验证码类(Discuz! X2.5 新增) 脚本位置:source/class/seccode/seccode_name.php 语言包位置:source/language/seccode/lang_name.php 【Discuz! X3.0 新增】 脚本位置:source/plugin/插件目录/seccode/seccode_name.php <?phpclass seccode_name { var $version = '1.0';//脚本版本号 var $name = 'name';//验证码类型名称 (可填写语言包项目) var $copyright = 'Comsenz Inc.';//版权 (可填写语言包项目) var $setting = array();//后台设置后的变量 function check($value, $idhash) {//检查输入的验证码,返回 true 表示通过 } function make() {//输出验证码,echo 输出内容将显示在页面中 }}?> 计划任务模块开发 ∙本功能为 Discuz! X3.0 新增内容 ∙计划任务模块用于拓展一个计划任务项目,本模块会在插件安装时自动添加到系统计划任务中,并在插件卸载时自动从中删除 脚本位置:source/plugin/插件目录/cron/cron_name.php <?php//cronname:mycron 计划任务名称,可写脚本语言包中的项目//week:1 设置星期几执行本任务,留空为不限制//day:1 设置哪一日执行本任务,留空为不限制//hour:1 设置哪一小时执行本任务,留空为不限制//minute:0,30 设置哪些分钟执行本任务,至多可以设置 12 个分钟值,多个值之间用半角逗号 "," 隔开,留空为不限制if(!defined('IN_DISCUZ')) { exit('Access Denied');}//您的计划任务脚本内容?> 缓存更新模块开发 ∙本功能为 Discuz! X3.0 新增内容 ∙缓存更新模块用于在系统更新缓存时拓展一个缓存更新项目 脚本位置:source/plugin/插件目录/cache/cache_name.php <?phpif(!defined('IN_DISCUZ')) { exit('Access Denied');}function build_cache_plugin_name() { //您的缓存更新脚本内容}?> 插件安装、卸载、升级脚本的设计
安装、卸载 插件作者可以设计 2 个脚本文件用于插件的安装和卸载,文件名任意。脚本中可用 runquery() 函数执行 SQL 语句,表名可以直接写“cdb_”。插件作者只需在导出的 XML 文件结尾加上安装、卸载脚本的文件名即可 <item id="installfile"><![CDATA[install.php]]></item> <item id="uninstallfile"><![CDATA[uninstall.php]]></item> </item> </root> 安装、卸载程序中可随意设计页面的跳转,只要在插件安装、卸载结束时候输出添加以下代码即可。 $finish = TRUE;升级 插件作者可以设计一个脚本文件用于插件的升级,文件名任意。脚本中可用 runquery() 函数执行 SQL 语句,表名可以直接写“cdb_”。插件作者只需在导出的 XML 文件结尾加上升级脚本的文件名即可 <item id="upgradefile"><![CDATA[upgrade.php]]></item> </item> </root> 升级程序中可通过 $fromversion 和 $toversion 变量判断升级的具体版本号,并随意设计页面的跳转,只要在插件升级结束时候输出添加以下代码即可。 $finish = TRUE; 插件的当前版本号位于 XML 文件的以下分支中,可自行更改。 <item id="plugin"> ...... <item id="version"><![CDATA[当前版本]]></item> ...... </item>检测 插件作者可以设计一个脚本文件用于插件在安装、卸载、升级操作前的检测,文件名任意。插件作者只需在导出的 XML 文件结尾加上检测脚本的文件名即可 <item id="checkfile"><![CDATA[check.php]]></item> </item> </root>授权协议、插件介绍 插件在安装的时候您可以自定义授权信息文本,文本支持 Discuz! 代码,站长同意后才能安装插件。如果插件存在后台管理界面或者变量配置,那么插件介绍文本会显示在插件后台页面中。插件作者只需在导出的 XML 文件结尾加上以下内容即可 <item id="license"><![CDATA[授权协议文本]]></item> <item id="intro"><![CDATA[插件介绍文本]]></item> </item> </root>Discuz! 版本兼容性设置 请仔细检查您的插件是否可以在相应的 Discuz! 版本中运行。然后在 XML 文件的以下分支中自行更改。 如您的插件兼容多个版本,请用逗号(,)分隔,如“X2,X2.5”(此写法从 Discuz! X2 R20120329 后开始支持) <item id="Data"> <item id="plugin"> ...... </item> ...... <item id="version"><![CDATA[兼容性设置]]></item> ...... </item>其他论坛数据导入 插件安装时可以直接导入一个或多个论坛数据,这些论坛数据包括表情(smilies)、风格(styles)的数据。在导出的 XML 文件结尾加上需要导入数据的类型和数据文件名即可,多个文件名用逗号(",")分隔。 <item id="importfile"> <item id="smilies"><![CDATA[discuz_l]]></item> <item id="styles"><![CDATA[discuz_l]]></item> </item> </item> </root>小提示 如果导出的 XML 文件名以 SC_GBK、SC_UTF8、TC_BIG5、TC_UTF8 结尾,显示的时候将直接显示为“简体”、“繁体”、“UTF8”等字样。 插件模板和语言包的设计 插件语言包创建语言包 ∙给插件创建语言包首先需要创建一个 data/plugindata/identifier.lang.php 文件,文件内容中包含 4 个数组,如下: <?php$scriptlang['identifier'] = array( 'english' => 'chinese', ...);$templatelang['identifier'] = array( 'english' => 'chinese', ...);$installlang['identifier'] = array( 'english' => 'chinese', ...);$systemlang['identifier'] = array( 'file' => array( 'english' => 'chinese', ... ), ...);?> $scriptlang 为程序脚本文件的语言包。 $templatelang 为模版文件的语言包。 $installlang 为安装、升级、卸载脚本用的语言包。 $systemlang 为系统语言包(Discuz! X3 新增)。 如果插件不涉及某些类型的语言文字,变量可忽略。 ∙ 然后在插件基本设置中开启语言包选项后即可。 调用语言包 模版中调用模板文件语言包,通过 {lang identifier:english} 方式调用。 程序脚本中调用脚本文件语言包,通过 lang('plugin/identifier', 'english') 方式调用。 安装脚本中调用安装脚本文件语言包,通过 $installlang 变量直接获取。如 $installlang['english']。 系统语言包用于替换系统语言包中的某些语言条目。 语言包导出 创建好的语言包在插件导出后会自动导出到 XML 文件中,供插件作者转码后发放多编码版本的插件。如上例中导出的 XML 中会包含以下内容: <item id="language"> <item id="scriptlang"> <item id="english"><![CDATA[chinese]]></item> </item> <item id="templatelang"> <item id="english"><![CDATA[chinese]]></item> </item> <item id="installlang"> <item id="english"><![CDATA[chinese]]></item> </item> <item id="systemlang"> <item id="file"> <item id="english"><![CDATA[chinese]]></item> </item> </item></item> data/plugindata/identifier.lang.php 文件不必在插件发布的时候导出,此文件仅供插件设计者模式时使用。 插件模板 插件的模板统一放置到 source/plugin/identifier/template 目录下,程序脚本通过以下语句调用插件模板文件,如下例,调用 source/plugin/identifier/template/test.htm include template('identifier:test'); 模版中调用插件模版通过以下方法: {template identifier:test} 插件注册及插件新版本提示 以下内容仅限 Discuz! X2.0 为了保护插件的合法权益,你可以把设计好的插件到官方的应用中心( addon.discuz )进行注册,注册后你将拥有此插件的唯一所有权。 插件 LOGO 设置 设置插件的 LOGO,提升插件的价值。请自行设计一个 40x40 大小的 PNG 图片,上传到扩展中心,此 LOGO 会在 Discuz! 的插件管理中心显示。 插件新版本提示 插件新版本提示可以让站长在随时检测到你插件是否存在新版本。请插件作者把自己发布插件的相关文件生成 MD5 校验码,然后到扩展中心进行插件版本校验文件的登记。 插件校验码生成函数 function createValidator($pluginid, $md5files) { define('IN_DISCUZ', true); require_once 'source/class/class_xml.php'; require_once 'source/discuz_version.php'; $plugindir = 'source/plugin/'.$pluginid.'/'; $md5 = ''; foreach($md5files as $file) { $md5 .= md5_file($file); } echo md5(md5($md5).$pluginid); $xml = array( 'Title' => 'Discuz! Plugin Validator', 'Version' => DISCUZ_VERSION, 'Data' => $md5files, ); if($fp = @fopen($plugindir.'l', 'wb')) { fwrite($fp, array2xml($xml)); fclose($fp); }} 此函数执行后会在插件目录生成 l 文件,请同插件其他文件一并打包发布。页面输出的 MD5 校验码填写到扩展中心“插件版本校验文件登记”中。 使用范例 $md5files = array( 'source/plugin/myrepeats/switch.inc.php', 'source/plugin/myrepeats/admincp.inc.php', 'source/plugin/myrepeats/discuz_l', 'source/plugin/myrepeats/memcp.inc.php',);createValidator('myrepeats', $md5files); 编写插件的原则与注意事项 请在您动手编写插件之前,还需要仔细的阅读以下原则,遵循这些原则,将有效的避免可能发生的问题: ∙所有与插件的程序,包括其全部的前后台程序,请全部放入 source/plugin/ 目录中,同时在插件的安装说明中指出,插件的文件需要复制到哪些目录。为了避免与其他插件冲突,请尽量建立 source/plugin/ 下的子目录,并将插件程序放置于子目录下,这样您编写的插件将获得更好的兼容性。 ∙如果您的插件包含“导航栏”模块,该模块将统一用 plugin.php?identifier=xxx&module=yyy 的方式调用,请在相应链接、表单中使用此方式。其中 xxx 为插件的惟一标识符,yyy 为模块名称。前台插件外壳程序 plugin.php 已经加载了通用初始化模块 /source/class/class_core.php,不需再次引用。 ∙如果您的插件包含“管理中心”模块,该模块将统一用 admin.php?action=plugins&identifier=xxx&pmod=yyy 的方式调用,请在相应链接、表单中使用此方式。其中 xxx 和 yyy 的定义与“导航栏”模块中的相同。系统还允许用 admin.php?action=plugins&edit=$edit&pmod=$mod 的方式来生成链接和表单地址,$edit 和 $mod 变量已经被插件后台管理接口赋值,因此将这两个变量值带入 URL 中也是被支持的。由于后台模块是被 admin.php 调用,因此已加载了通用初始化模块 /source/class/class_core.php 并进行了后台管理人员权限验证,因此模块程序中可直接写功能代码,不需再进行验证。 ∙请勿绕过插件的前后台外壳(plugin.php 和 admin.php)而以直接调用某程序的方式编写插件,因为这样既导致了用户使用不便,代码冗余和不规范,同时又产生了因验证程序考虑不周到而带来的安全隐患。您可以在任何地方,包括链接、表单等处方便的使用上述 URL 地址对插件模块进行调用。 ∙所有与插件有关的程序,包括全部的前台程序,因全部使用外壳调用,请务必在第一行加入 if(!defined('IN_DISCUZ')) { exit('Access Denied');} 后台程序第一行加入 if(!defined('IN_DISCUZ') || !defined('IN_ADMINCP')) { exit('Access Denied');} ∙以免其被 URL 直接请求调用,产生安全问题。 ∙一般情况下,您发布插件请使用插件导出的功能,以方便使用者一次性导入插件的配置数据,极特殊的情况下,也可以分步骤告知使用者如何进行插件配置管理和安装此插件。 ∙如果功能独立,请尽量使用单独程序的方式编写插件(即外挂型插件),而尽量少的对论坛本身代码进行修改,这将为使用者今后的升级带来很大方便。 ∙您可以修改 Discuz! 本身的数据结构,但更推荐在不很影响效率的前提下将插件数据用另外的数据表存储,因为不能排除您增加的字段或索引和今后版本 Discuz! 核心数据字段重名的可能。在任何情况下,请不要删除 Discuz! 标准版本数据结构中已有的字段或索引。 ∙请在插件说明书中对插件做以详尽的描述,例如增加了哪些字段、哪些表,修改了或新增了哪些程序,版本兼容性,后续支持的提供方式(例如不提供支持,或以什么样的方式提供)。如果方便,请尽可能提供插件的卸载方法,例如去除哪些字段、删除哪些新增的程序、将哪些被插件修改的程序恢复原状等等,使用者会感激您为此付出的辛勤劳动,甚至愿意支付相应的费用支持您未来的发展。 ∙如果插件使用另外的数据表存储,请在插件管理中准确的设置插件所使用的数据表名称(不包含前缀),这样用户在备份数据的时候,能够把插件数据一同备份。 ∙Discuz! 内置了 8 种自定义积分,存储于 common_member 表中的 extcredits1 至 extcredits8 字段中,类型为有符号整数 2、语言包编码转换工具 convertz 【百度一下】(专门用来处理多种编码的插件安装 ) 3、数据库管理工具 navicat 【百度一下】(方便数据库的查看与操作) 4、网站的基本数据,这些数据包括:系统常量、全局变量、系统调用 ,首先从系统常量说起 4.1、系统常量 DISCUZ_ROOT //网站根目录 TIMESTAMP //程序执行的时间戳 CHARSET //程序的语言编码类型 IS_ROBOT //是否是机器访问 FORMHASH //HASH值 其余的可直接打印出来查看,如: 1<?php 2require_once './source/class/class_core.php'; 3$discuz = & discuz_core::instance(); 4$discuz->init(); 5print_r(get_defined_constants()); 6?> 复制代码 4.2、全局变量 直接打印$_G即可得知,如: 7<?php 8require_once './source/class/class_core.php'; 9$discuz = & discuz_core::instance(); 10$discuz->init(); 11print_r($_G); 12?> 复制代码 4.3、数据库配置参数 直接打印$_G['config']['db']即可,如: 13<?php 14require_once './source/class/class_core.php'; 15$discuz = & discuz_core::instance(); 16$discuz->init(); 17print_r($_G['config']['db']); 18?> 复制代码 4.4、数据库操作 DB::table() //增加了pre的数据库表名 DB::delete() //删除表中数据 DB::insert() //向表中插入数据 DB::update() //更新表中数据 DB::fetch() //配合DB::query来实现数据资源数据的获取 DB::query() //执行一条数据库语句 DB::fetch_first() //获取结果集的第一条记录 更多操作请查看文档:/wiki/index ... E%E5%BA%93%E7%B1%BB 5、熟悉 ./source/function/function_admincp.php 管理后台文件里的函数,知道具体函数是实现什么功能效果 6、了解和掌握基础通用的类、函数 /wiki/#.E5. ... 1.E5.87.BD.E6.95.B0 二、安全性处理 1、文件的安全性 所有与插件有关的程序,包括全部的前后台程序,因全部使用外壳调用,请务必在第一行加入 if(!defined('IN_DISCUZ')) { exit('Access Denied'); } 以免其被 URL 直接请求调用,产生安全问题。 2、对数值处理 2.1、 intval(); //处理非负整数 ,如:$uid=intval($uid); 注意,使用intval后,一定要想一想,自己这个变量是不是应该非负的?如果是的话,得加个判断语句,或者用abs,max等函数处理下 2.2、 trim(); //去除左右空格, 如:$username=trim($username); 2.3、 对于文字内容,记得使用htmlspecialchars(dhtmlspecialchars) 2.4、 写入数据库时的注意事项 要进数据库的变量一定得addslashes(DZ内为daddslashes,如用DZ无须再次过滤,DZ已将所有$_POST和$_GET过滤),当然,如果你进的是数字(比如uid,并且已经intval过),或者是其他一些肯定不会出错的,那么你可以不做这一步。 2.5、 在写sql语句时,变量一定得记得用’框起来。如果变量是字符串,不这么做会出错。如果是数字不这么做不会提示出错,但是有可能有注入的危险。 2.6、 数组在运用前记得写$xxx = array(); 原因很简单,防止用户提交恶意的值。 3、语句查询优化 在写SQL语句是尽量符合SQL规则,语句查询要相应的优化,有先有后;数据表要相应的创建索引,加快查询速度,这里不多说。 三、实例讲解之插件的前兆 1、最先清楚需要开发什么功能的插件,插件机制是否能够开发,最后能否达到预期效果,否则一切都免谈了 2、需要使用什么菜单、什么参数,配置哪些选项、数据结构如何设计、前后台实现哪些功能等等 3、需要哪些函数,discuz内部是否有这功能的函数,尽量用内部的函数来达到预期效果 4、最好不要改动discuz原有的布局,宁愿Coty一段代码出来也不要在原有的函数上添加功能,防止以后的升级问题 5、尽最大能力去开发智能的插件,多用变量代替常量,增强程序的移植性,可维护性 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论