> ## Documentation Index
> Fetch the complete documentation index at: https://discuz.p.cafe/llms.txt
> Use this file to discover all available pages before exploring further.

# RESTful API 开发手册

详情代码请看：[https://gitee.com/Discuz/discuz-restful-api](https://gitee.com/Discuz/discuz-restful-api)

# Discuz! RESTful API

## 文件说明

* discuz\_restful\_sample.xml: RESTful API XML 文件范例
* discuz\_restful\_official\_trial.xml:
  官方提供的范例接口，完整接口请通过管理中心“站长”>“RESTful 接口”的“导入接口”中在线安装“Discuz! Team”的接口，API 文档见
  [https://docs.apipost.net/docs/detail/2c7d89151864000](https://docs.apipost.net/docs/detail/2c7d89151864000)
* request\_sample.php: PHP 版本的接口调用范例，其他语言范例参考 [https://gitee.com/Discuz/UCenter/tree/master/developer](https://gitee.com/Discuz/UCenter/tree/master/developer) （Discuz! RESTful API 规范和 UCenter 2.0 的 RESTful API 是一致的）

## 介绍

本手册所述内容目前仅针对 Discuz!ᵂ、Discuz! 企飞版，Discuz! X5。

RESTful API 为 Discuz! 基于 oAuth2 协议开发的一套开放的 API 接口。正常情况下，您只需要书写一个 XML 文件即可创建一个 API 接口，而无需书写 PHP 代码。本 Git 附带的 discuz\_restful\_official\_trial.xml 文件为范例文件，您可以打开阅读协助您开发出自己的 API。

## XML 规范

此 XML 遵从 Discuz! 标准的开放 XML 格式书写方法。

```xml theme={null}
<?xml version="1.0" encoding="ISO-8859-1"?>
<root>
    <item id="Title"><![CDATA[Discuz! RESTful]]></item>
    <item id="Data">
        <item id="copyright"><![CDATA[Discuz! Team]]></item>
        <item id="api">
            <item id="v1">
            ......
            </item>
        </item>
    </item>
</item>        
```

### 主体结构

* Title 节点为固定内容“Discuz! RESTful”，识别 XML 内容类型
* Data 节点为具体接口数据
* Data.copyright 为版权信息，您可以写上您的姓名
* Data.api 为详细的 API 列表及内容

### Data.api

在 Data.api 节点中，必须首先声明版本号，我们本着多版本兼容共存的原则，我们建议您在开发 API 的时候旧版本定型稳定后请不要再去改动它，而是启用新版本号。用户在 Discuz! 管理中心导入的时候，多版本是可以同时存在的。

```xml theme={null}
<item id="v1">
......
</item>
<item id="v2">
......
</item>
......
```

#### 接口声明

一个接口需完成以下内容的声明才能生效

```xml theme={null}
<item id="接口path">
    <item id="name"><![CDATA[接口名称]]></item>
    <item id="attr">
        <item id="validateData"><![CDATA[1]]></item>
        <item id="validateUnique"><![CDATA[30]]></item>
    </item>
    <item id="script"><![CDATA[调用脚本]]></item>
    <item id="output">
        ...... 输出变量映射
    </item>
    <item id="plugin">
        ...... 过滤插件
    </item>
    <item id="get">
        ...... GET 参数
    </item>
    <item id="post">
        ...... POST 参数
    </item>
    <item id="usage">
        ...... 参数说明
    </item>
</item>
```

##### 接口path

英文字母、数字、下划线的组合，如：forumdisplay，那么这个接口的具体 URL 为 /api/restful?/forumdisplay

如接口要分级，请按照如下方式书写，可定义出 /api/restful?/member/loginInfo、/api/restful?/member/registerInfo 2个用户接口

```xml theme={null}
<item id="member">
    <item id="name"><![CDATA[用户接口]]></item>
    <item id="loginInfo">
        ......
    </item>
    <item id="registerInfo">
        ......
    </item>
</item>    
```

##### 调用脚本

当前接口调用的脚本名，如调用 forum.php，填写 forum，只能填写根目录的脚本

##### 输出变量映射

输出映射按照如下规则填写多条

```xml theme={null}
<item id="output">
    <item id="原变量"><![CDATA[映射KEY]]></item>
    ......
</item>
```

例如：

```xml theme={null}
<item id="output">
    <item id="_G/dshowmessageParam"><![CDATA[msg]]></item>
    <item id="_G/uid,username,groupid,groupname"><![CDATA[user]]></item>
    <item id="_L/seccodecheck"><![CDATA[seccodecheck]]></item>
</item>
```

* \_G/dshowmessageParam 表示把 \$\_G\['dshowmessageParam'] 变量的内容映射到 API json 中 "msg" 这个 key 的内容中
* \_G/uid,username,groupid,groupname 表示把 \$\_G 的 uid、username、groupid、groupname 4个 key 的内容映射到 "user" 中
* \_L/seccodecheck 把，局部变量（通常在 class、function 内部）\$seccodecheck 的内容，映射到 "seccodecheck" 中

##### GET、POST 参数

GET、POST 为指定调用脚本具体的参数，例如

```xml theme={null}
<item id="get">
    <item id="mod"><![CDATA[logging]]></item>
    <item id="action"><![CDATA[login]]></item>
    <item id="loginsubmit"><![CDATA[yes]]></item>
</item>
<item id="post">
    <item id="fastloginfield"><![CDATA[username]]></item>
    <item id="username"><![CDATA[{:username:}]]></item>
    <item id="password"><![CDATA[{:password:}]]></item>
    <item id="formhash"><![CDATA[{:formhash:}]]></item>
</item>
```

当 value 为 `"{:xxx:}" `格式的时候，xxx 的内容为当前 API 接口的参数，需要调用方进行传参

`{:formhash:} `为系统参数，调用方无需额外传参

##### 参数说明

参数说明非必须，当您定义了多个 API 接口参数的时候，书写此说明文本，可以在 Discuz! 管理中心生成一个简单的接口说明文档

```xml theme={null}
<item id="usage">
    <item id="username"><![CDATA[用户名]]></item>
    <item id="password"><![CDATA[密码]]></item>
</item>
```

##### 接口属性

* validateData: 值为 1，有此属性时，表示调用接口需要验证数据的完整性。请求时需要在 Header 中发送 validatecode 字段，此字段的值为校验码，校验码算法如下，其中 \$post 为 json 后的参数

```php theme={null}
sha1($secret.$post)
```

* validateUnique: 有此属性时，表示调用接口需要验证唯一性，值传递唯一性值的有效期。请求时需要在 Header 中发送 uniqueid 字段，此字段的值为唯一串

包含以上属性接口的请求方法可参考范例中的 \_request() 方法

##### 过滤插件

过滤插件可以通过脚本对输出的数据进行额外的处理

```xml theme={null}
<item id="plugin">
    <item id="before">
        <item id="函数">
            <item id="param"><![CDATA[参数]]></item>
        </item>
        .....
    </item>
    <item id="after">
        <item id="函数">
            <item id="param"><![CDATA[参数]]></item>
        </item>
        ......
    </item>
</item>
```

插件分为 before、after 2类，before 会在调用脚本执行前被调用，after 会在脚本执行完毕后被调用

插件脚本的固定路径为 "source/plugin/pluginid/restful.class.php"，考虑到 before 会在调用脚本执行前被调用的缘故，此脚本可以不书写 "defined('IN\_DISCUZ')" 的判断

restful.class.php 是一个 class，您需要书写一个以下内容的脚本

```php theme={null}
<?php

class restful_pluginid {

    // pluginid:beforePlugin
    public static function beforePlugin(&$data, $param) {
        
    }

    // pluginid:afterPlugin
    public static function afterPlugin(&$data, $param) {
        
    }    

}

对于以上 2 个方法，函数填写的内容为 "pluginid:beforePlugin"、"pluginid:afterPlugin"

```

param 节点为函数参数，多个参数用逗号","分隔，param 的内容会传递给相应的静态方法，脚本中只需修改 \$data 的内容即可对相应输出变量进行处理，例如

```xml theme={null}
<item id="plugin">
    <item id="after">
        <item id="pluginid:thread">
            <item id="param"><![CDATA[forum_thread]]></item>
        </item>
    </item>
</item>

class restful_pluginid {

    // pluginid:thread
    public static function thread(&$data, $param) {
        global $_G;

        $key = $param[0];
        if(empty($data[$key])) {
            return;
        }

        //接口隐藏匿名
        if($data[$key]['authorid'] > 0 && $data[$key]['author'] === '') {
            $data[$key]['author'] = $_G['setting']['anonymoustext'];
            $data[$key]['authorid'] = 0;
        }
    }

}

```

可参考插件范例：[https://gitee.com/Discuz/DiscuzXPluginSample/tree/DZW](https://gitee.com/Discuz/DiscuzXPluginSample/tree/DZW)

## XML 的导入和更新

XML 写好后你可以用分享的形式将 XML 发布出去，用户在 "Discuz! 管理中心 > 站长 > RESTful 接口" 导入即可使用，多次导入会覆盖、更新旧版本。

### 添加更新源

您可以自己设计一个更新源的接口，接口直接吐出 XML 内容。然后，要让更新源生效，您可以在兼容 W1.0 版插件的安装脚本中补充以下 SQL。

```
INSERT INTO pre_restful_source (name, url) VALUES ('My Team', 'http://youapiurl');
```

## 接口的调用

使用前需要先创建一个应用，获取 appid 和 secret，并设置好权限。

### 全局参数

全局参数包含 4 个 appid、nonce、t、sign，请将此 4 个参数添加到请求的 Header 中

nonce 为唯一串，请保证唯一性，可用 uuid

t 为时间戳

sign 为签名，下面提供 2 个版本的签名算法

```php theme={null}
$sign = base64_encode(hash('sha256', $nonce.$t.$secret));
function getSign(nonce, t, secret) {
    let sha256 = CryptoJS.SHA256(nonce + t + secret).toString();
    let base64_sign = CryptoJS.enc.Base64.stringify(CryptoJS.enc.Utf8.parse(sha256));
    return base64_sign;
}
```

### 接口的请求

请求范例见 request\_sample.php。所有的接口参数都请通过 POST 提交。

"\_REQUEST" 是通用接口参数的名称，如接口参数未涉及到原脚本某些请求参数时，可用此通用参数，此参数为 json 字串，为以下格式：

```json theme={null}
{
    "GET": {
        "key": "value",
        ......
    },
    "POST": {
        "key": "value",
        ......
    },
    "COOKIE": {
        "key": "value",
        ......
    },
}
```

不涉及相关类型的请求参数时可忽略，比如不包含 POST、COOKIE 时可留空

#### 获取 Token

在获取所有其他接口前，您需要先获取 Token，Token
接口URL：`/api/restful/?/token`

请求参数：

* token: (可选)刷新 Token 时携带旧的 Token

返回参数：

```json theme={null}
{
    "ret": 0,
    "token": "LUIXE1DWBGQIQDSU",
    "expires_in": 1703911668
}
```

返回 token 和有效期，业务方可自行判断

#### 其他接口

获取到 Token 后，您可以把 Token 放入请求的 Header 中，也可以作为正常的全局参数带入，变量名为 "token"

具体接口的请求参数和返回参数视具体接口定义而定

#### restful 类常量说明

在 X5 的 class\_restful.php 中有以下 2 个常量，可酌情进行调整

```php theme={null}
const RESTFUL_REDIS_PREFIX = '';
const RESTFUL_DEVELOPER_MODE = false;
```

##### RESTFUL\_REDIS\_PREFIX:

Discuz! RESTful 默认使用 Redis 存储 API 数据，默认只支持一个站点，如果存在多个站点公用同一个 Redis 的情况，请在此处填写多个站的代号，避免 Redis key 冲突

##### RESTFUL\_DEVELOPER\_MODE

为了方便开发者本地开发自己的 API 接口，本地开发 API 时可以设置为 true。开发者只需调试 data/discuz\_restful.xml 文件，而无需反复在管理中心导入接口
