IITT网络服务中心

标题: Discuz! 的插件机制 [打印本页]

作者: admin    时间: 2018-3-1 04:46
标题: Discuz! 的插件机制
#准备工作
插件实现流程

开始编写社区插件,您应当首先对插件实现的流程有一个大致的了解,以下是我们推荐的插件编写流程:


文件命名规范

Discuz! 按照如下的规范对程序和模板进行命名,请在设计插件时尽量遵循此命名规范:


class_core.php 模块功能白皮书

source/class/class_core.php 是 Discuz! 的通用初始化模块程序,其几乎被所有的外部代码所引用,在您开始插件设计之前,可以先对该模块的大致功能做一定的了解。class_core.php 主要完成了以下任务:



作者: admin    时间: 2018-3-1 04:46
#插件接口
使用管理员账号登录 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”。注意:由于引用外部程序,因此即便设置了模块的使用等级,您的程序仍需进行判断使用等级是否合法。
程序链接 主导航项目 - 插件菜单:可在主导航栏的插件子菜单中增加一个菜单项。
程序链接 顶部导航项目、底部导航项目、快捷导航项目、家园导航项目:可在各个导航中增加一个菜单项。
扩展项目 个人设置:可在个人设置中增加一个菜单项。
扩展项目 个人设置 - 个人资料:可在个人设置的个人资料页上部增加一个菜单项。
扩展项目 个人设置 - 积分:可在个人设置的积分页上部增加一个菜单项。
扩展项目 站点帮助:可在站点帮助中增加一个菜单项。
扩展项目 我的帖子:可在我的帖子中增加一个菜单项。
扩展项目 门户管理:可在门户管理面板上部增加一个菜单项。
扩展项目 论坛管理 - 基本:可在前台论坛管理面板侧边上部增加一个菜单项。
扩展项目 论坛管理 - 工具:可在前台论坛管理面板侧边下部增加一个菜单项。
扩展项目 管理中心:可在后台插件栏目中为此插件增添一个管理模块。
扩展项目 管理中心 - 列表链接:可在后台插件列表页增添一个远程链接。(Discuz! X3.1 新增)
程序脚本 页面嵌入 - 普通版:设置一个包含页面嵌入脚本的模块,该模块用于在普通电脑访问的页面显示。模块文件名指派为 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 方式访问。

插件变量配置
插件接口中提供了一个通用的插件配置管理程序,在大多数情况下可实现插件的参数配置,省却了插件开发者自行编写后台管理模块(即上面提到的“扩展项目 管理中心”模块)的麻烦。通常情况下,应优先使用通用插件配置管理程序来实现插件的参数配置,只有在通用程序确实无法实现时,才自行编写后台管理模块。输入配置名称和配置变量名、选择合适的配置类型后,即可为此插件增加一个配置变量,点“详情”可以编辑此配置变量的更多信息。为了方便插件程序调用使用者配置好的参数,配置变量同样被存放在了缓存文件中,读取方法将在后面的《插件的参数读取与缓存控制》中详细说明。

注意:您只有在插件管理中将插件设置为“可用”,以上设置才能生效。
作者: admin    时间: 2018-3-1 04:47
#参数读取
编写插件程序时,可能需要读取一些插件的信息,如果插件需要使用者进行配置,还需要读取使用者设置的参数值。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'] 中。


