Skip to content

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

Description

@likemusic

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

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions