pusher / pusher/pusher-http-php
getChannels() crashes on servers returning an empty channels array — the guard exists in process_trigger_result() but not here
Nobody has claimed this yet.
- Dominant language
- PHP
- Stars
- 1.5k
- Forks
- 317
- PR merge metrics
- No merged PRs in 30d
Description
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
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in src/Pusher.php at getChannels(), then compare its channels handling with process_trigger_result(), which already guards non-object responses. Exercise the method with an empty channels array and verify it returns the documented array shape without a TypeError; run the relevant project tests to confirm existing behavior remains intact.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- php
- Domain
- api
- Issue type
- Bug
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 84/100