作者: admin    时间: 2018-3-1 04:51
# 页面嵌入
页面嵌入类型脚本格式普通版脚本中的类名以 plugin_ 开头。手机版脚本中的类名以 mobileplugin_ 开头。插件的唯一标识符,在插件设置中设置。嵌入点位于的脚本名,如 forum.php 为 forum。
函数名调用位置声明位置参数含义
HookId()所有模块执行前被调用脚本嵌入点类
HookId_output($value)模块执行完毕,模板输出前被调用脚本嵌入点类$value: array('template' => 当前要输出的模版,'message' => showmessage 的信息内容,'values' => showmessage 的信息变量,
)
global_HookId()模块执行完毕,模板输出前被调用全局嵌入点类
HookId_message($value)showmessage() 执行时调用脚本嵌入点类$value: array('param' => showmessage() 函数的参数数组,
)
ad_adId($value)相应的广告位中调用
函数名为广告位脚本 ID 如:ad_headerbanner()
全局嵌入点类
脚本嵌入点类
$value: array('params' => 广告位参数,'content' => 当前广告位原本将要显示的内容,
)
common()所有模块执行前被调用全局嵌入点类
discuzcode($value)discuzcode() 函数执行时调用
用于在帖子内容解析时嵌入自己的功能,函数中 $_G['discuzcodemessage'] 变量为待解析的字串
全局嵌入点类$value: array('param' => caller 函数的参数数组,'caller' => caller 函数,此嵌入点被哪个函数调用'discuzcode' 被 discuzcode() 调用'messagecutstr' 被 messagecutstr() 调用
)
deletethread($value)deletethread() 函数执行时调用
用于在主题删除前后嵌入自己的功能,此函数将在 deletethread() 中被调用 2 次,函数中 $_G['deletethreadtids'] 变量为待处理的 TID 数组
全局嵌入点类$value: array('param' => deletethread() 函数的参数数组,'step' => 删除的步骤'check' 检测步骤'delete' 删除步骤
)
deletepost($value)deletepost() 函数执行时调用
用于在帖子删除前后嵌入自己的功能,此函数将在 deletepost() 中被调用 2 次,函数中 $_G['deletepostids'] 变量为待处理的 ID 数组
全局嵌入点类$value: array('param' => deletepost() 函数的参数数组,'step' => 删除的步骤'check' 检测步骤'delete' 删除步骤
)
avatar($value)
(X2.5 新增)
avatar() 函数执行时调用
用于在头像调用时嵌入自己的功能,函数中 $_G['hookavatar'] 变量为新头像返回值
全局嵌入点类$value: array('param' => avatar() 函数的参数数组
)
profile_node($post, $start, $end)
(X3.0 新增)
贴内用户信息标记,返回值为标记显示内容全局嵌入点类$post: 当前帖子信息数组
$start: 用户填写的前置字符
$end: 用户填写的后置字符

要查看所有的预定义嵌入点,请打开 config/config_global.php 文件,将文件结尾添加的设计者模式值改成“2”,然后更新缓存即可。在页面源码中查找"<hook>"可搜索到嵌入点。(详细内容可参阅的《插件嵌入点列表》)

  1. $_config['plugindeveloper'] = 2;
复制代码


预定义的嵌入点会在页面预置好的位置输出函数返回的内容。函数返回值类型如果是 array 且是空值的,必须输出一个空数组,如:

  1. return array();
复制代码

函数名并不限于以上列表,您可以自定义,只要符合以下规则,函数就会在适当的地方被调用。

  1. function CURMODULE_USERDEFINE[_output]()
复制代码

CURMODULE 指明了此函数在哪个模块执行,可通过常量 CURMODULE 得到当前页面的 CURMODULE 值。 USERDEFINE 可自定义,如果函数名以“_output”结尾则会在模板输出前调用,否则会在模块执行前调用。 如:attachment_test() 函数会在论坛的下载附件的时候执行。 “_output”结尾的函数的第一个参数为数组,含义为 array('template' => 要输出的模板名, 'message' => showmessage 的文字) 如:以下函数将在登录的时候输出调试文字

  1. function logging_test_output($a) {
  2.         print_r($a);
  3.         print_r($_POST);
  4. }
复制代码

plugin_identifier 类中的其它函数为了便于阅读建议以“_”开头,如:

  1. <?php

  2. class plugin_sample {

  3.         function _updatecache() {
  4.                 ......
  5.                 return ...;
  6.         }

  7. }

  8. class plugin_sample_forum extends plugin_sample {

  9.         function viewthread_posttop() {
  10.                 ......
  11.                 return ...;
  12.         }

  13.         ......

  14. }

  15. ?>
复制代码

插件嵌入点列表

附: 插件嵌入点列表



作者: admin    时间: 2018-3-1 04:53
#特殊主题


作者: admin    时间: 2018-3-1 04:56
#第三方拓展类 广告类

