如何用PHP项目实现监控大屏?

wen java案例 3

本文目录导读:

如何用PHP项目实现监控大屏?

  1. 整体架构设计
  2. PHP 后端实现示例
  3. 前端大屏 HTML 实现
  4. 针对“性能与实时性”的优化

使用 PHP 实现监控大屏,通常并不是指用 PHP 去渲染实时动画(如 WebSocket 推送图表数据),因为 PHP 本身是同步阻塞的语言,不适合做长连接。

在真实的生产环境中,PHP 通常负责后端数据处理和 API 接口,而前端的实时刷新和图表渲染由 JavaScript(如 ECharts、Highcharts) + WebSocket/SSE/Ajax 来完成。

以下是一套经典、可行的 PHP 项目实现监控大屏的方案,分为架构设计、后端实现、前端实现三个部分。


整体架构设计

这是目前最主流的“PHP + 前端实时刷新”方案,而非“PHP 推流”。

graph TD
    A[监控数据源<br>服务器/数据库/API] --> B(PHP 后端)
    B --> C{数据存储}
    C --> D[数据库/Redis]
    D --> E(PHP API 接口)
    E --> F[前端定时请求 Ajax]
    F --> G[JavaScript 大屏渲染<br>ECharts/DataV]
  • PHP 角色:聚合数据(从数据库、Redis、外部API拉取)、清洗数据、提供 JSON 接口、鉴权。
  • 前端角色:每隔 N 秒(如3-5秒)通过 setIntervalsetTimeout 请求 PHP 接口,拿最新数据更新图表。

为什么不用 WebSocket? 如果你坚持全栈 PHP,可以使用 WorkermanSwoole 扩展让 PHP 支持 WebSocket 推送,但大多数情况下,Ajax 轮询已经满足监控大屏的“准实时”需求(1-5秒延迟)。


PHP 后端实现示例

假设我们有服务器 CPU、内存、在线用户数需要展示。

数据采集与存储 (模拟)

通常通过定时脚本(Crontab)或守护进程采集数据存入数据库或 Redis。

// collect_data.php (定时任务脚本,每分钟执行)
function collectMetrics() {
    // 模拟获取服务器负载和用户数
    $data = [
        'time'    => date('Y-m-d H:i:s'),
        'cpu'     => mt_rand(10, 95),
        'memory'  => mt_rand(30, 90),
        'users'   => mt_rand(1000, 5000),
    ];
    // 存入 Redis (推荐用于实时大屏)
    $redis = new Redis();
    $redis->connect('127.0.0.1', 6379);
    $redis->set('dashboard_cpu', json_encode($data));
    // 同时存入 MySQL 用于历史趋势
    // DB::table('metrics')->insert($data);
}
// 每60秒执行一次
collectMetrics();

提供 JSON 接口给大屏

这是前端会请求的 API。

// api/dashboard.php?type=current
header('Content-Type: application/json');
header('Access-Control-Allow-Origin: *');
// 请求类型
$type = $_GET['type'] ?? 'current';
if ($type === 'current') {
    // 从 Redis 获取最新数据
    $redis = new Redis();
    $redis->connect('127.0.0.1', 6379);
    $current = $redis->get('dashboard_cpu');
    echo $current ?: json_encode(['error' => 'No data']);
} elseif ($type === 'history') {
    // 从 MySQL 获取过去24小时数据 (用于折线图)
    $history = DB::table('metrics')
        ->where('time', '>', date('Y-m-d H:i:s', strtotime('-24 hours')))
        ->get();
    echo json_encode($history);
}

聚合多个图表的数据接口

为了减少前端请求次数,可将多个图表数据合并到一个接口返回。

// api/dashboard_all.php
$data = [
    'cpu'    => ['value' => 75, 'status' => 'warning'],
    'memory' => ['value' => 60, 'status' => 'normal'],
    'users'  => ['value' => 3200, 'prev' => 2800], // 当前和昨日对比
    'realtime' => [
        ['time' => '10:00:00', 'value' => 50],
        ['time' => '10:00:05', 'value' => 55],
        // ... 最近100条
    ]
];
echo json_encode($data);

前端大屏 HTML 实现

使用 HTML + ECharts + 定时刷新 PHP 接口。

