本文目录导读:

- 方式一:文件/日志变化监控(非实时,最基础)
- 方式二:使用 inotify(Linux 原生文件监控)
- 方式三:WebSocket 实时推送(推荐用于 Web 应用)
- 方式四:Server-Sent Events (SSE) —— 单向实时推送
- 方式五:使用现代工具配合(生产推荐)
- 各方法对比
在 PHP 中实现“实时监控”通常有两种理解:一种是轮询(定期请求)来模拟实时,另一种是通过长连接技术(如 WebSocket)实现真正的实时推送。
PHP 本身是请求-响应模式的脚本语言,并不原生支持常驻内存或长连接,但可以通过以下 3 种主要方式实现:
文件/日志变化监控(非实时,最基础)
适用于监控日志文件、目录变化等。
<?php
$file = '/var/log/nginx/access.log';
$lastSize = filesize($file);
while (true) {
clearstatcache();
$currentSize = filesize($file);
if ($currentSize > $lastSize) {
$handle = fopen($file, 'r');
fseek($handle, $lastSize);
$newData = fread($handle, $currentSize - $lastSize);
echo "New log: " . $newData;
$lastSize = $currentSize;
}
sleep(1); // 轮询间隔
}
特点:
- 简单,但会消耗服务器资源
- 不是真正的“实时”,取决于轮询间隔
使用 inotify(Linux 原生文件监控)
PHP 扩展 inotify 可以监控文件/目录的增删改事件,真正的事件驱动,不用轮询。
安装:
pecl install inotify
示例代码:
<?php
$fd = inotify_init();
$watch_descriptor = inotify_add_watch($fd, '/path/to/dir', IN_CREATE | IN_MODIFY);
while (true) {
$events = inotify_read($fd); // 阻塞等待事件
foreach ($events as $event) {
echo "File: " . $event['name'] . " - Event: " . $event['mask'] . PHP_EOL;
// 处理事件...
}
}
inotify_rm_watch($fd, $watch_descriptor);
fclose($fd);
适用场景:
- 监控配置文件变更(自动重载)
- 监控文件上传目录
- 日志实时分析
⚠️ 注意: 需要 PHP CLI 运行,且 inotify 是阻塞的,不能用于 Web 请求。
WebSocket 实时推送(推荐用于 Web 应用)
此方案才是真正的浏览器实时更新,实时数据看板、聊天、推送通知。
安装 Ratchet(PHP WebSocket 库)
composer require cboden/ratchet
服务端代码(WebSocket Server)
<?php
// server.php
use Ratchet\MessageComponentInterface;
use Ratchet\ConnectionInterface;
use Ratchet\Server\IoServer;
use Ratchet\Http\HttpServer;
use Ratchet\WebSocket\WsServer;
require __DIR__ . '/vendor/autoload.php';
class MonitorServer implements MessageComponentInterface {
protected $clients;
public function __construct() {
$this->clients = new \SplObjectStorage;
}
public function onOpen(ConnectionInterface $conn) {
$this->clients->attach($conn);
echo "New connection: {$conn->resourceId}\n";
}
public function onMessage(ConnectionInterface $from, $msg) {
// 收到客户端消息,可以处理
foreach ($this->clients as $client) {
if ($from !== $client) {
$client->send($msg); // 广播
}
}
}
public function onClose(ConnectionInterface $conn) {
$this->clients->detach($conn);
echo "Connection {$conn->resourceId} disconnected\n";
}
public function onError(ConnectionInterface $conn, \Exception $e) {
echo "Error: {$e->getMessage()}\n";
$conn->close();
}
}
// 启动 WebSocket 服务
$server = IoServer::factory(
new HttpServer(
new WsServer(
new MonitorServer()
)
),
8080 // WebSocket 端口
);
$server->run();
启动服务
php server.php
客户端(浏览器 JavaScript)
// 建立 WebSocket 连接
const ws = new WebSocket('ws://localhost:8080');
ws.onopen = function() {
console.log('连接成功');
// 可以发送订阅消息
ws.send(JSON.stringify({action: 'subscribe', channel: 'monitor'}));
};
ws.onmessage = function(event) {
const data = JSON.parse(event.data);
// 实时更新页面
document.getElementById('realtime-data').innerText = data.value;
};
从 PHP 业务代码推送数据
如果有其他 PHP 脚本需要向 WebSocket 推送数据,可以使用 ZeroMQ 或 Redis Pub/Sub:
// 从业务控制器推送数据
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
$redis->publish('monitor_channel', json_encode(['cpu' => 85, 'memory' => 60]));
然后在 WebSocket 服务端订阅 Redis:
// 在 MonitorServer 中增加 Redis 订阅
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
$redis->subscribe(['monitor_channel'], function($redis, $channel, $msg) use ($monitorServer) {
foreach ($monitorServer->clients as $client) {
$client->send($msg);
}
});
Server-Sent Events (SSE) —— 单向实时推送
如果只需要服务器向浏览器推送(不需客户端发消息),SSE 比 WebSocket 更轻量。
PHP 服务端:
<?php
// sse.php
header('Content-Type: text/event-stream');
header('Cache-Control: no-cache');
header('Connection: keep-alive');
while (true) {
$data = ['cpu' => rand(0, 100), 'memory' => rand(0, 100)];
echo "data: " . json_encode($data) . "\n\n";
ob_flush();
flush();
sleep(2); // 2秒推送一次
}
浏览器接收:
const evtSource = new EventSource('sse.php');
evtSource.onmessage = function(event) {
const data = JSON.parse(event.data);
document.getElementById('cpu').innerText = data.cpu + '%';
};
适用场景:
- 实时看板、监控仪表盘
- 通知提醒
- 不需要双向通信的场景
使用现代工具配合(生产推荐)
PHP 不适合长时间运行的任务,生产环境建议:
| 场景 | 推荐方案 |
|---|---|
| 实时数据看板 | SSE + 后端用 Go/Node.js 推数据 |
| 日志监控 | ELK Stack(Elasticsearch, Logstash, Kibana) |
| 系统指标监控 | Prometheus + Grafana |
| 文件变化监控 | inotify + 将事件写入 Redis/Queue |
| 高并发推送 | Node.js + Socket.IO 或 Go + gorilla/websocket |
各方法对比
| 方式 | 实时性 | 实现难度 | 适用场景 | 备注 |
|---|---|---|---|---|
| 轮询 | 中 | 低 | 简单监控 | 资源浪费 |
| inotify | 高 | 中 | 本地文件监控 | Linux 专用 |
| WebSocket | 最高 | 高 | 双向通信、聊天、推送 | 需要常驻服务 |
| SSE | 高 | 中 | 服务器→浏览器推送 | 单向,简单 |
| 外部工具 | 高 | 低 | 生产环境 | 推荐用于大规模 |
如果你的需求是“监控 PHP 进程/代码变化”,推荐配合 Supervisor + inotify 或使用 Laravel Horizon 等专业工具。