脚本位置: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

  1. <?php

  2. class adv_name {

  3.         var $version = '1.0';//脚本版本号
  4.         var $name = 'name';//广告类型名称 (可填写语言包项目)
  5.         var $description = 'desc';//广告类型说明 (可填写语言包项目)
  6.         var $copyright = 'Comsenz Inc.';//版权 (可填写语言包项目)
  7.         var $targets = array('portal', 'home', 'member', 'forum', 'group', 'userapp', 'plugin', 'custom');//广告类型适用的投放范围
  8.         var $imagesizes = array('120x60', '120x240');//图片广告推荐大小

  9.         function getsetting() {//返回设置项目
  10.                 $settings = array(
  11.                         'text' => array(
  12.                                 'title' => 'text_title',//设置项目名称 (可填写语言项目)
  13.                                 'type' => 'mradio',//项目类型
  14.                                 'value' => array(),//项目选项
  15.                                 'default' => 0,//项目默认值
  16.                         )
  17.                 );
  18.                 return $settings;
  19.         }

  20.         function setsetting(&$advnew, &$parameters) {//保存设置项目
  21.         }

  22.         function evalcode() {//广告显示时的运行代码
  23.                 return array(
  24.                         //检测广告是否投放时的代码
  25.                         'check' => '
  26.                         if(condition) {
  27.                                 $checked = false;
  28.                         }',
  29.                         //广告显示时的代码 (随机调用投放的广告)
  30.                         'create' => '$adcode = $codes[$adids[array_rand($adids)]];',
  31.                 );
  32.         }
  33. }

  34. ?>
复制代码

道具类

脚本位置: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

  1. <?php

  2. class magic_name {

  3.         var $version = '1.0';//脚本版本号
  4.         var $name = 'name';//道具名称 (可填写语言包项目)
  5.         var $description = 'desc';//道具说明 (可填写语言包项目)
  6.         var $price = '10';//道具默认价格
  7.         var $weight = '10';//道具默认重量
  8.         var $copyright = 'Comsenz Inc.';//版权 (可填写语言包项目)

  9.         function getsetting() {//返回设置项目
  10.                 $settings = array(
  11.                         'text' => array(
  12.                                 'title' => 'text_title',//设置项目名称 (可填写语言项目)
  13.                                 'type' => 'mradio',//项目类型
  14.                                 'value' => array(),//项目选项
  15.                                 'default' => 0,//项目默认值
  16.                         )
  17.                 );
  18.                 return $settings;
  19.         }

  20.         function setsetting(&$advnew, &$parameters) {//保存设置项目
  21.         }

  22.         function usesubmit($magic, $parameters) {//道具使用
  23.         }

  24.         function show($magic) {//道具显示
  25.         }

  26. }

  27. ?>
复制代码

任务类

脚本位置: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

  1. <?php

  2. class task_name {

  3.         var $version = '1.0';//脚本版本号
  4.         var $name = 'name';//任务名称 (可填写语言包项目)
  5.         var $description = 'desc';//任务说明 (可填写语言包项目)
  6.         var $copyright = 'Comsenz Inc.';//版权 (可填写语言包项目)
  7.         var $icon = '';//默认图标
  8.         var $period = '';//默认任务间隔周期
  9.         var $periodtype = 0;//默认任务间隔周期单位
  10.         var $conditions = array(//任务附加条件
  11.                 'text' => array(
  12.                         'title' => 'text_title',//设置项目名称 (可填写语言项目)
  13.                         'type' => 'mradio',//项目类型
  14.                         'value' => array(),//项目选项
  15.                         'default' => 0,//项目默认值
  16.                         'sort' => 'complete',//条件类型 (apply:申请任务条件 complete:完成任务条件)
  17.                 ),
  18.         );

  19.         function preprocess($task) {//申请任务成功后的附加处理
  20.         }

  21.         function csc($task = array()) {//判断任务是否完成 (返回 TRUE:成功 FALSE:失败 0:任务进行中进度未知或尚未开始  大于0的正数:任务进行中返回任务进度)
  22.         }

  23.         function sufprocess($task) {//完成任务后的附加处理
  24.         }

  25.         function view($task, $taskvars) {//任务显示
  26.         }

  27.         function install() {//任务安装的附加处理
  28.         }

  29.         function uninstall() {//任务卸载的附加处理
  30.         }

  31.         function upgrade() {//任务升级的附加处理
  32.         }

  33. }

  34. ?>
