Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Elephant.io Laravel Package

wisembly/elephant.io

Elephant.io is a PHP WebSocket client for talking to Socket.IO servers. It offers a simple API to emit events and listen for responses, making real-time communication easy to add to PHP applications.

Deep Wiki
Context7

Getting Started

Install

composer require wisembly/elephant.io

This package is archived and the last tagged release is from May 2017. It still installs and runs on modern PHP, but treat it as a frozen dependency: no security patches, no Socket.IO v3/v4 support, and no PHP 8 signature fixes are coming.

Where to look first

  • ElephantIO\Client — the façade you actually talk to (initialize(), emit(), read(), close(), getEngine()).
  • ElephantIO\Engine\SocketIO\Version1X / Version2X — engines that speak the Socket.IO handshake and framing. Pick the one matching the server's Socket.IO version, not your PHP version.
  • ElephantIO\Engine\WebSocket\WebSocket — for a plain RFC 6455 endpoint that is not Socket.IO.
  • ElephantIO\Exception\SocketException — the only exception type you will realistically catch.

First working example — emit an event to a local Socket.IO 2.x server:

use ElephantIO\Client;
use ElephantIO\Engine\SocketIO\Version2X;

$client = new Client(new Version2X('http://127.0.0.1:3000', [
    'timeout' => 5,
]));

$client->initialize();
$client->emit('order.created', ['id' => 42, 'total' => 19.99]);
$client->close();

That is the 80% use case: a Laravel request or job wants to tell a Node-side Socket.IO process that something happened. There is no pub/sub layer, no acknowledgment, and no server-side API — you are just a very small WebSocket client.

Implementation Patterns

1. Never call it inline in a web request. The handshake involves a blocking GET /socket.io/... plus a WebSocket upgrade. Wrap the client in a queued job or a listener implementing ShouldQueue so a slow/unreachable Socket.IO server never slows your users.

class BroadcastSocketEvent implements ShouldQueue
{
    public function __construct(
        public string $event,
        public array $payload,
    ) {}

    public function handle(): void
    {
        $client = new Client(new Version2X(config('elephant.url'), [
            'timeout' => config('elephant.timeout', 5),
        ]));
        $client->initialize();
        $client->emit($this->event, $this->payload);
        $client->close();
    }
}

2. Bind a thin service into the container. Don't sprinkle new Client(...) across the codebase; a SocketIoEmitter class with one emit(string $event, array $payload) method is the right granularity for testing and for swapping the implementation later.

3. Version-match the engine explicitly. Version1X for Socket.IO 1.x, Version2X for 2.x, and (legacy) Version0X. There is no Version3X/Version4X — the package was archived before those protocols existed. If you are on Socket.IO 4, you cannot use this library against it without protocol shims.

4. Namespaces. Client::emit($event, $data, $namespace) sets the nsp in the CONNECT packet. The server must already accept that namespace; the client does not negotiate it.

5. Plain WebSocket endpoints. Use WebSocket engine and drive frames via $client->getEngine() and $client->read(). There is no emit semantics here — you are sending raw text/binary frames.

6. Long-running consumer / bridging worker. Blocking read loop with backoff:

while (true) {
    try {
        $client = new Client(new WebSocket($url));
        $client->initialize();
        while ($frame = $client->read()) {
            $this->dispatchDownstream($frame);
        }
    } catch (Throwable $e) {
        Log::warning('elephant.io disconnected', ['err' => $e->getMessage()]);
        sleep(5);
    } finally {
        try { $client->close(); } catch (Throwable) {}
    }
}

Run it under Supervisor (or a dedicated Horizon queue with a single worker) — not inside a normal php artisan serve request.

7. Config. Add config/elephant.php with url, engine, timeout, and a boolean for SSL verification. Map it in AppServiceProvider to the emitter binding so production credentials never live in code.

8. Testing. Point the emitter at a local Socket.IO server in Docker Compose and assert server-side receipt of the event. The package ships no in-memory transport, no mock client, and no way to assert an emit() without a real server.

9. Auth. There is no first-class auth hook. Append query parameters to the URL (https://host:3000/?token=...) or pass http headers through the context option. Neither is guaranteed to survive the WebSocket upgrade on every Socket.IO server.

Gotchas and Tips

  • Archived. The joke description ("Ça trompe énormément" — "It is very misleading") is more than a decade old. Bugs you find will not be fixed. Audit before committing to it for anything revenue-adjacent.
  • Wrong engine class = silent hang or 400. If the handshake GET /socket.io/... returns non-2xx or the upgrade stalls, you get a SocketException, often only after the timeout. Verify the Socket.IO version on the server first.
  • read() blocks indefinitely. There is no non-blocking mode, no promise, no future. Every consumer design is a blocking loop; treat it as a dedicated worker process.
  • close() is not tolerant of half-open state. Calling it after a failed initialize() or twice can throw or double-close the socket. Always wrap in try/finally and swallow close errors.
  • emit() is fire-and-forget. No ack, no error if the remote has no listener for the event, no delivery guarantee if the socket dies immediately afterward. Build your own confirmation channel if you need one.
  • timeout is the connect timeout, not a read deadline. A server that accepts TCP and then goes quiet will leave read() hanging past the configured timeout.
  • debug => true writes raw frames to stdout. Fine in a CLI script, catastrophic in a web request. Prefer injecting a psr/log LoggerInterface as the second Client argument.
  • SSL. For wss://, pass a context via stream_context_create() with proper ssl options. Peer verification is on by default at the PHP layer; disable it explicitly and only for self-signed/internal hosts.
  • URL format matters. Include the scheme; http/https map to ws/wss internally. Any path prefix behind a reverse proxy (e.g. /socket.io/) must be in the base URL.
  • No reconnection, no heartbeat. Older engines partially handle Socket.IO pings; do not rely on it for long-lived connections. Assume the connection will go stale and implement your own retry loop.
  • Not fork-safe. Never reuse a Client across queue workers or after pcntl_fork(). One client, one process, one connection, initialize → emit → close.
  • Extension points. Implement ElephantIO\Engine\EngineInterface to add a new protocol; inject a custom LoggerInterface; use $client->getEngine() to reach the raw socket for anything the engine doesn't expose. Those three are the only seams the library offers.
  • Upgrade path. On Laravel 9+/PHP 8.1+, test in a sandbox first. The code is PHP 5-era; dynamic-property deprecations and untyped signatures will surface, and you will be patching them yourself.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
elsayed85/laravel-api-exceptions
ouhssini/laravel-demo-mode
daworks/ncloud-outbound-mailer-driver
gp247/cms
ignibyte/aic-gates
nexa-merchant/blog
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
cgv/localized-resource