本文目录导读:

我将为您详细介绍 PHP Web 推送的几种实现方式,主要包括Server-Sent Events (SSE) 和 WebSocket 两种技术方案。
Server-Sent Events (SSE) 实现
SSE 是单向推送(服务器→客户端),实现简单,适合消息推送、通知等场景。
服务器端代码 (push.php)
<?php
header('Content-Type: text/event-stream');
header('Cache-Control: no-cache');
header('Connection: keep-alive');
header('Access-Control-Allow-Origin: *');
// 设置无限执行时间
set_time_limit(0);
ob_implicit_flush(true);
ob_end_flush();
// 模拟数据推送
$counter = 0;
while (true) {
$counter++;
// 发送事件数据
echo "id: {$counter}\n";
echo "event: message\n";
echo "data: " . json_encode([
'time' => date('Y-m-d H:i:s'),
'message' => "这是第 {$counter} 条消息"
]) . "\n\n";
// 检查客户端是否断开连接
if (connection_aborted()) {
break;
}
sleep(2);
}
客户端 JavaScript 代码
<!DOCTYPE html>
<html>
<head>SSE 示例</title>
</head>
<body>
<div id="messages"></div>
<script>
// 创建 EventSource 连接
const eventSource = new EventSource('push.php');
// 监听消息事件
eventSource.addEventListener('message', function(e) {
const data = JSON.parse(e.data);
const messagesDiv = document.getElementById('messages');
messagesDiv.innerHTML += `<p>${data.time}: ${data.message}</p>`;
});
// 监听连接打开
eventSource.addEventListener('open', function(e) {
console.log('连接已建立');
});
// 监听错误
eventSource.addEventListener('error', function(e) {
console.error('连接错误:', e);
eventSource.close();
});
</script>
</body>
</html>
WebSocket 实现
WebSocket 支持双向通信,适合实时交互场景,需要安装 Ratchet 或 Swoole 等库。
使用 Ratchet(推荐)
安装 Ratchet
composer require cboden/ratchet
服务器端代码 (server.php)
<?php
require 'vendor/autoload.php';
use Ratchet\MessageComponentInterface;
use Ratchet\ConnectionInterface;
use Ratchet\Server\IoServer;
use Ratchet\Http\HttpServer;
use Ratchet\WebSocket\WsServer;
class WebSocketServer implements MessageComponentInterface {
protected $clients;
public function __construct() {
$this->clients = new \SplObjectStorage;
}
public function onOpen(ConnectionInterface $conn) {
// 存储新连接
$this->clients->attach($conn);
echo "新连接: {$conn->resourceId}\n";
// 发送欢迎消息
$conn->send(json_encode([
'type' => 'welcome',
'message' => '欢迎连接 WebSocket 服务器'
]));
}
public function onMessage(ConnectionInterface $from, $msg) {
$data = json_decode($msg, true);
switch ($data['type']) {
case 'broadcast':
// 广播消息给所有客户端
foreach ($this->clients as $client) {
if ($from !== $client) {
$client->send(json_encode([
'type' => 'broadcast',
'from' => $from->resourceId,
'message' => $data['message']
]));
}
}
break;
case 'private':
// 发送私信给指定客户端
$targetId = $data['target'];
foreach ($this->clients as $client) {
if ($client->resourceId == $targetId) {
$client->send(json_encode([
'type' => 'private',
'from' => $from->resourceId,
'message' => $data['message']
]));
break;
}
}
break;
}
}
public function onClose(ConnectionInterface $conn) {
$this->clients->detach($conn);
echo "连接关闭: {$conn->resourceId}\n";
}
public function onError(ConnectionInterface $conn, \Exception $e) {
echo "错误: {$e->getMessage()}\n";
$conn->close();
}
}
// 创建 WebSocket 服务器
$server = IoServer::factory(
new HttpServer(
new WsServer(
new WebSocketServer()
)
),
8080
);
echo "WebSocket 服务器启动在端口 8080\n";
$server->run();
客户端 JavaScript 代码
<!DOCTYPE html>
<html>
<head>WebSocket 示例</title>
</head>
<body>
<div id="messages"></div>
<input type="text" id="messageInput" placeholder="输入消息">
<button onclick="sendMessage()">发送</button>
<script>
// 创建 WebSocket 连接
const ws = new WebSocket('ws://localhost:8080');
// 连接打开
ws.addEventListener('open', function(e) {
console.log('WebSocket 连接已建立');
addMessage('系统', '已连接到服务器');
});
// 接收消息
ws.addEventListener('message', function(e) {
const data = JSON.parse(e.data);
switch (data.type) {
case 'welcome':
addMessage('服务器', data.message);
break;
case 'broadcast':
addMessage(`用户 ${data.from}`, data.message);
break;
case 'private':
addMessage(`私信来自 ${data.from}`, data.message);
break;
default:
addMessage('未知', JSON.stringify(data));
}
});
// 连接关闭
ws.addEventListener('close', function(e) {
console.log('WebSocket 连接已关闭');
addMessage('系统', '连接已断开');
});
// 错误处理
ws.addEventListener('error', function(e) {
console.error('WebSocket 错误:', e);
addMessage('系统', '连接错误');
});
// 发送消息
function sendMessage() {
const input = document.getElementById('messageInput');
const message = input.value.trim();
if (message) {
ws.send(JSON.stringify({
type: 'broadcast',
message: message
}));
input.value = '';
}
}
// 添加消息到界面
function addMessage(sender, message) {
const div = document.getElementById('messages');
div.innerHTML += `<p><strong>${sender}:</strong> ${message}</p>`;
}
</script>
</body>
</html>
使用 Swoole(高性能方案)
安装 Swoole
pecl install swoole
服务器端代码
<?php
$server = new Swoole\WebSocket\Server("0.0.0.0", 9501);
// 监听 WebSocket 连接打开事件
$server->on('open', function (Swoole\WebSocket\Server $server, $request) {
echo "新连接: {$request->fd}\n";
$server->push($request->fd, json_encode([
'type' => 'welcome',
'message' => '欢迎连接到 Swoole WebSocket 服务器'
]));
});
// 监听消息事件
$server->on('message', function (Swoole\WebSocket\Server $server, $frame) {
echo "收到消息: {$frame->data}\n";
// 广播消息给所有客户端
foreach ($server->connections as $fd) {
if ($fd !== $frame->fd) {
$server->push($fd, $frame->data);
}
}
});
// 监听连接关闭事件
$server->on('close', function ($ser, $fd) {
echo "连接关闭: {$fd}\n";
});
echo "Swoole WebSocket 服务器启动在端口 9501\n";
$server->start();
使用第三方推送服务
Pusher(推荐)
<?php
require 'vendor/autoload.php';
use Pusher\Pusher;
$options = array(
'cluster' => 'ap1',
'useTLS' => true
);
$pusher = new Pusher(
'your-app-key',
'your-app-secret',
'your-app-id',
$options
);
// 推送消息
$data['message'] = 'Hello World!';
$pusher->trigger('my-channel', 'my-event', $data);
Firebase Cloud Messaging (FCM)
<?php
function sendFCMNotification($deviceToken, $title, $body) {
$url = 'https://fcm.googleapis.com/fcm/send';
$fields = [
'to' => $deviceToken,
'notification' => [
'title' => $title,
'body' => $body,
'sound' => 'default'
],
'data' => [
'type' => 'notification',
'action' => 'open_page'
]
];
$headers = [
'Authorization: key=' . YOUR_SERVER_KEY,
'Content-Type: application/json'
];
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($fields));
$result = curl_exec($ch);
curl_close($ch);
return $result;
}
选择建议
| 技术方案 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|
| SSE | 实时通知、数据推送 | 实现简单,原生支持 | 单向通信,浏览器兼容性有限 |
| WebSocket | 即时通讯、在线游戏 | 双向通信,实时性好 | 需要特殊服务器支持 |
| Pusher | 快速集成推送 | 开箱即用,功能完善 | 有费用限制 |
| FCM | 移动推送 | 免费,覆盖面广 | 依赖第三方服务 |
生产环境注意事项
-
性能优化:
- 使用连接池管理连接
- 设置合理的超时时间
- 考虑使用消息队列(如 RabbitMQ)
-
安全性:
- 验证客户端身份
- 加密敏感数据
- 限制推送频率
-
可靠性:
- 实现断线重连机制
- 保存未推送消息
- 监控连接状态
选择哪种推送方案取决于您的具体需求:如果只是简单的服务器推送消息,SSE 即可;如果需要双向实时通信,推荐使用 WebSocket。