复制代码

验证问答类

脚本位置:source/class/secqaa/secqaa_name.php

语言包位置:source/language/secqaa/lang_name.php

【Discuz! X3.0 新增】


脚本位置:source/plugin/插件目录/secqaa/secqaa_name.php

  1. <?php

  2. class secqaa_name {

  3.         var $version = '1.0';//脚本版本号
  4.         var $name = 'name';//验证问答名称 (可填写语言包项目)
  5.         var $description = 'desc';//验证问答说明 (可填写语言包项目)
  6.         var $copyright = 'Comsenz Inc.';//版权 (可填写语言包项目)

  7.         function make(&$question) {//返回安全问答的答案和问题 ($question 为问题,函数返回值为答案)
  8.         }

  9. }

  10. ?>
复制代码

验证码类(Discuz! X2.5 新增)

脚本位置:source/class/seccode/seccode_name.php

语言包位置:source/language/seccode/lang_name.php

【Discuz! X3.0 新增】


脚本位置:source/plugin/插件目录/seccode/seccode_name.php

  1. <?php

  2. class seccode_name {

  3.         var $version = '1.0';//脚本版本号
  4.         var $name = 'name';//验证码类型名称 (可填写语言包项目)
  5.         var $copyright = 'Comsenz Inc.';//版权 (可填写语言包项目)
  6.         var $setting = array();//后台设置后的变量

  7.         function check() {//检查输入的验证码,返回 true 表示通过               
  8.         }

  9.         function make() {//输出验证码,echo 输出内容将显示在页面中
  10.         }

  11.         function image() {//纯图片验证码 URL,用于移动端显示(Discuz! X3.1 新增)
  12.         }

  13. }

  14. ?>
复制代码
友情提示:下载学习 Discuz! X3 范例插件



作者: admin    时间: 2018-3-1 04:57
#其它模块
计划任务模块开发

脚本位置:source/plugin/插件目录/cron/cron_name.php

  1. <?php

  2. //cronname:mycron     计划任务名称,可写脚本语言包中的项目
  3. //week:1              设置星期几执行本任务,留空为不限制
  4. //day:1               设置哪一日执行本任务,留空为不限制
  5. //hour:1              设置哪一小时执行本任务,留空为不限制
  6. //minute:0,30         设置哪些分钟执行本任务,至多可以设置 12 个分钟值,多个值之间用半角逗号 "," 隔开,留空为不限制

  7. if(!defined('IN_DISCUZ')) {
  8.         exit('Access Denied');
  9. }

  10. //您的计划任务脚本内容

  11. ?>
复制代码

缓存更新模块开发

脚本位置:source/plugin/插件目录/cache/cache_name.php

  1. <?php

  2. if(!defined('IN_DISCUZ')) {
  3.         exit('Access Denied');
  4. }

  5. function build_cache_plugin_name() {
  6.         //您的缓存更新脚本内容
  7. }

  8. ?>
复制代码



作者: admin    时间: 2018-3-1 05:00
#安装脚本
安装、卸载

插件作者可以设计 2 个脚本文件用于插件的安装和卸载,文件名任意。脚本中可用 runquery() 函数执行 SQL 语句,表名可以直接写“cdb_”。插件作者只需在导出的 XML 文件结尾加上安装、卸载脚本的文件名即可

  1.                 <item id="installfile"><![CDATA[install.php]]></item>
  2.                     <item id="uninstallfile"><![CDATA[uninstall.php]]></item>
  3.             </item>
  4.     </root>
复制代码
安装、卸载程序中可随意设计页面的跳转,只要在插件安装、卸载结束时候输出添加以下代码即可
  1. $finish = TRUE;
复制代码

从 Discuz! X3.1 开始,卸载程序将不再支持页面的跳转及上面的 $finish 变量

升级

