Download the PHP package jx3dev/onebot-v11 without Composer

On this page you can find all versions of the php package jx3dev/onebot-v11. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.

FAQ

After the download, you have to make one include require_once('vendor/autoload.php');. After that you have to import the classes with use statements.

Example:
If you use only one package a project is not needed. But if you use more then one package, without a project it is not possible to import the classes with use statements.

In general, it is recommended to use always a project to download your libraries. In an application normally there is more than one library needed.
Some PHP packages are not free to download and because of that hosted in private repositories. In this case some credentials are needed to access such packages. Please use the auth.json textarea to insert credentials, if a package is coming from a private repository. You can look here for more information.

  • Some hosting areas are not accessible by a terminal or SSH. Then it is not possible to use Composer.
  • To use Composer is sometimes complicated. Especially for beginners.
  • Composer needs much resources. Sometimes they are not available on a simple webspace.
  • If you are using private repositories you don't need to share your credentials. You can set up everything on our site and then you provide a simple download link to your team member.
  • Simplify your Composer build process. Use our own command line tool to download the vendor folder as binary. This makes your build process faster and you don't need to expose your credentials for private repositories.
Please rate this library. Is it a good library?

Informations about the package onebot-v11

jx3dev/onebot-v11

OneBot V11 反向 WebSocket 服务端。多机器人接入、多 Worker 可用。

功能

目录

安装

配置

1. 加一个 WebSocket Server

config/autoload/server.php 的 servers 里追加:

需要「同一条连接的帧恒定落在同一个 Worker」——prompt() / capture() 的会话等待,以及冷却 #[Cooldown] / 互斥 #[Exclusive] 的 per-worker static 状态全靠它。

  • SWOOLE_BASE:天然满足(谁 accept 谁持有),dispatch_mode 在该模式下不生效。
  • SWOOLE_PROCESS:需要有连接亲和性的 dispatch_mode —— 2(按 fd,Swoole 默认,推荐)或 4(按 IP; 注意同一出口 IP 的多个机器人会全挤在同一个 Worker)。

别用 1(轮询)/ 3(抢占):它们把同一连接的帧打散到多个 Worker。Swoole 不报错也不警告、握手照样成功, 但事件会大面积丢失,上述功能静默失效。(开了 open_http2_protocol 时 Swoole 会在启动期拦下 1/3,但那是 http2 的守卫,不能指望它兜底。)

2. 注册路由

config/routes.php:

对端(go-cqhttp / NapCat / Lagrange / LLOneBot)的反向 WS 地址填 ws://<host>:9502/onebot/v11/ws。本包只处理 Universal 连接,不要用 API / Event 分离的那两个地址。

想在握手阶段就返回真 401(而不是升级后再断开),给路由挂 AccessTokenMiddleware:

挂了它,token 不对的连接在握手时直接收到 401、不会升级;不挂也有鉴权,只是退化成 onOpen 里「升级后关闭」。两者共用 access_token 配置。

3. config/autoload/onebot.php

配置项 默认值 说明
access_token '' 握手鉴权,留空不校验
call_timeout 30.0 call() 默认超时(秒)
disabled_classes [] 启动时不注册这些类的任何 #[Bot*] 注解(按类禁用整个插件),写 Foo::class
command_prefixes ['/', ''] #[BotCommand] 的 command/别名叠加的前缀
super_users '' 超级管理员 QQ。.env 的 ONEBOT_SUPER_USERS 单个或逗号分隔多个;也可写数组 [1243, 1122]
nicknames '' 机器人昵称。以昵称开头(小明 天气)算「叫我」、剥掉后再匹配命令;.env 的 ONEBOT_NICKNAMES 单个或逗号分隔,或数组
log 见 日志 内置日志开关:log.events(收包)/ log.commands(完成)默认 true

同时在线机器人的容量写死在 ConnectionRegistry::MAX_BOTS(4096,约 1~2MB 共享内存),运行期不可扩容;真有超过的极端需求,改常量重启即可。

