norgul/xmpp-php

PHP 的 XMPP 库。

安装次数: 8,076

依赖项: 1

建议者: 0

安全: 0

星标: 45

关注者: 8

分支: 23

类型:项目

v2.2.3 2019-10-14 18:36 UTC

README

Latest Stable Version Total Downloads Latest Unstable Version Build Status License

这是由于网络上缺乏此类库(至少是我能找到的具有良好文档的库),因此为使 PHP 能够与 XMPP 通信而实现的低级别套接字实现。

XMPP 核心文档可以在 这里 找到。

安装要求和示例

项目要求在 composer.json 中给出( Composer 网站

您可以通过运行以下命令在项目中使用此库

composer require norgul/xmpp-php

您可以通过更改凭据指向您的 XMPP 服务器,在项目根目录下运行 php Example.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。

获取原始响应

可以使用$client->getResponse()获取服务器响应(或更确切地说,是服务器端持续的XML会话)。如果您想看到来自服务器的所有内容的连续流,您可以在无限循环或某些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。

Presence

setPriority() - 为指定的资源设置优先级。第一个参数是一个整数-128 <> 127。如果没有第二个参数,则优先级将设置为您当前使用的资源。其他资源可以作为第二个参数提供,而优先级将设置为此特定资源。

subscribe() - 接受JID作为参数并请求该用户的状态。

acceptSubscription() - 接受来自该用户的请求。

declineSubscription() - 拒绝来自该用户的请求。

会话

会话目前仅用于区分多个连接时生成的日志。

XmppClient类接受第二个可选参数$sessionId,您可以将其从您的系统转发,或者它将自动分配。

您可以通过Options对象($options->setSessionManager(false))禁用会话,因为它们可能在框架或类似情况下与已建立的会话发生冲突。不用说,如果禁用,则将第二个参数转发到XmppClient不会建立新的会话。

更多选项(不是必需的)

Options对象可以接受更多选项,这些选项可以是链式的,但不是必需的。这些在Options类中的代码中直接进行了解释和注释。

$options
    ->setProtocol($protocol)  // defaults to TCP
    ->setResource($resource)  // defaults to 'norgul_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会话无效,并且您可能需要重新启动脚本。这是一个高度实验性的功能,实际上并未得到维护。这是一个被遗弃的方法,其父母已经离开并且匆忙。它可能有一天会成为哈利·波特,但是嘿...我们都清楚地怀疑这一点。你可能是个特别的人,但没有人喜欢你。向前,孤儿之家!方法(只是开玩笑,我不会删除它)!

谁说readme很无聊。

开发文档

对于愿意贡献的人来说,这是一个关于结构的简要概述

  • Options.php - 库中所有可变的内容
  • Socket.php - 套接字相关实现(连接、读取、写入等)
  • XmppClient.php - 与库交互的用户友好方法以及启用用户通过实例化类调用stanza方法的包装器。这应该包含尽可能少的逻辑,但事实证明这并不容易 :)
  • AuthTypes - 包含用于验证自己到XMPP服务器的各种方法。除了具体实现外,还有一个包含少量逻辑的抽象类以避免重复,以及一个包含所有必要方法的接口,以便在需要新的认证类型时使用。

  • Buffers - 缓冲区实现(或者说是一个简单的数组),当套接字调用receive()方法时会填充,并在任何读取时刷新,例如在调用getResponse()方法时。简要的历史背景:我在遇到不可恢复的错误时遇到了问题。在这种情况下,我必须做两件事:尝试重新连接,向用户显示错误。问题是getResponse()返回字符串,而在重新连接的情况下,程序执行将继续返回空或返回错误字符串,因为服务器已经连接了第二次,从而误导用户之前发生的错误。缓冲区就是这样诞生的。

  • Exceptions - 这基本上是一个标准。我只是覆盖了构造函数,以便我可以获得我的消息。

  • Loggers - 包含将日志存储到logs/xmpp.log文件的逻辑。想法是将几种日志类型放在里面(完整、简单、无记录器),但我发现一个就足够了。

Xml

  • Xml.php - 一个由过多正则表达式匹配组成的特质。这部分应该重新格式化。
  • Stanzas - 与服务器进行所有stanza通信的主要逻辑。这曾经只是普通的XML,但我决定在内部转发socket依赖,这样当你调用方法时,你实际上也将其发送到服务器。这曾经类似于 $this->socket->send($this->iq->getRoster()),这在编程角度上是正确的,但为了简单起见,我更喜欢 $client->iq->getRoster()。我对其他建议持开放态度。

CI

通过 Travis CI 进行持续集成,每次推送都会经过一个目前非常简单的流程:

  • 检查单元测试(天知道我有很多)
  • 检查语法错误
  • 运行 phpcs(配置在 phpcs.xml 中)
  • 运行 phpmd(配置在 phpmd.xml 中)

TODO

  • 单元测试 - 很遗憾,我已经推迟了很长时间,也许有喜欢编写测试的好心人。
  • 限速 - 当发生不可恢复的错误时(目前我正在捕获导致流中断的 <stream:error> 错误),程序将自动尝试重新连接。如果这种情况反复发生,程序将无限期地尝试连接,这在除日志之外的所有方面都是可以接受的,因为日志可能会变得拥挤。我希望限速连接,使其在每次失败时增加连接时间。问题在于我只能捕获响应时的错误,而响应可能在第一次XML交换时成功(例如,当你发送打开流请求时),而在第二次请求时中断。考虑到这一点,我唯一想到的方法是使用时间戳或其他方法来实现限速。
  • 会话 - 我假设这部分工作正常,但应该从框架中进行测试
  • 多个连接 - 我认为这部分工作得很好,但我担心在同时获取消息时触发 getRoster() 可能会删除一个服务器响应。如果你在一次批量操作中同时获取罗盘和消息,它将被添加到缓冲区。回调响应将得到罗盘或消息,而不是两者。然后缓冲区将被刷新。这是一个需要思考的问题。
  • XmppClient 的结构 - 为了启用 $client->stanza->method,我需要在类中实例化所有stanza。我觉得这可以简化。