pdahal / php-xmpp
基于 `xmppo/xmpp-php` 的 PHP XMPP 库
Requires
- php: >=8.2
Requires (Dev)
- friendsofphp/php-cs-fixer: ~3.64
- phpmd/phpmd: ~2.15
- phpunit/phpunit: ~11.0
- rector/rector: ~1.2
- squizlabs/php_codesniffer: ~3.10
This package is not auto-updated.
Last update: 2024-09-28 10:58:20 UTC
README
此库基于 xmppo/xmpp-php
这是由于网上缺少此类库(至少是我能找到的具有良好文档的库),所以这是 PHP 与 XMPP 通信的低级别套接字实现。
XMPP 核心文档可以在 这里 找到。
使用
您可以在 Example.php
文件中查看使用示例,通过更改凭据指向您的 XMPP 服务器,然后在项目根目录下运行 php Example.php
。
库使用
初始化
为了开始使用此库,您首先需要创建一个新的 Options
类实例。主机、用户名和密码是必填字段,如果省略端口号,则默认为 5222
,这是 XMPP 的默认端口号。
用户名可以是裸 JID
或 JID/resource
形式。如果您使用裸 JID
,则资源将被自动添加。您可以通过使用 $client->iq->setResource()
显式设置资源来覆盖此操作。在第二种情况下,用户名将被自动解析为 username
和 resource
变量。在 JID/resource/xyz
格式的情况下,第二个斜杠之后的所有内容将被忽略。如果同时存在 JID/resource
以及使用 $client->iq->setResource()
方法,则最后定义的将具有优先权。
$options = new Options();
$options
->setHost($host) // required
->setPort($port) // not required, defaults to 5222
->setUsername($username) // required
->setPassword($password); // required
Options
对象对于建立连接和后续请求是必需的,因此一旦设置,就不应该更改。
设置此对象后,您可以创建一个新的 XmppClient
对象并将 Options
对象传入。
XMPP 客户端类说明
由于 XMPP 全部关于 3 个主要报文(IQ、消息和 Presence),我创建了依赖于套接字实现的单独类,以便您可以直接通过调用报文方法发送 XML。
这意味着从 XmppClient
类构造函数中提供了 3 个报文,以便像在客户端的特定类上使用链式方法一样使用。
当前逻辑是 $client->STANZA->METHOD()
。例如
$client->iq->getRoster();
$client->message->send();
$client->presence->subscribe();
连接到服务器
除了作为报文包装器外,XmppClient
类还提供了一些公开方法。
$client->connect()
方法执行以下操作
- 连接到在
XmppClient
构造函数中初始化的套接字 - 打开与 XMPP 服务器的 XML 流进行交换
- 根据提供的凭据尝试与服务器进行身份验证
- 开始与服务器进行初始通信,这是您开始所需的最低限度
当前版本支持 PLAIN
和 DIGEST-MD5
身份验证方法。
默认支持 TLS。如果服务器支持 TLS,库将自动尝试使用 TLS 连接并使连接安全。
如果您想显式禁用此功能,可以在 Options
实例上使用 setUseTls(false)
函数来禁用 TLS 通信。请注意,这将在支持 TLS 但不是必需的环境中起作用。如果 TLS 是必需的,程序将独立于您设置的选项连接到它。
发送原始数据
send()
消息在 XmppClient
类中公开,其目的是将原始 XML 数据发送到服务器。为了正确工作,您发送的 XML 必须是有效的 XML。
获取原始响应
服务器响应(或更确切地说是服务器端的连续XML会话)可以通过$client->getResponse()
获取。这应该用于无限循环或在一些WebSocket解决方案中,如Ratchet中,如果您想看到来自服务器的连续数据流。
如果您想在控制台看到接收到的响应的输出,可以调用$client->prettyPrint($response)
方法。
接收消息和其他响应
如果您不感兴趣于从服务器接收到的完整响应,您也可以使用$client->message->receive()
($client->getMessages()
已被删除,因为它只是此方法的简写)来匹配消息标签与正则表达式,并返回匹配的消息数组。如果您想在终端看到响应,可以这样做
do {
$response = $client->message->receive();
if($response)
echo print_r($response);
} while (true);
断开连接
断开连接方法向服务器发送关闭XML,结束当前打开的会话,并关闭打开的套接字。
Stanza方法分解
记得从这里 -> $client->STANZA->METHOD()
消息
send()
- 向某人发送消息。接受3个参数,其中最后一个参数是可选的。第一个参数是要发送的实际消息(正文),第二个参数是消息的接收者,第三个参数是要发送的消息类型。默认为chat
。
可能的类型可以在此RFC文档中找到
receive()
- 在本节中介绍
IQ
getRoster()
- 不接受任何参数,获取当前认证用户的联系人列表。
setGroup()
- 将指定用户放入您提供的群组。方法接受两个参数:第一个参数是您将附加到指定用户的群组名称,另一个是该用户的JID。
存在
setPriority()
- 为指定资源设置优先级。第一个参数是整数-128 <> 127
。如果没有提供第二个参数,则优先级将设置为当前使用的资源。也可以提供其他资源作为第二个参数,则优先级将设置为该特定资源。
subscribe()
- 接受JID作为参数,请求该用户的存在。
acceptSubscription()
- 接受JID作为参数,并接受该用户的存在。
declineSubscription()
- 接受JID作为参数,并拒绝该用户的存在。
会话
会话目前仅用于区分多连接时的日志。
XmppClient
类接受第二个可选参数$sessionId
,您可以将其从您的系统转发会话ID,或者它将自动分配。
您可以通过Options
对象($options->setSessionManager(false)
)禁用会话,因为它们如果在框架或类似环境中使用可能会与已建立的会话冲突。不用说,如果禁用,则将第二个参数转发到XmppClient
不会建立新的会话。
更多选项(非必需)
Options
对象可以接受更多选项,这些选项可以链式调用,但不是必需的。这些在Options
类中直接进行解释和注释
$options
->setProtocol($protocol) // defaults to TCP
->setResource($resource) // defaults to 'Pdahal_machine_' string + timestamp
->setLogger($logger) // logger instance (logging explained below)
->setAuthType($authType) // Takes on classes which implement Authenticable
套接字选项
大多数套接字选项默认设置,因此不需要修改此类,但是您可以额外更改套接字在执行socket_read()
时的超时,这可以通过$socket->setTimeout()
来完成。
日志记录
在建立新的会话后,库会在 logs/
文件夹中创建一个 xmpp.log
日志文件。
您可以通过在实例化 Options
时使用 setLogger($logger)
来手动设置日志记录器。该方法接受任何实现 Loggable
接口的对象,因此您可以创建自己的实现。
有趣的事实:这曾经是一个 PSR-3
日志记录器接口,但我认为它在这个开发阶段过于复杂。
其他
Example.php
中有一个 sendRawXML()
方法,这对于调试非常有用。该方法的工作方式是您可以提供手写的 XML 并将其发送到服务器。另一方面,您也可以通过提供方法名而不是 XML 来触发一个方法。
Enter XML: <xml>foo</xml> <-- will send XML
Enter XML: getRoster <-- will run getRoster() method
Enter XML: requestPresence x@x.com <-- will run with argument requestPresence(x@x.com)
一些有效的 XMPP XML 会被拒绝(例如发送 <presence/>
),因为 simplexml_load_string()
无法将其解析为有效的 XML。如果您需要做一些自定义操作,并且您确信它是有效的 XMPP XML,您可以移除解析行,并让 send()
方法执行其魔法。
请注意!请务必注意! 向服务器发送无效的 XML 可能会破坏当前打开的 XML 会话,并且您可能需要重新启动脚本。这是高度实验性的,实际上并未维护。这是一个可怜的孤儿方法,其父母已经遗弃它并匆忙离开。它可能有一天会成为哈利·波特,但嘿...我们都清楚地怀疑这一点。您可能是一个特别的雪花,但没有人喜欢您。继续前进到孤儿院!方法(只是开个玩笑,我不会删除它)!
谁说说明文件无聊。
开发文档
对于任何愿意贡献的人来说,以下是结构的快速概述
Options.php
- 库中的一切都是可变的Socket.php
- 与套接字相关的实现(连接、读取、写入等)XmppClient.php
- 与库交互的用户友好方法,并提供了 stanza 包装器,使用户可以通过实例化的类调用 stanza 方法。这个文件应包含尽可能少的逻辑,但实际上并不那么容易:)
AuthTypes
- 包含用于身份验证 XMPP 服务器的各种方法。除了具体的实现之外,还有一个抽象类,它包含一些逻辑以避免重复,并有一个接口,其中包含所有必要的接口方法,以备出现新的身份验证类型。Buffers
- 当套接字调用receive()
方法时,它会填充缓冲区(或者说是一个简单的数组),并在调用getResponse()
方法(例如)进行读取时刷新。简而言之,为什么:我在一个不可恢复的错误发生时遇到了问题。在这种情况下,我必须做两件事:尝试重新连接,向用户显示错误。问题是getResponse()
返回一个字符串,并且在重新连接的情况下,程序执行将继续返回空值或错误字符串,这会在服务器第二次连接后误导用户关于之前发生的错误。于是诞生了缓冲区。Exceptions
- 这基本上是一个标准。我只是覆盖了构造函数,这样我就可以得到我的消息。Loggers
- 包含将日志存储到logs/xmpp.log
文件的逻辑。最初的想法是在其中保留多种日志类型(完整、简单、无日志记录器),但我发现一种就足够了。
Xml
Xml.php
- 一个包含大量正则表达式匹配的 trait。这应该被重新格式化。Stanzas
- 与服务器进行所有 stanza 通信的主要逻辑。这曾经只是纯 XML,但我决定将套接字依赖项传递进去,以便当您调用方法时,您实际上也将它发送到服务器。这曾经像$this->socket->send($this->iq->getRoster())
一样,从编程角度来看是正确的,但从简单起见,我更喜欢$client->iq->getRoster()
。我欢迎其他建议。
待办事项
- 单元测试 - 很遗憾,我拖延了很长时间,也许世界上有喜欢编写测试的人。
- 节流 - 当发生无法恢复的错误时(目前我正在捕获
<stream:error>
错误,这些错误会破坏流),会自动重新连接。如果这种情况反复发生,程序将无限期地尝试连接,这在任何方面都很好,除了日志会被堵塞。我希望通过节流来增加每次失败时的连接时间。问题在于我只能捕获响应时的错误,而响应可能在第一次XML交换(例如发送打开流请求时)成功,而在第二次请求时失败。考虑到这一点,我唯一的想法是实现带有时间戳的节流。 - 会话 - 我假设这部分工作正常,但应该通过框架进行测试。
- 多个连接 - 我认为这部分工作良好,但我担心在同时获取消息时触发
getRoster()
可能会删除一个服务器响应。如果你在同一个批次中获取联系人列表和消息,它们将添加到缓冲区中。调用回响应将获得联系人列表或消息,而不是两者。然后缓冲区将被刷新。这是需要思考的问题。 - XmppClient 结构 - 为了启用
$client->stanza->method
,我需要在类中实例化所有报文。我觉得这可以简化。