或者:复用已有的 HTTP server

不想多开端口的话,把骨架里现有的 http server 的 type 改成 SERVER_WEBSOCKET,在原有的 ON_REQUEST 之外补上三个 ws 回调,同一个端口就能同时跑 HTTP 和 WS:

这种情况下路由不用 addServer 包一层 —— Router 的默认 server 名就是 http,顶层注册即可:

注意这条路径同时也会被 HTTP 路由表命中:不带 Upgrade: websocket 头去访问它会走到 onRequest,把 WebSocketController 当普通控制器调其 __invoke()。控制器已实现该方法,对这类请求抛 HttpException(426, 'Upgrade Required'),由你 app 的异常处理器渲染(需注册 HTTP 异常处理器)。

写第一个命令

任意类的方法挂上 #[Bot*] 注解即可,无需继承、无需注册——启动时自动扫描收集。

注解总览

全部注解在 OneBot\Annotation 命名空间下。带 ★ 的可重复(一个方法可挂多个)。

注解 作用 handler 收
#[BotCommand] ★ 命令:前缀词 / 正则 + 作用域 / 权限 CommandContext
#[BotMessage] 消息事件糖,按 message_type.sub_type 收窄 BotContext
#[BotNotice] 通知事件糖 BotContext
#[BotRequest] 请求事件糖 BotContext
#[BotMetaEvent] 元事件糖(心跳 / 生命周期) BotContext
#[BotEvent] 匹配所有事件(分发最后一层) BotContext
#[BotEventBefore] 三层主 handler 之前 BotContext
#[BotEventAfter] 三层主 handler 之后(finally 语义) BotContext
#[BotCommandBefore] 全局命令前置(guarded 定位权限前/后) CommandContext
#[BotCommandAfter] 全局命令后置 CommandContext
#[BotActionBefore] 每次 API 调用发出前(可改参 / abort()) ActionContext
#[BotActionAfter] 每次 API 调用收到响应后 ActionContext
#[BotException] ★ 按异常类型分派处理 ExceptionContext
#[BotMiddleware] ★ 给事件 handler 挂中间件(类级 / 方法级) —(作用于上面各事件类 handler)
#[BotConnect] 机器人连接建立后 ConnectionContext
#[BotDisconnect] 机器人连接断开后 ConnectionContext
#[BotServerStart] fork 前、主进程一次 参数按类型注入
#[BotWorkerStart] 每个 Worker 启动后各一次 参数按类型注入

所有事件类注解都带 priority(大者先执行,只在同层内比较)。

事件路由与分层

一条事件按类别分三层,按先后跑,三层默认都执行(分层只定先后、不互相兜底):

