侧边栏壁纸

PHP搭建QQ机器人(QQ官方)

2024年10月20日 940阅读 12评论 4点赞

52-1

QQ官方机器人简介:

1.消息通知给开发者使用websocket服务
2.发送消息,使用openapi即http
3.官方只给了go和node.js的SDK,没有PHP的
4.官方文档: https://bot.q.qq.com/wiki/develop/api/
5.再主动发送消息数量有限制,不同机器人数量不同
6.公域机器人,即其他人搜索即可添加到自己的频道或群,主动发送消息每日数量很少,好像每日就几条
7.私域,即需要开发者设置允许哪个频道或群添加,才能使用。主动消息数量较多,好像调整到了每日100。
8.被动回复消息都不限量
9.准备看下面更凌乱的内容 表情

开发参考:

在gitee找到的一个的例子,其他没找到 阿巴叭叭叭 / QbotPHP /

程序介绍:

使用phrity/websocket库搭建websocket服务
本来想用ratchet,一直报错,没整正常

安装要求:

1.PHP > 8.0
2.composer
3.phrity/websocket 版本大于等于2.0

安装步骤:

1.机器人目录(自定义)下新建 composer.json文件,输入

{
   "require": {
       "phrity/websocket": "^2.0"
   }
}

2.打开ssh,进入机器人目录,输入命令 composer install 回车执行
3.在机器人目录新建GuildSocket.php文件


<?php

use WebSocket\Client;
use WebSocket\Connection;
use WebSocket\Message\Message;
use WebSocket\Middleware\PingResponder;

class GuildSocket
{
    private $qqGuildUrl = '';
    private $appId = '';
    private $token = '';
    private $appSecret = '';
    private $access_token = '';
    private $expires_in = '';
    private $guzzleOptions = [];
    private $s = '';
    private $session_id = '';
    private $time0 = 0;
    private $seconds = 0;
    
    /**
     * 设置最大执行时间设置为无限制
     * 设置内存限制设置为无限制
     * 初始化参数
     * 
     */
    public function __construct(String $qqGuildUrl, String $appId, String $token, String $appSecret, Array $guzzleOptions)
    {
        
        set_time_limit(0);
        ini_set('memory_limit','-1');
        $this->qqGuildUrl = $qqGuildUrl;
        $this->appId = $appId;
        $this->token = $token;
        $this->appSecret = $appSecret;
        $this->guzzleOptions = $guzzleOptions;
        
    }

    /**
     * @param $token
     * @return mixed
     * 获取Gateway
     */
    private function getGateway(String $token): string
    {
        return "wss://sandbox.api.sgroup.qq.com/websocket";
    }
    
