pdahal/php-xmpp

基于 `xmppo/xmpp-php` 的 PHP XMPP 库

v1.0.1 2024-09-13 12:17 UTC

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 的默认端口号。

用户名可以是裸 JIDJID/resource 形式。如果您使用裸 JID,则资源将被自动添加。您可以通过使用 $client->iq->setResource() 显式设置资源来覆盖此操作。在第二种情况下,用户名将被自动解析为 usernameresource 变量。在 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() 方法执行以下操作

  1. 连接到在 XmppClient 构造函数中初始化的套接字
  2. 打开与 XMPP 服务器的 XML 流进行交换
  3. 根据提供的凭据尝试与服务器进行身份验证
  4. 开始与服务器进行初始通信,这是您开始所需的最低限度

当前版本支持 PLAINDIGEST-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,我需要在类中实例化所有报文。我觉得这可以简化。