前言

在完成配置开源安卓QQ协议库Mirai后,便可使用已有开源项目来部署自己的QQ机器人,但自行开发显然更符合需求。借助mirai-api-http插件提供的接口,可以很方便的开发机器人,开发语言根据自己的意愿选择即可,这里以PHP为例。

配置Mirai-Api-Http插件

mirai-api-http插件将mirai-core-api的所有功能封装为http服务,提供的HTTP接口供所有语言使用mirai,从而大大的降低了开发门槛,使得开发QQ机器人更加容易和灵活。

关于mirai-api-http在Mirai生态中的作用可以看官方的Mirai生态介绍文档,文档详细介绍了Mirai的生态中各个框架和应用的关系,相信读完后会对Mirai生态有更为清晰的了解。

接下来配置mirai-api-http插件

如使用Mirai Console Loader启动mirai的话,可直接在mirai所在根目录执行

1
./mcl --update-package net.mamoe:mirai-api-http --channel stable --type plugin

其他方式也可以从Releases中手动下载放入”plugins”文件夹中。

以使用Mirai Console Loader为例,在mirai根目录执行以上命令后输入./mcl启动mirai,启动时会自行下载安装mirai-api-http插件,启动完成后会在”config/net.mamoe.mirai-api-http”目录下生成配置文件”setting.yml”,此时输入stop停止mirai,编辑该配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
# CORS跨域域名配置,默认允许所有域名
cors:
- '*'
# 地址,一般不需要改
host: 0.0.0.0
# 使用端口
port: 8080
# 认证Key
authKey: xxxxxxxxxx
# 缓存大小
cacheSize: 4096
# 是否开启websocket
enableWebsocket: false
# 消息上报配置
report:
# 总开关
enable: true
# 群消息上报
groupMessage:
report: true
# 好友消息上报
friendMessage:
report: true
# 临时消息上报
tempMessage:
report: true
# 事件上报
eventMessage:
report: true
# 上报URL
destinations:
- 'https://xxx.xxx.xxx'
# 上报时的额外Header
extraHeaders:
xxxxxx: xxxxxx

## 心跳(即每隔一段时间上报消息表明插件工作状态)
heartbeat:
# 总开关
enable: false
# 启动延迟
delay: 10
# 心跳间隔
period: 15
# 心跳上报URL
destinations: []
# 上报时的额外信息
extraBody: {}
# 上报时的额外头
extraHeaders: {}

注释中已包含对参数的说明,更详细的说明参考官方文档。其中”authKey”是与mirai-api-http接口认证的重要参数,”消息上报”是实现与QQ机器人互动的重要功能,”上报URL”是当消息上报时的上报地址,注意开放相应端口,配置完成后保存文件并重启mirai。

PHP实现QQ机器人

完成mirai-api-http插件配置后就能使用其提供的接口,通过向指定接口发送特定请求便能实现想要的操作,具体参考接口的详细文档

使用PHP开发首先需要能运行PHP的环境(以下代码需要PHP7以上),这里不多赘述。然后在Web服务器监听目录下新建文件Bot.class.php,编辑该文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
<?php

namespace Mirai;

use Exception;

/**
* Mirai QQ机器人
* @param string $_url MiraiHTTP接口地址
* @param string $_authKey Mirai认证Key
* @param string $_sessionKey Mirai会话Key
*/
class Bot
{
private $_url;
private $_authKey;
private $_sessionKey;

/**
* 构造函数
* @param string $url MiraiHTTP接口地址
* @param string $authKey Mirai认证Key
*/
function __construct(string $url, string $authKey)
{
$this->_url = $url;
$this->_authKey = array('authKey' => $authKey);
}


/**
* cURL获取数据
* @param string $url 发送请求的链接
* @param int $ifPost 是否为post请求(1||0)
* @param mixed $postFields post的数据
* @param string $cookie 发送请求携带的cookie
* @param mixed $cookieFile cookie文件
* @param int $ifHeader 是否获取响应头信息(1||0)
* @throws Exception 请求失败
* @return mixed 响应结果
*/
public function httpRequest(string $url, int $ifPost = 0, $postFields = '', string $cookie = '', $cookieFile = '', int $ifHeader = 0)
{
// 模拟http请求header头
$header = array(
"Connection: Keep-Alive",
"Accept: text/html, application/xhtml+xml, */*",
"Pragma: no-cache",
"Accept-Language: zh-Hans-CN,zh-Hans;q=0.8,en-US;q=0.5,en;q=0.3",
"User-Agent: Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; WOW64; Trident/6.0)"
);

// 初始化一个cURL会话
$ch = curl_init();

// 设置cURL传输选项
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HEADER, $ifHeader);
curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
$ifPost && curl_setopt($ch, CURLOPT_POST, $ifPost);
$ifPost && curl_setopt($ch, CURLOPT_POSTFIELDS, $postFields);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
$cookie && curl_setopt($ch, CURLOPT_COOKIE, $cookie); // 发送cookie变量
$cookieFile && curl_setopt($ch, CURLOPT_COOKIEFILE, $cookieFile); // 发送cookie文件
$cookieFile && curl_setopt($ch, CURLOPT_COOKIEJAR, $cookieFile); // 写入cookie到文件
curl_setopt($ch, CURLOPT_TIMEOUT, 60); // 允许执行的最长秒数
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);