    /**
     * @param $url  请求地址
     * @param  $method  请求方法
     * @param  $param  请求参数
     * @param  $headers  请求头
     * 构造HTTP请求
     * 
     */
    private function httpRequest($url, $method = "POST", $param = "", $header = [])
    {
    
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);
        curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $param);
        $response = curl_exec($ch);
        curl_close($ch);
        $response = json_decode($response, true);
        
        return $response;
        
    }
    
    
    /**
     * 获取openapi的调用凭证access_token
     */
    private function getSendMsgToken()
    {
        
        $param = [
            "appId"=> $this->appId,
            "clientSecret"=> $this->appSecret
            ];
        $token = $this->httpRequest("https://bots.qq.com/app/getAppAccessToken", "POST", json_encode($param), ['Content-Type: application/json']);
        
        if(!empty($token['access_token'])) {
            
            // 更新token及token失效时间
            $this->access_token = $token['access_token'];
            $this->expires_in = $token['expires_in'] + time();
            echo("\033[32m[消息发送token更新]\033[0m\n" . $token['access_token'] . "\n\n");
            
        }
        
    }

    /**
     * @param String $token
     * @param Client $client
     * @return String
     * WS身份验证,返回SessionID
     */
    private function idVerify(String $token, Client $client): string
    {
        $data = [
            'op' => 2,
            'd' => [
                'token' => "Bot " . $this->appId . "." . $this->token,
                'intents' => 2081166851,
                'properties' => []
            ]
        ];
        $client->text(json_encode($data));
        
        $receive = $client->receive()->getContent();
        
        $session_id = json_decode($receive, true)['d']['session_id'];
        
        echo("\033[32m[身份鉴权完毕]\033[0m\n session_id:" . $session_id . "\n\n");
        
        return $session_id;
    }

    /**
     * 建立WS连接
     */
    public function connect()
    {

        //获取WS连接路径
        $gateway = $this->getGateway($this->token);

        //创建连接
        $this->s = '';
        
        $client = new Client($gateway);

        // //获取心跳间隔
        $this->seconds = intval($this->getHeartBeat($client));
        echo("\033[32m[连接成功]\033[0m\n心跳间隔:" . $this->seconds . "\n\n");
        
        //身份鉴权
        $this->session_id = $this->idVerify($this->token, $client);
        
        // 获取发送消息鉴权token
        $this->getSendMsgToken();
        
        //首次心跳
        $this->time0 = time();
        $client->text(json_encode(['op'=>1, 'd'=>null]));

        // //消息监听
        $client->setTimeout($this->seconds)
            // Add standard middlewares
            ->addMiddleware(new PingResponder())
            // Listen to incoming Text messages
            ->onText(function (Client $client, Connection $connection, Message $message) {
                
                //将消息转换为数组
                $receiveArr =json_decode($message->getContent(), true);

                //如果op存在
                if (isset($receiveArr['op'])){

                    //排除心跳pong
                    //if($receiveArr['op']!=11){}

                    //如果是服务端推送,将消息派发到队列处理
                    if($receiveArr['op']==0){
                            
                        // 写入最新消息识别码s
                        $this->s = $receiveArr['s'];
                        echo("\033[34m[收到消息]\033[0m\n" . $receiveArr['d']['content'] . "\n\n");
                        
                        // 传递消息给消息处理类
                        GuildMessage::msgDispatch($this->qqGuildUrl, $this->appId, $this->access_token, $receiveArr);
                        
                    }

                    //如果服务端通知重连
                    if($receiveArr['op'] == 7){
                        
                        $client->text(json_encode(['op'=>6, 'd'=>['token'=>"Bot ".$this->appId.".".$this->token, 'session_id'=>$this->session_id, 's'=>$this->s]]));
                        
                    }

                }


            })
            ->onTick(function (Client $client){
                
                //检测是否到心跳时间
                $time1 = time();
                if($time1 - $this->time0 > $this->seconds - 20){
                    $client->text(json_encode(['op'=>1, 'd'=>$this->s]));
                    echo("\033[32m[心跳成功]\033[0m\n消息识别码(s):" . $this->s . "\n\n");
                    $this->time0 = $time1;
                };
                
                // 更新openapi调用鉴token
                if($this->expires_in - $time1 < 60) {
                    $this->getSendMsgToken();
                }

            })
            ->onError(function (Client $client){
                //重新连接
                $client->text(json_encode(['op'=>6, 'd'=>['token'=>"Bot ".$this->appId.".".$this->token, 'session_id'=>$this->session_id, 's'=>$this->s]]));
            })
            ->start();

    }

    /**
     * @param $client
     * @return float
     * 获得心跳时间
     */
    public function getHeartBeat($client)
    {
        
        $receive = $client->receive()->getContent();
        $initReceive = json_decode($receive, true);
        return floor($initReceive['d']['heartbeat_interval']/1000);
        
    }
  
  
}

4.新建

qBot.php

文件


<?php

require './vendor/autoload.php';

// websocket服务管理类
require "GuildSocket.php";
// 消息处理类
require "GuildMessage.php";
// phrity/websocket库,要求2.0以上版本
use WebSocket\Client;

$qqGuildUrl='https://sandbox.api.sgroup.qq.com';  // 沙盒环境接口
// $qqGuildUrl='https://api.sgroup.qq.com';  // 正式环境接口

$appId = "";  // QQ机器人ID
$token = '';  // 机器人toekn
$appSecret = "";  // 机器人密钥
$guzzleOptions = ['verify' => false];

$guild = new GuildSocket($qqGuildUrl, $appId, $token, $appSecret, $guzzleOptions);

$guild->connect();

5.创建文件

GuildMessage.php

这个文件是消息处理文件


<?php

/**
 * 消息处理类
 */
class GuildMessage
{
    
    /**
     * 接收消息
     * 
     */
    public static function msgDispatch(String $qqGuildUrl, String $appId, String $access_token, Array $receiveArr) {
        
        // 事件类别
        $eventType = $receiveArr['t'];
        // 消息内容
        $receiveMsgArr = $receiveArr['d'];
        // 构建发送子频道消息接口
        $postUrl = $qqGuildUrl . "/channels/" . $receiveMsgArr['channel_id'] . "/messages";
        // 构建回复消息
        $sendMsgArr = [
            "msg_id"=> $receiveArr['id'],
            ];
        
        $content = '';
        
        // @机器人的消息处理
        if($eventType == "AT_MESSAGE_CREATE") {
            
            $content =  self::msgAtBot($receiveMsgArr);
            
        }
        
        if(!empty($content)) {
            
            $sendMsgArr['content'] = $content;
            $headers = [
                  'Authorization: QQBot ' . $access_token,
                  'X-Union-Appid: ' . $appId,
                ];

            // 发送消息
            self::httpRequest($postUrl, "POST", json_encode($sendMsgArr), $headers);
            
            echo("\033[34m[发送消息]\033[0m\n".$content."]\n\n");
            
        }
        
    }
    
    
    /**
     * @机器人消息处理事件
     * return 返回消息内容(文本消息)
     * 
     */
    private static function msgAtBot(Array $receiveMsgArr) {
        
        // 消息内容
        $msgContent = preg_match('/<@!.*?>\s*(.*)/', $receiveMsgArr['content'], $matches);
        $msgContent = $matches[1];
        
        $content = self::httpRequest("https://api.lolimi.cn/API/AI/wx.php?msg=" . $msgContent, "GET")['data']['output'];
        
        return $content;
        
    }
    
    
    /**
     * 构建http请求
     * 
     */
    private static function httpRequest($url, $method = "POST", $param = "", $headers = array()) {
        
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);
        curl_setopt($ch, CURLOPT_HTTPHEADER, array_merge($headers, ['Content-Type: application/json']));
        curl_setopt($ch, CURLOPT_POSTFIELDS, $param);  
        $response = curl_exec($ch);
        curl_close($ch);
        