插件作者可以设计一个脚本文件用于插件的升级,文件名任意。脚本中可用 runquery() 函数执行 SQL 语句,表名可以直接写“cdb_”。插件作者只需在导出的 XML 文件结尾加上升级脚本的文件名即可

  1.                     <item id="upgradefile"><![CDATA[upgrade.php]]></item>
  2.             </item>
  3.     </root>
复制代码
升级程序中可通过 $fromversion 和 $toversion 变量判断升级的具体版本号,并随意设计页面的跳转,只要在插件升级结束时候输出添加以下代码即可。
  1. $finish = TRUE;
复制代码
插件的当前版本号位于 XML 文件的以下分支中,可自行更改。
  1.             <item id="plugin">
  2.                     ......
  3.                     <item id="version"><![CDATA[当前版本]]></item>
  4.                     ......
  5.             </item>
复制代码

检测

插件作者可以设计一个脚本文件用于插件在安装、卸载、升级操作前的检测,文件名任意。插件作者只需在导出的 XML 文件结尾加上检测脚本的文件名即可

  1.                     <item id="checkfile"><![CDATA[check.php]]></item>
  2.             </item>
  3.     </root>
复制代码

授权协议、插件介绍

插件在安装的时候您可以自定义授权信息文本,文本支持 Discuz! 代码,站长同意后才能安装插件。如果插件存在后台管理界面或者变量配置,那么插件介绍文本会显示在插件后台页面中。插件作者只需在导出的 XML 文件结尾加上以下内容即可

  1.                     <item id="license"><![CDATA[授权协议文本]]></item>
  2.                     <item id="intro"><![CDATA[插件介绍文本]]></item>
  3.             </item>
  4.     </root>
复制代码

开启、关闭(Discuz! X3.1 新增)

插件作者可以设计 2 个脚本文件用于插件在开启和关闭时执行,文件名任意。脚本中可用 runquery() 函数执行 SQL 语句,表名可以直接写“cdb_”。插件作者只需在导出的 XML 文件结尾加上开启、关闭脚本的文件名即可

  1.                     <item id="enablefile"><![CDATA[enable.php]]></item>
  2.                     <item id="disablefile"><![CDATA[disable.php]]></item>
  3.             </item>
  4.     </root>
复制代码
  1. Discuz! 版本兼容性设置
  2. 请仔细检查您的插件是否可以在相应的 Discuz! 版本中运行。然后在 XML 文件的以下分支中自行更改。

  3. 如您的插件兼容多个版本,请用逗号(,)分隔,如“X2,X2.5”(此写法从 Discuz! X2 R20120329 后开始支持)
复制代码
  1.             <item id="Data">
  2.                     <item id="plugin">
  3.                                 ......
  4.                     </item>
  5.                     ......
  6.                     <item id="version"><![CDATA[兼容性设置]]></item>
  7.                     ......
  8.             </item>
复制代码

其他论坛数据导入

插件安装时可以直接导入一个或多个论坛数据,这些论坛数据包括表情(smilies)、风格(styles)的数据。在导出的 XML 文件结尾加上需要导入数据的类型和数据文件名即可,多个文件名用逗号(",")分隔。

  1.                     <item id="importfile">
  2.                             <item id="smilies"><![CDATA[discuz_smilies_test.xml]]></item>
  3.                             <item id="styles"><![CDATA[discuz_styles_test.xml]]></item>
  4.                     </item>
  5.             </item>
  6.     </root>
复制代码

小提示

如果导出的 XML 文件名以 SC_GBK、SC_UTF8、TC_BIG5、TC_UTF8 结尾,显示的时候将直接显示为“简体”、“繁体”、“UTF8”等字样。



作者: admin    时间: 2018-3-1 05:02
#安装语言包插件语言包创建语言包

作者: admin    时间: 2018-3-1 05:04
#注意事项

请在您动手编写插件之前,还需要仔细的阅读以下原则,遵循这些原则,将有效的避免可能发生的问题:


后台程序第一行加入
  1. if(!defined('IN_DISCUZ') || !defined('IN_ADMINCP')) {
  2.         exit('Access Denied');
  3. }
复制代码





欢迎光临 IITT网络服务中心 (http://service.iitt.cc/) Powered by Discuz! X3