sondt-1245/pusher-php-server

与 Pusher REST API 交互的库

v7.1.0-beta 2022-06-02 09:26 UTC

README

Tests Packagist Version Packagist License Packagist Downloads

PHP 库,用于与 Pusher Channels HTTP API 交互。

https://pusher.com 上注册并使用以下所示的应用程序凭证。

安装

您可以通过名为 pusher-php-server 的 composer 包来获取 Pusher Channels PHP 库。请参阅 https://packagist.org.cn/packages/pusher/pusher-php-server

$ composer require pusher/pusher-php-server

或在 composer.json 中添加以下内容:

"require": {
    "pusher/pusher-php-server": "^7.0"
}

然后运行 composer update

支持的平台

  • PHP - 支持 PHP 版本 7.3、7.4 和 8.0。
  • Laravel - 版本 8.29 及以上版本已内置对 Pusher Channels 的支持,作为 Broadcasting 后端
  • 其他 PHP 框架 - 在您使用支持的 PHP 版本的情况下提供支持。

Pusher Channels 构造函数

使用您 Pusher Channels 应用程序的凭证来创建一个新的 Pusher\Pusher 实例。

$app_id = 'YOUR_APP_ID';
$app_key = 'YOUR_APP_KEY';
$app_secret = 'YOUR_APP_SECRET';
$app_cluster = 'YOUR_APP_CLUSTER';

$pusher = new Pusher\Pusher($app_key, $app_secret, $app_id, ['cluster' => $app_cluster]);

第四个参数是一个 $options 数组。额外的选项包括

  • scheme - 例如 http 或 https
  • host - 主机,例如 api.pusherapp.com。没有尾随的反斜杠
  • port - HTTP 端口
  • path - 附加到所有请求路径的前缀。这仅在您运行自己的端点时才有用(例如,根据路径前缀路由的代理)。
  • timeout - HTTP 超时
  • useTLS - 快速选项,用于使用 https 方案和 443 端口。
  • cluster - 指定应用程序运行的集群。
  • encryption_master_key - 一个 32 个字符长的密钥。此密钥与频道名称一起用于生成每个频道的加密密钥。每个频道的密钥用于加密加密频道的请求数据。

例如,默认情况下调用将通过 HTTPS 进行。要使用纯 HTTP,可以将 useTLS 设置为 false

$options = [
  'cluster' => $app_cluster,
  'useTLS' => false
];
$pusher = new Pusher\Pusher($app_key, $app_secret, $app_id, $options);

日志配置

建议的日志方法是使用符合 PSR-3 的 logger 实现 Psr\Log\LoggerInterface。The Pusher 对象实现了 Psr\Log\LoggerAwareInterface,这意味着您可以通过调用 setLogger(LoggerInterface $logger) 来设置 logger 实例。

// where $logger implements `LoggerInterface`

$pusher->setLogger($logger);

自定义 Guzzle 客户端

此库使用 Guzzle 内部进行 HTTP 调用。您可以将自己的 Guzzle 实例传递给 Pusher 构造函数

$custom_client = new GuzzleHttp\Client();

$pusher = new Pusher\Pusher(
    $app_key,
    $app_secret,
    $app_id,
    [],
    $custom_client
);

这允许您传递自己的中间件,请参阅测试中的 示例

发布/触发事件

要在一个或多个频道上触发事件,请使用 trigger 函数。

单个频道

$pusher->trigger('my-channel', 'my_event', 'hello world');

多个频道

$pusher->trigger([ 'channel-1', 'channel-2' ], 'my_event', 'hello world');

批处理

还可以通过单个 API 调用发送多个事件(在多租户集群上每个调用最多 10 个事件)

$batch = [];
$batch[] = ['channel' => 'my-channel', 'name' => 'my_event', 'data' => ['hello' => 'world']];
$batch[] = ['channel' => 'my-channel', 'name' => 'my_event', 'data' => ['myname' => 'bob']];
$pusher->triggerBatch($batch);

异步接口

triggertriggerBatch 中,还有 triggerAsynctriggerBatchAsync 的异步对应项。这些函数返回 Guzzle promises,可以使用 ->then 进行链式调用

$promise = $pusher->triggerAsync(['channel-1', 'channel-2'], 'my_event', 'hello world');

$promise->then(function($result) {
  // do something with $result
  return $result;
});

$final_result = $promise->wait();

数组

数组会自动转换为 JSON 格式

$array['name'] = 'joe';
$array['message_count'] = 23;

$pusher->trigger('my_channel', 'my_event', $array);

输出将是

"{'name': 'joe', 'message_count': 23}"