// 执行cURL会话
$result = curl_exec($ch);

// 失败则抛出异常
if ($result === false) {
throw new Exception('Sending request to ' . $url . ' failed!');
}
// 关闭 cURL 会话
curl_close($ch);

// 释放$ch
unset($ch);

return $result;
}


/**
* 进行认证
* @throws Exception 认证失败
* @return bool
*/
public function auth(): bool
{
$url = $this->_url . '/auth';
$postData = json_encode($this->_authKey);
$response = json_decode($this->httpRequest($url, 1, $postData));
if ($response !== false && $response->code === 0) {
$this->_sessionKey = $response->session;
return true;
} else {
throw new Exception('Mirai authentication failed!');
}
}

/**
* 校验Session
* @param int $qq Session将要绑定的Bot的qq号
* @throws Exception 校验Session失败
* @return bool
*/
public function verify(int $qq): bool
{
$url = $this->_url . '/verify';
$postData = json_encode(
array(
'sessionKey' => $this->_sessionKey,
'qq' => $qq
)
);
$response = json_decode($this->httpRequest($url, 1, $postData));
if ($response !== false && $response->code === 0) {
return true;
} else {
throw new Exception('Validation session failed!' . 'The qq is ' . $qq . '.');
}
}

/**
* 释放Session
* @param int $qq 与该Session绑定Bot的QQ号码
* @throws Exception 释放Session失败
* @return bool
*/
public function release(int $qq): bool
{
$url = $this->_url . '/release';
$postData = json_encode(
array(
'sessionKey' => $this->_sessionKey,
'qq' => $qq
)
);
$response = json_decode($this->httpRequest($url, 1, $postData));
if ($response !== false && $response->code === 0) {
return true;
} else {
throw new Exception('Failed to release session! The qq is ' . $qq . '!');
}
}

/**
* 发送好友消息
* @param int $qq 发送消息目标好友的QQ号
* @param array $messageChain 消息链,消息对象构成的数组
* @param int $quote 回复消息的messageId
* @throws Exception 发送好友消息失败
* @return int messageId 可引用进行回复
*/
public function sendFriendMessage(int $qq, array $messageChain, $quote = null): int
{
$url = $this->_url . '/sendFriendMessage';
$postData = json_encode(
array(
'sessionKey' => $this->_sessionKey,
'target' => $qq,
'quote' => $quote,
'messageChain' => $messageChain
)
);
$response = json_decode($this->httpRequest($url, 1, $postData));
if ($response !== false && $response->code === 0) {
return $response->messageId;
} else {
throw new Exception('Failed to send friend message to qq:' . $qq . '!');
}
}
}

该类的方法实现了mirai-api-http所提供功能的一部分,包括认证身份、校验Session、释放Session和发送好友消息。其中属性”_authKey”便是插件配置文件中的”authKey”,重要参数和功能已在注释中说明,编辑完成后保存文件。

在相同目录下新建文件index.php,编辑该文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
<?php

namespace Mirai;

use Exception;

// 包含bot类
include_once("./Bot.class.php");

// 实例化一个bot
$bot = new Bot('MiraiHTTPAPI地址', 'Mirai认证Key');

// 机器人QQ
$botQQ = xxxxxxxxxx;
// 消息链
$message_chain = array(
array(
'type' => 'Plain',
'text' => 'HelloWorld!'
)
);
// 发送消息的目标QQ
$targetQQ = xxxxxxxxx;

try {
// 进行认证
$bot->auth();
// 校验Session
$bot->verify($botQQ);
// 发送该消息
$bot->sendFriendMessage($targetQQ, $message_chain);
// 释放Session
$bot->release($botQQ);
} catch (Exception $e) {
// 输出错误信息
echo $e->getMessage().' At file:'.$e->getFile().' on line:'.$e->getLine().'.';
// 发生异常时记录日志
error_log($e->getMessage() . ' At file:' . $e->getFile() . ' on line:' . $e->getLine() . '.');
}

以上代码实例化了一个Bot并向指定QQ好友发送了消息”HelloWorld!”,其中重要参数已在注释中说明。替换其中的“接口地址、认证Key、机器人QQ、目标QQ“,然后访问一次该文件,即可向指定QQ好友发送消息”HelloWorld!”。

完成以上实例就已经可以根据自己的需求开发QQ机器人了,仔细阅读API文档根据需求开发即可。

聊天机器人实例

这是一个QQ(智能)聊天机器人的实例,为了控制文章篇幅,实例转到地址:QQ聊天机器人实例

相关资料

基于Mirai的QQ机器人方案

开发 mirai QQ机器人起步教程

mirai-api-http文档参考

Mirai 生态中各个框架和应用的关系

最后

新手上路,如有错误请多指教。