PHP开发基于Mirai的QQ机器人

博客和更新地址:PHP开发基于Mirai的QQ机器人

前言

在完成配置开源安卓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 Console Loader启动mirai的话,可直接在mirai所在根目录执行

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

注意!以上方法下载的mirai-api-http插件为最新版2.x,2.x的api有所改动,本文章仅适合1.x版本,需手动下载!!!

请在Releases页面使用1.x的最新版,下载mirai-api-http-v1.xx.x.mirai.jar放入’pulgins’文件夹内。

如果已经使用了以上方法下载了2.x版本,请输入以下命令卸载:

.\mcl --remove-package net.mamoe:mirai-api-http

将1.x版本的’mirai-api-http’放入’pulgins’文件夹后输入./mcl启动mirai,启动完成后会在"config/net.mamoe.mirai-api-http"目录下生成配置文件"setting.yml",此时输入stop停止mirai,编辑该配置文件

# 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,编辑该文件

_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,编辑该文件

 '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 生态中各个框架和应用的关系

最后

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

你可能感兴趣的:(教程,php,mirai,qq,聊天机器人,经验分享)