Mastering Server‑Sent Events (SSE) in PHP and JavaScript: Real‑Time Push Made Simple

This guide explains what Server‑Sent Events (SSE) are, why they are needed for real‑time server‑to‑client communication, presents complete PHP and JavaScript examples, compares three implementation patterns, and contrasts SSE with WebSocket, highlighting strengths and limitations.

Open Source Tech Hub
Open Source Tech Hub
Open Source Tech Hub
Mastering Server‑Sent Events (SSE) in PHP and JavaScript: Real‑Time Push Made Simple

Introduction

SSE (Server‑Sent Events) is an HTTP‑based, one‑way (half‑duplex) communication mechanism that lets a server push real‑time data to a client without the client repeatedly polling.

Data Communication

Problem Solved

Traditional HTTP request‑response cannot initiate data from the server; SSE fills this gap.

Typical Use Cases

Real‑time subscription updates

Instant notifications

Live log monitoring

Real‑time statistics

Simple text data transmission

Server‑Side Example (PHP)

ini_set('output_buffering', 'off');
ini_set('zlib.output_compression', false);
while (@ob_end_flush()) {}
header('Content-Type: text/event-stream');
header('Cache-Control: no-cache');
header('Connection: keep-alive');
header('X-Accel-Buffering: no');

function sse($data) {
    return "data:{$data}

";
}

ob_start();
while (true) {
    $json = json_encode(['data' => ['time' => date('Y-m-d H:i:s')]], JSON_UNESCAPED_UNICODE);
    echo sse($json);
    ob_flush();
    flush();
    sleep(1);
}

Client‑Side Example (JavaScript)

<!doctype html>
<html>
<head><meta charset="UTF-8"><title>Document</title></head>
<body>
<script>
if (!!window.EventSource) {
    var sse = new EventSource('http://127.0.0.1/test/sse.php');
    sse.onmessage = function(event) {
        var response = JSON.parse(event.data);
        console.log(response.data.time);
    };
    sse.onopen = function() { console.log('连接成功'); };
    sse.onclose = function() { console.log('连接关闭'); };
    sse.onerror = function() { console.error('连接失败'); };
} else {
    alert('您的浏览器不支持SSE');
}
</script>
</body>
</html>

Synchronization Strategies

Solution 1 – Pure Polling

Method: continuously query the database.

Pros: simple to implement.

Cons: high performance cost, not elegant.

Scenario: small data volume or temporary fix.

ob_start();
$user_id = 1; // example user ID
while (true) {
    $notice_count = DB::table('notice')->where('user_id', $user_id)->count();
    echo sse(json_encode(['notice_num' => $notice_count]));
    ob_flush();
    flush();
    sleep(1);
}

Solution 2 – Event‑Driven Pub/Sub with Message Queue (Redis)

Method: publish a task to a Redis queue when data changes; SSE module consumes the queue.

Pros: avoids intensive polling.

Cons: still consumes resources, slightly more complex.

Scenario: when the subscriber needs to perform richer business logic.

// Publisher
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
$user_id = 1;
$redis->lPush('add_one_notice_task:' . $user_id, 1);

// Subscriber
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
$user_id = 1;
$notice_count = DB::table('notice')->where('user_id', $user_id)->count();
$redis->set('user_notice_num:' . $user_id, $notice_count);
while (true) {
    $task = $redis->rPop('add_one_notice_task:' . $user_id);
    if ($task) { $redis->incr('user_notice_num:' . $user_id); }
    echo sse(json_encode(['notice_num' => $redis->get('user_notice_num:' . $user_id) ?? 0]));
    ob_flush();
    flush();
    sleep(1);
}

Solution 3 – Event‑Driven Polling via Cache

Method: after data changes, write the new value to a cache; the listener repeatedly reads the cache.

Pros: simpler than full pub/sub while avoiding heavy DB polling.

Cons: still a polling loop, consumes some resources.

Scenario: simple data return without complex subscriber logic.

// Trigger side
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
$user_id = 1;
$notice_count = DB::table('notice')->where('user_id', $user_id)->count();
$redis->set('user_notice_num:' . $user_id, $notice_count);

// Listener side
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
while (true) {
    echo sse(json_encode(['notice_num' => $redis->get('user_notice_num:' . $user_id) ?? 0]));
    ob_flush();
    flush();
    sleep(1);
}

Project‑Level Helper Function

function sse($callback, $millisecond = 1000) {
    set_time_limit(0);
    ini_set('output_buffering', 'off');
    ini_set('zlib.output_compression', false);
    while (@ob_end_flush()) {}
    header('Content-Type: text/event-stream; Charset=UTF-8');
    header('Cache-Control: no-cache');
    header('Connection: keep-alive');
    header('X-Accel-Buffering: no');
    header('Access-Control-Allow-Origin: *');
    header('Access-Control-Allow-Credentials: true');
    header('Access-Control-Allow-Methods: *');
    header('Access-Control-Allow-Headers: *');
    ob_start();
    while (true) {
        $res = $callback();
        if ($res !== null) {
            $data = json_encode($res, JSON_UNESCAPED_UNICODE);
            echo "data:{$data}

";
        }
        ob_flush();
        flush();
        usleep($millisecond * 1000);
    }
}

// Usage example
sse(function() {
    if ('业务逻辑数据存在') {
        return ['k' => 'v'];
    }
    return null;
}, 1000);

Advantages of SSE

Simple to implement and use.

Built‑in reconnection logic handles network interruptions.

Reduces request volume compared to short‑polling and avoids the overhead of adding a full WebSocket layer for lightweight real‑time needs.

Disadvantages of SSE

Not supported by Internet Explorer.

Half‑duplex only; data flows from server to client.

Browsers may limit the number of concurrent SSE connections per domain or per instance.

SSE vs. WebSocket

Protocol Difference

SSE runs over HTTP, while WebSocket uses a separate protocol, though both can maintain persistent connections.

Data Format

SSE transmits plain text (commonly JSON), suitable for simple messages; WebSocket can handle both text and binary, making it better for large media streams.

Communication Mode

SSE is half‑duplex (server‑to‑client only); WebSocket is full‑duplex, allowing bidirectional data exchange.

Compatibility

WebSocket is supported from IE10 onward; SSE is unsupported in all IE versions and varies across other browsers, though polyfills can mitigate gaps.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

Real-TimeJavaScriptWebSocketPHPServer-Sent EventsSSE
Open Source Tech Hub
Written by

Open Source Tech Hub

Sharing cutting-edge internet technologies and practical AI resources.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.