套接字 ID

为了避免重复,您可以在触发事件时可选地指定发送者的socket ID。

$pusher->trigger('my-channel', 'event', 'data', ['socket_id' => $socket_id]);
$batch = [];
$batch[] = ['channel' => 'my-channel', 'name' => 'my_event', 'data' => ['hello' => 'world'], ['socket_id' => $socket_id]];
$batch[] = ['channel' => 'my-channel', 'name' => 'my_event', 'data' => ['myname' => 'bob'], ['socket_id' => $socket_id]];
$pusher->triggerBatch($batch);

在发布时获取频道信息[实验性]

您可以使用info参数请求有关已发布到频道的属性

$result = $pusher->trigger('my-channel', 'my_event', 'hello world', ['info' => 'subscription_count']);
$subscription_count = $result->channels['my-channel']->subscription_count;
$batch = [];
$batch[] = ['channel' => 'my-channel', 'name' => 'my_event', 'data' => ['hello' => 'world'], 'info' => 'subscription_count'];
$batch[] = ['channel' => 'presence-my-channel', 'name' => 'my_event', 'data' => ['myname' => 'bob'], 'info' => 'user_count,subscription_count'];
$result = $pusher->triggerBatch($batch);

foreach ($result->batch as $i => $attributes) {
  echo "channel: {$batch[$i]['channel']}, name: {$batch[$i]['name']}";
  if (isset($attributes->subscription_count)) {
    echo ", subscription_count: {$attributes->subscription_count}";
  }
  if (isset($attributes->user_count)) {
    echo ", user_count: {$attributes->user_count}";
  }
  echo PHP_EOL;
}

JSON格式

如果您的数据已经以JSON格式编码,您可以通过将第六个参数设置为true来避免第二次编码步骤,如下所示

$pusher->trigger('my-channel', 'event', 'data', [], true);

验证私有频道

为了授权您的用户访问Pusher上的私有频道,您可以使用socketAuth函数

$pusher->socketAuth('private-my-channel','socket_id');

验证存在频道

使用存在频道与私有频道类似,但您可以指定额外数据来识别特定用户

$pusher->presenceAuth('presence-my-channel','socket_id', 'user_id', 'user_info');

Webhooks

此库提供了一种验证您从Pusher收到的webhooks是否实际上是来自Pusher的真实webhooks的方法。它还提供了一个用于存储它们的结构。名为webhook的辅助方法实现了这一点。传入请求的标头和正文,它将返回一个包含已验证事件的Webhook对象。如果库无法验证签名,则抛出异常。

$webhook = $pusher->webhook($request_headers, $request_body);
$number_of_events = count($webhook->get_events());
$time_received = $webhook->get_time_ms();

端到端加密

此库支持对您的私有频道进行端到端加密。这意味着只有您和您的连接客户端才能阅读您的消息。Pusher无法解密它们。您可以通过以下步骤启用此功能

  1. 首先设置私有频道。这涉及到在您的服务器上创建一个认证端点

  2. 接下来,生成32字节的密钥,进行base64编码并安全存储。这是秘密的,您绝不应该与任何人分享,甚至不包括Pusher。

    要从一个好的随机源生成适当的关键字,您可以使用openssl命令

    openssl rand -base64 32
  3. 在创建Pusher客户端时指定主加密密钥

    $pusher = new Pusher\Pusher(
        $app_key,
        $app_secret,
        $app_id,
        [
            'cluster' => $app_cluster,
            'encryption_master_key_base64' => "<your base64 encoded master key>"
        ]
     );
  4. 您希望使用端到端加密的频道应以前缀private-encrypted-开头。

  5. 在您的客户端中订阅这些频道,您就完成了!您可以通过查看https://dashboard.pusher.com/上的调试控制台来验证它是否正常工作,并查看加密的密文。

重要提示:这不会加密不以private-encrypted-为前缀的频道上的消息。

限制:您不能在trigger调用中触发多个频道上的单个事件,例如。

$data['name'] = 'joe';
$data['message_count'] = 23;

$pusher->trigger(['channel-1', 'private-encrypted-channel-2'], 'test_event', $data);

原因:此库中的方法直接映射到单个频道的HTTP API请求。如果我们允许在多个频道(一些加密,一些未加密)上触发单个事件,那么将需要两个API请求:一个用于将事件加密到加密频道,另一个用于将事件解密到未加密频道。

存在示例

首先在您的JS应用程序中设置此变量

Pusher.channel_auth_endpoint = '/presenceAuth.php';

接下来,在presenceAuth.php中创建以下内容

<?php

header('Content-Type: application/json');