四个事件糖(#[BotMessage] / #[BotNotice] / #[BotRequest] / #[BotMetaEvent]):type 是点分二级 二级类型.三级类型 ,留空匹配该类全部:

#[BotEvent(type)]:type 是点分三级 post_type.二级.三级,如 message、message.group、notice.notify.poke ,留空匹配全部事件。#[BotEventBefore] / #[BotEventAfter] 同样按这个三级 type 收窄。

命令 #[BotCommand]

命令是消息事件的细化:先按消息事件筛,再按下面规则命中。可重复(一个方法多条命令,任一命中即以该命令跑)。

参数 说明
name 主命令词,叠加全局前缀(command_prefixes,如 ['/', ''] 则 /help 和 help 都中)
alias name 的别名,同样叠加前缀
regex 正则;完全 /^x$/、前缀 /^x/、后缀 /x$/、包含 /x/、忽略大小写 /x/i。具名捕获进 args()->param(name),编号捕获进 args()
scope 限定 'group' / 'private',留空不限
toMe 仅「叫我」才命中:私聊一律算;群里要 @我 或以昵称开头
permission 权限(OR),见下
denyReply 权限不满足时回的一句话;留空静默
priority 同层优先级

name 与 regex 是「或」:任一命中即算命中;都留空则不匹配任何消息(启动时会打一条 warning,多半是漏填命令词)。匹配用消息纯文本( extractPlainText,已滤掉 at/image 等非文本段)。

name / alias 不能含空白:首尾空白(含全角空格)会自动清掉,内部还含空白(多词)的命令词永远匹配不上、启动时会打一条 warning——多词匹配请用 regex。

命令参数 Args

非命令 handler 参数类型写 BotContext 即可。

权限

permission 是 OR 逻辑,任一通过即命中,不满足则静默不命中。内置名用 Permission::* 常量(super 看 super_users 配置; owner/admin/member 看群消息的 sender.role,admin 含群主),可与自定义 PermissionInterface 类混用:

被拒默认静默。想回一句:注解加 denyReply(检查器里 stop() 了则不发),或方法里用 $ctx->isSuper() / isOwner() / isAdmin() / senderRole() 自行处理。

重定向命令 runCommand() / hasCommand()

让 handler 把当前消息手动转给某条命令执行,走完整命令管线(权限 + 中间件 + 命令前后置):

钩子

事件前后置 #[BotEventBefore] / #[BotEventAfter]

在三层之外:before 在所有主 handler 前、after 在所有之后(after 同 finally,始终执行)。#[BotEventBefore] 排在会话拦截 (prompt() / capture())之前,是真正「每一条消息都过」的全局闸门——即便某个会话正活着、这条消息将被 prompt / capture 收走,前置也照跑;在前置里 stop() 就彻底拦下:消息既不投给会话、也不进命令层(黑名单 / 全局限流 / 埋点靠的就是这个)。也能 像 BotEvent 一样按三级 type 收窄(#[BotEventBefore('message.group')] 只在群消息前跑)。

分层放对地方:#[BotEventBefore] 放便宜的全局闸门(查缓存黑名单、敏感词),它对每条消息都跑、包括多轮问答 / 接龙里的 每条答案;贵的富化(查群信息 / 群成员、setTemp() 预备数据)放 #[BotCommandBefore],只在命令真命中时才跑,别让每条闲聊都付这个代价。

「便宜」还有个时序理由:前置链排在会话投递之前,链里任何一个 await 都会推迟消息送到挂起的 prompt() / capture()、 吃掉它的超时预算——极端情况那句回答会因 prompt 已超时清理而落回常规分发、甚至误触命令。另外,想「无论如何都跑」的收尾 / 埋点别靠调低 priority(高优先级前置 stop() 会让低优先级的整个不跑),放 #[BotEventAfter],它不受 stop() 影响。

命令前后置 #[BotCommandBefore] / #[BotCommandAfter]

对所有命令统一生效(不用逐个挂中间件)。guarded 决定前置落在权限检查的哪一侧——权限检查正夹在两组前置中间:

API 钩子 #[BotActionBefore] / #[BotActionAfter]

包在每次 call() / callRaw() 外:action 留空匹配全部,填具体 action(如 send_group_msg)只匹配该调用。before 能改参数( setParams()),after 能读响应(getResponse())。它们挨个执行、无法用 stop 阻断。

before 里可用 abort() 短路这次调用——不碰网络,直接用你给的响应走完 after 和成功校验:

abort() 切断剩余的 before 钩子;after 照常执行(用 $ctx->isAborted() 区分是不是短路来的)。

异常 #[BotException]

按异常类型分派,只兜分发链路内(事件 handler、中间件、事件解析、连接钩子、action 钩子)抛出的异常;分发链路之外自己调 call()(定时任务、控制器里)抛的不归它管,请自行 try/catch。

$exception 指定要接的异常类型(含子类),默认 Throwable 兜底全部。一次异常会通知所有类型匹配的 handler(按 priority 依次执行、互不影响)——全局 logger 与具体处理器可共存。可重复:

#[BotEventAfter] 里可用 $ctx->exceptions() 拿到本次事件被捕获的所有异常(list<Throwable>),做统一成功/失败统计。

连接钩子 #[BotConnect] / #[BotDisconnect]

机器人连接建立 / 断开后触发,handler 收 ConnectionContext。断开时连接已断,勿再发消息。

生命周期 #[BotServerStart] / #[BotWorkerStart]

方法参数按类型注入(声明对应事件就拿事件、声明任意 DI 服务就注入它,顺序随意,不要就空着):

HandlerRegistry::addAlias(string $commandName, array $aliases): int:给已注册命令追加别名,等价于注解里的 alias ,只是启动时动态加(可从配置 / 数据库来)。返回实际新增的别名数(0 = 命令不存在、全重复、或都含空白被跳过)。重复自动去重;别名同样不能含空白(首尾自动清、内部含空白的跳过不计);正则命令没命令词、无法加别名。

⚠ 两个钩子都每次触发各跑一遍;共享 Swoole\Table 只能在 #[BotServerStart](fork 前)建;钩子里抛异常只记日志、不影响其余。

中间件

#[BotMiddleware]

给事件 handler 挂中间件,可用在类上(该类所有事件 handler)或方法上(只该方法),可重复。执行顺序:类级先于方法级,同级按书写顺序。 $middleware 是实现 MiddlewareInterface 的类名,$args 作为构造参数经容器 make() 注入。

中间件的 process() 收 BotContext,因此只对「事件类」handler 生效——#[BotMessage] / #[BotNotice] / #[BotRequest] / #[BotMetaEvent] / #[BotEvent] / #[BotCommand],以及四个事件/命令前后置。挂在连接钩子 / action 钩子上不生效也不报错 ,请勿这么挂。

内置:冷却 #[Cooldown] / 互斥 #[Exclusive]

两个开箱即用的命令中间件,都是 #[BotMiddleware] 的类型化子类注解,挂命令上即用。

冷却 #[Cooldown]:

互斥 #[Exclusive](同 key 的命令不并发、一次一个,后到的排队):

两维分桶(共用 ScopedBucket):scope 定「谁和谁共享」、key 定「哪些命令共享」。

⚠ 于是类级 #[Cooldown] / #[Exclusive] 挂在有多个方法的类上,是每个方法各自一桶、不是全类共享(默认桶按 类::方法 区分)。想全类共享,显式给同一个 key。

状态存 static、per-worker(同一条连接恒定落同一 Worker,无需 Table,见 配置)。想自扩展(令牌桶限流、递增冷却的变体…),照这俩: class X extends BotMiddleware implements MiddlewareInterface { use ScopedBucket; ... },process() 里 $this->bucket($ctx, $this->scope, $this->key) 拿桶键写自己的逻辑(extends BotMiddleware 后靠 IS_INSTANCEOF 自动被收)。

主动调用 API:call / send / 群发 / 定时任务

从任意 DI 服务里注入 BotManager 取 bot:

call() / callRaw()(要等响应)

API 一律不做封装,只有 call() / callRaw();协议里的 action 也可通过 __call() 用驼峰直接调(转成 snake_case),Bot 类顶部的方法注解仅供 IDE 补全。

call() 返回响应里的 data,callRaw() 返回完整响应体。两者都要等对端响应,只能在 Worker / Task Worker 里调用。

send()(即发即忘)

不关心返回、或要在自定义进程里调,用 send()——即发即忘、返回 bool、任意进程可用:

群发

send() 任意进程可用,天然适合群发。给所有在线 bot 的某个目标发:

要发到某个 bot 的所有群,先取群列表(call(),需在 Worker / Task Worker 里)再逐个 send():

定时任务

本包不含定时器;在 Hyperf 里用 hyperf/crontab(或自定义进程 AbstractProcess )驱动,任务体里推送用 send()——最稳、任意进程可用:

上下文 BotContext

事件 handler 收到的 $ctx。命令 handler 收 CommandContext(BotContext 子类,多一个 args())。

身份与消息查询

回复

⚠ 裸字符串一律当纯文本发:reply() / finish() / prompt() 收到 string 时,里面的 CQ 码([CQ:at,qq=all]、 [CQ:image,...])不解析——所以把用户可控文本(群名片、echo 参数…)直接 reply() 是安全的,不会被诱导 @全体 / 发任意卡片。真要发 at / 图片,用段构造器(Segment::at(...))或 Message;真要按 CQ 串解析(罕见),显式 Message::fromCQ($s)。入站消息不受影响,仍按 CQ 解析成 at / image 等段。

会话:多轮追问 prompt() / 捕获 capture()

同一个人 / 群的后续消息,不用再靠命令绕:

会话等待是纯本地的(本地 Channel),依赖「同一条连接恒定落同一 Worker」。反向 WS 每端一条连接, SWOOLE_BASE 天然满足、SWOOLE_PROCESS 在 dispatch_mode 为 2/4 时满足;换成打散分派的 1/3, prompt/capture 会静默等不到。见 配置。

临时数据

事件内跨 handler / 中间件共享(区别于 field() 读的原始 payload):

停止分发 / 切换机器人

替换上下文 / 机器人对象

想给上下文加方法、或给 call()/send() 包一层限速/重试/日志:继承 → 写工厂 → dependencies.php 重绑,无需改本包。

之后 $bots->get() / $ctx->bot() / handler 里的 $ctx 都是你的子类(类型标注仍写 BotContext / Bot,子类满足)。

消息段 Segment / Message

reply() / call() 的 message 字段收 string(走 CQ 码解析)、Segment、Message 或段数组,都会归一。构造段:

异常与日志

异常

异常 触发时机
BotNotFoundException 目标 self_id 不在线
ConnectionException 帧没能写进连接
ApiTimeoutException 超时未收到响应
ApiCallException 对端返回 status=failed,带 retcode 和原始响应

都在 OneBot\Exception 下,共同基类 OneBotException。注意 status=async(_async 后缀调用返回的 retcode=1)是「已受理」, 不会抛异常。分发链路里的异常交给 #[BotException](见上)。

日志

内置三类,走 onebot channel(正文前缀 [onebot]),格式 / 级别 / 去向在 config/autoload/logger.php 调:

多 Worker 原理与已知限制

不用 Redis,靠两样东西:

  1. 连接注册表建在 Swoole\Table(共享内存)上,由 CreateRegistryListener 在 Master fork 之前创建,每个 Worker 看到同一份 self_id -> fd 映射。
  2. 下行推送直接用 Hyperf 的 Sender(自带跨 Worker 的 fd 代理);上行响应把 workerId 编进 echo( php.{workerId}.{随机串}),响应帧落在连接所属 Worker,解出前缀后用 sendMessage 回投给真正挂起的那个 Worker。

已知限制

测试

协程相关用例需要 ext-swoole(没装则自动跳过)。覆盖消息段与 CQ 码互转、命令匹配(前缀 / 别名 / 正则 / 作用域 / 权限)、冷却与互斥中间件(含高并发下的原子性与上限不超卖)、call / send 与成功判定、会话 prompt / capture、上下文与分发管线。

许可

MIT


All versions of onebot-v11 with dependencies

PHP Build Version
Package Version
Requires php Version >=8.2
hyperf/contract Version ^3.2
hyperf/di Version ^3.2
hyperf/framework Version ^3.2
hyperf/logger Version ^3.2
hyperf/websocket-server Version ^3.2
Composer command for our command line client (download client) This client runs in each environment. You don't need a specific PHP version etc. The first 20 API calls are free. Standard composer command

The package jx3dev/onebot-v11 contains the following files

Loading the files please wait ...