getChannels() crashes on servers returning an empty channels array — the guard exists in process_trigger_result() but not here

オープン 初心者向け
#408 コメント 0 件 リアクション 0 件 担当者 0 名 GitHub で見る

@mkantautas がすでに取り組んでいます。

2026年10月23日 から。

  • #409 @mkantautas による — オープン

評価

難易度
2/5
見積もり時間
1〜3時間
初心者へのやさしさ
84/100
issue の種類
バグ
明瞭さ
明確に書かれている
活発さ
活発
技術スタック
php
領域
api

調査の方向性

src/Pusher.php の getChannels() から始め、channels の処理を、オブジェクトでないレスポンスをすでに保護している process_trigger_result() と比較します。空の channels 配列を指定してメソッドを実行し、TypeError なしでドキュメントに記載された配列形式を返すことを確認します。既存の動作が維持されていることを確認するため、関連するプロジェクトのテストを実行します。

索引モデルが issue の本文から書いたものです。

説明

Summary

getChannels() calls get_object_vars() without a type check, so a server response where channels is an empty JSON array crashes the client:

TypeError: get_object_vars(): Argument #1 ($object) must be of type object, array given
  src/Pusher.php:664

The interesting part: this library already guards against exactly this, but only on one code path.

process_trigger_result() (added in #323, fixing #322) checks the type:

https://github.com/pusher/pusher-http-php/blob/master/src/Pusher.php#L1195-L1197

if (property_exists($result, 'channels') && is_object($result->channels)) {
    $result->channels = get_object_vars($result->channels);
}

getChannels() does not:

https://github.com/pusher/pusher-http-php/blob/master/src/Pusher.php#L660-L666

public function getChannels(array $params = []): object
{
    $result = $this->get('/channels', $params);

    $result->channels = get_object_vars($result->channels);

    return $result;
}

Why it happens in practice

Pusher-protocol implementations other than Pusher itself are common now (Reverb, Sockudo, Soketi). I hit this with Laravel Reverb v1.11.1, which serialises an empty channel list as [] instead of {} — I reported it there as laravel/reverb#402, and it should be fixed on their side too.

But the failure mode is worth guarding here regardless, because it is silent and intermittent: the response is an array only while no channel is occupied. One connected client turns the PHP array into a string-keyed map, json_encode emits an object, and the crash disappears. So it reproduces on idle systems and vanishes under load.

Measured side by side, same signed request:

Reverb   →  {"channels":[]}
Sockudo  →  {"channels":{}}

Suggestion

Apply the same guard that process_trigger_result() already uses:

$result->channels = is_object($result->channels) ? get_object_vars($result->channels) : (array) $result->channels;

This keeps the documented return shape (channels as an array of channel names) for every server, instead of a fatal error for some of them. Happy to send a PR.

Environment

  • pusher/pusher-php-server ^7.2
  • PHP 8.3
主要言語
PHP
スター
1.5k
フォーク
318
PR マージ指標
30日以内にマージされた PR はありません

環境構築

  • Dockerfile・Docker Compose ファイルなし
  • プルリクエストのテンプレートあり
  • コントリビューションガイドなし

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

pusher/pusher-http-php のほかの issue

pusher/pusher-http-php の issue をすべて見る

似ている issue

PHP の issue をもっと見る

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。