<!DOCTYPE html>
<html>
<head>监控大屏</title>
    <script src="https://cdn.jsdelivr.net/npm/echarts@5.4.3/dist/echarts.min.js"></script>
    <style>
        body { background: #0a1f3d; color: white; margin: 0; }
        .grid { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 20px; padding: 20px; height: 100vh; }
        .panel { background: rgba(255,255,255,0.05); border: 1px solid rgba(255,255,255,0.1); border-radius: 8px; }
    </style>
</head>
<body>
<div class="grid">
    <div id="chartCpu" class="panel"></div>
    <div id="chartMemory" class="panel"></div>
    <div id="chartUsers" class="panel"></div>
    <div id="chartTrend" class="panel" style="grid-column: span 3; height: 400px;"></div>
</div>
<script>
// 初始化所有图表
const chartCpu = echarts.init(document.getElementById('chartCpu'));
const chartUsers = echarts.init(document.getElementById('chartUsers'));
const chartTrend = echarts.init(document.getElementById('chartTrend'));
// 定义更新函数
function refreshDashboard() {
    fetch('/api/dashboard_all.php')
        .then(res => res.json())
        .then(data => {
            // 1. 更新 CPU 仪表盘 (Gauge)
            chartCpu.setOption({
                series: [{
                    type: 'gauge',
                    startAngle: 180, endAngle: 0,
                    min: 0, max: 100,
                    data: [{ value: data.cpu.value, name: 'CPU' }],
                    axisLine: { lineStyle: { color: [[0.5, '#67e0e3'],[0.8, '#37a2da'],[1, '#fd666d']] } }
                }]
            });
            // 2. 更新用户数 (数字展示 + 对比)
            const userDiff = ((data.users.value - data.users.prev) / data.users.prev * 100).toFixed(2);
            chartUsers.setOption({
                title: { text: `当前用户\n${data.users.value}`, left: 'center', top: 'center', textStyle: {fontSize: 36, color: '#eee'} },
                // 也可以使用 ECharts 的 value cards 或 text 组件
                graphic: [{
                    type: 'text', left: 'center', top: '75%',
                    style: { text: `较昨日: ${userDiff > 0 ? '+' : ''}${userDiff}%`, fill: userDiff > 0 ? '#f00' : '#0f0', fontSize: 16 }
                }]
            });
            // 3. 更新实时趋势折线图
            chartTrend.setOption({
                xAxis: { type: 'category', data: data.realtime.map(i => i.time) },
                yAxis: { type: 'value' },
                series: [{ type: 'line', data: data.realtime.map(i => i.value), smooth: true, areaStyle: {} }]
            });
        })
        .catch(console.error);
}
// 首次加载
refreshDashboard();
// 定时刷新: 每3秒请求一次
setInterval(refreshDashboard, 3000);
// 窗口自适应
window.addEventListener('resize', () => {
    chartCpu.resize();
    chartUsers.resize();
    chartTrend.resize();
});
</script>
</body>
</html>

针对“性能与实时性”的优化

如果你希望更实时、服务器压力更小,有两种升级方案:

方案 A:PHP + SSE (Server-Sent Events)

PHP 脚本保持长连接,每 N 秒写一次数据给前端,优点:前端只需一个连接,后端主动推送。

// sse.php
header('Content-Type: text/event-stream');
header('Cache-Control: no-cache');
while (true) {
    $data = getLatestFromRedis(); // 获取最新数据
    echo "data: " . json_encode($data) . "\n\n";
    ob_flush(); flush();
    sleep(2); // 推2秒
}

前端使用 EventSource 接收。

方案 B:PHP + Swoole/Workerman

使用 PHP 扩展启动 WebSocket 服务端,后端采集数据后直接推送给前端。 这是一个真正的长连接方案,但需要熟悉 Swoole 库。


需求 实现方式 适用场景
简单、快速 Ajax 轮询 (每3秒请求PHP接口) 中小型项目、内部监控、数据吞吐量不大
较实时、省请求 SSE (PHP单线程推送) 数据更新频率稳定、不想使用 WebSocket
高并发、低延迟 WebSocket (Swoole/Workerman) 大规模监控、数据每秒变化

针对 PHP 项目最稳妥的建议

保持 PHP 只做数据提供方(接口),前端使用 Ajax 轮询实现大屏动态刷新,如果未来性能不够,再升级为 SSE 或 Swoole。

这个方案成本最低、易维护、兼容性好,也是目前 PHP 生态(如 Laravel、ThinkPHP)最常用的方法。

抱歉,评论功能暂时关闭!