if (isset($_SESSION['user_id'])) {
  $stmt = $pdo->prepare("SELECT * FROM `users` WHERE id = :id");
  $stmt->bindValue(':id', $_SESSION['user_id'], PDO::PARAM_INT);
  $stmt->execute();
  $user = $stmt->fetch();
} else {
  die(json_encode('no-one is logged in'));
}

$pusher = new Pusher\Pusher($key, $secret, $app_id);
$presence_data = ['name' => $user['name']];

echo $pusher->presenceAuth($_POST['channel_name'], $_POST['socket_id'], $user['id'], $presence_data);

注意:这假设您将用户存储在名为users的表中,并且这些用户有一个name列。它还假设您有一个登录机制,该机制将登录用户的user_id存储在会话中。

应用程序状态查询

获取频道的详细信息

$pusher->getChannelInfo($name);

您还可以从Channels HTTP API中获取有关频道的详细信息。

$info = $pusher->getChannelInfo('channel-name');
$channel_occupied = $info->occupied;

对于存在频道,您还可以查询当前订阅此频道的不同用户数量(单个用户可能订阅多次,但只计为一次)。

$info = $pusher->getChannelInfo('presence-channel-name', ['info' => 'user_count']);
$user_count = $info->user_count;

如果您已启用查询 subscription_count(当前订阅此频道的连接数)的功能,则可以按照以下方式查询此值。

$info = $pusher->getChannelInfo('presence-channel-name', ['info' => 'subscription_count']);
$subscription_count = $info->subscription_count;

获取应用程序频道列表

$pusher->getChannels();

您还可以从 Channels HTTP API 获取应用程序的频道列表。

$result = $pusher->getChannels();
$channel_count = count($result->channels); // $channels is an Array

获取经过筛选的应用程序频道列表

$pusher->getChannels(['filter_by_prefix' => 'some_filter']);

您还可以根据名称前缀获取频道列表。为此,您需要向调用提供 $options 参数。在以下示例中,调用将返回所有以 presence- 前缀开头的频道列表。这非常适合获取所有存在频道的列表。

$results = $pusher->getChannels(['filter_by_prefix' => 'presence-']);
$channel_count = count($result->channels); // $channels is an Array

这也可以使用通用的 pusher->get 函数实现。

$pusher->get('/channels', ['filter_by_prefix' => 'presence-']);

获取带有订阅计数的应用程序频道列表

返回频道列表的 HTTP API 不支持返回每个频道旁边的订阅计数。相反,您可以遍历每个频道并发出另一个请求来获取此数据。请注意:这种方法消耗(频道数量 + 1)条消息!

<?php
$subscription_counts = [];
foreach ($pusher->getChannels()->channels as $channel => $v) {
  $subscription_counts[$channel] =
    $pusher->getChannelInfo(
      $channel, ['info' => 'subscription_count']
    )->subscription_count;
}
var_dump($subscription_counts);

从存在频道获取用户信息

$results = $pusher->getPresenceUsers('presence-channel-name');
$users_count = count($results->users); // $users is an Array

这也可以使用通用的 pusher->get 函数实现。

$response = $pusher->get('/channels/presence-channel-name/users');

$response 格式如下

Array (
	[body] => {"users":[{"id":"a_user_id"}]}
	[status] => 200
	[result] => Array (
		[users] => Array (
			[0] => Array (
				[id] => a_user_id
			),
			/* Additional users */
		)
	)
)

通用获取函数

$pusher->get($path, $params);

用于针对 Channels HTTP API 进行 GET 查询。处理身份验证。

响应是一个具有 result 索引的关联数组。此索引的内容取决于所调用的 HTTP 方法。然而,始终存在一个表示 HTTP 状态码的 status 属性,如果状态码表示 API 调用成功,则设置 result 属性。

$response = $pusher->get('/channels');
$http_status_code = $response['status'];
$result = $response['result'];

运行测试

需要 phpunit

  • 运行 composer install
  • 进入 tests 目录
  • 重命名 config.example.php 并将值替换为有效的 Channels 凭证 创建环境变量。
  • 一些测试需要客户端连接到您在配置中定义的应用程序;您可以在浏览器中打开 https://dashboard.pusher.com/apps/<YOUR_TEST_APP_ID>/getting_started 来执行此操作
  • 从项目根目录执行 composer exec phpunit 以运行所有测试。

许可证

版权 2014,Pusher。根据 MIT 许可证授权:https://open-source.org.cn/licenses/mit-license.php

版权 2010,Squeeks。根据 MIT 许可证授权:https://open-source.org.cn/licenses/mit-license.php