        $response = json_decode($response, true);
        return $response;
        
  }
    
}

6.配置qBot.php文件内信息即可
7.ssh进入机器人文件夹下,执行命令php qBot.php,即可运行

使用说明:

1.消息处理只给了一个简单例子,自行添加修改即可
2.webscoket库一定要大于等于2.0版本
3.PHP版本要大于等于8.0
4.PHP安装fileinfo拓展

持续运行机器人:
ssh执行命令screen -S qqbot php qBot.php

4
打赏

—— 评论区 ——

昵称
邮箱
网址
取消
  1. 头像
    mostbet opinie
    Windows 10 x64 Edition   Google Chrome 114
    回复

    Interfejs aplikacji jest intuicyjny i dostosowany do ekranów różnej
    wielkości, co zapewnia komfortową rozgrywkę na każdym
    urządzeniu.

  2. 头像
    taya 365 app
    GNU/Linux x64   Opera 89
    回复

    Use Taya365 bonuses for maximum victories
    taya 365 app
    Get started your journey to big rewards at Taya365. With a variety of games
    to choose from, including sports betting, there’s always something new to try.
    Join now and start scoring!
    taya365 app casino

  3. 头像
    pin up casino aviator
    Windows 10 x64 Edition   Firefox 114
    回复

    Always available support – we’re ready to help! If you have any questions,
    the Pin-Up Casino support team is always ready. Contact us
    via chat, email, or Telegram for fast help and solutions to your issues.

    pin up casino aviator
    Pin-Up Casino Free spins rewards: A True Game-Changer?
    Free spins are one of the top methods to gain an advantage without betting
    your own money. Pin-Up Casino offers these as part of its incentives, and I’ve had some pretty good luck.

    What about you? Have you taken advantage of the free spins to collect some massive rewards?

    Let us know your story!

  4. 头像
    old bet9ja
    Windows 10 x64 Edition   Google Chrome 114
    回复

    Claim Your 150% Welcome Bonus with Bet9ja Today!
    old bet9ja
    Looking for a simple betting experience? Access the Bet9ja Old Mobile version and
    enjoy fast loading times and easy navigation. Bet on soccer, casino games, and virtual races without the distractions of
    the new version. Start betting in minutes!
    old bet9ja

  5. 头像
    pin up casino
    Windows 10 x64 Edition   Microsoft Edge
    回复

    Süper bonuslar ve slot oyunlarıyla Pinco Casino'yu keşfedin!
    pin up casino

    Pinco Casino, spor bahisleri ve daha fazlasını sunan bir platformdur.
    Özel bonuslarla hemen katılın ve kazanmak için şansınızı deneyin!
    pinco ne demek

  6. 头像
    AmandaAncese1
    Windows 7 x64 Edition   Google Chrome 103
    回复

    让我们看看我们今晚能走多远 - https://rb.gy/es66fc?Kenlywet

  7. 头像
    GeorgeSox
    Windows 10 x64 Edition   Google Chrome 130
    回复

    Ողջույն, ես ուզում էի իմանալ ձեր գինը.

  8. 头像
    AmandaAnceseb
    Windows 10 x64 Edition   Google Chrome 103
    回复

    让我们看看我们今晚能走多远 - https://rb.gy/es66fc?Kenlywet

  9. 头像
    TAYA365 customer support
    Windows 10 x64 Edition   Opera 89
    回复

    أنا ألعب 1xbet مصر – دون مشاكل ومربح!
    السحب فوري دائماً! TAYA365 customer support

  10. 头像
    AmandaAncesea
    Windows 8.1 x64 Edition   Google Chrome 103
    回复

    让我们看看我们今晚能走多远 - https://rb.gy/es66fc?Kenlywet

  11. 头像
    flsrpmfzec
    Windows 10 x64 Edition   搜狗高速浏览器
    回复

    建议补充发展中国家案例,避免视角局限。

  12. 头像
    Bônus Pagbet
    Mac OS X 12.5   Safari 15
    回复

    أفضل كازينو – 1xbet Egypt! احتمالات ربح مرتفعة ومكافآت ضخمة!
    Bônus Pagbet

人生倒计时
舔狗日记

海云博客公告

海云博客、云服务、API、霹雳霹雳、百宝箱、LGZ、影视、卡密网等由于特殊原因将于2025年3月-6月末暂时停更停维护



博客先这样吧,在搞子比很快就好了
欢迎!
一天只弹一次
朕已阅

Warning: Invalid argument supplied for foreach() in /www/wwwroot/mnbt.20739403/usr/plugins/Clogin/Plugin.php on line 158