PHP项目如何实现公告推送功能?

wen PHP项目 10

本文目录导读:

PHP项目如何实现公告推送功能?

  1. 核心需求分析
  2. 方案详解
  3. 技术选型建议
  4. 升级与优化
  5. 最终推荐(懒人版)

PHP项目实现公告推送功能,通常有以下几种主流方案,具体选择取决于你的实时性要求用户规模以及技术栈


核心需求分析

在开始编码前,先明确你的场景:

  • 被动获取:用户打开页面或刷新时看到公告(简单,适合非紧急通知)。
  • 主动推送:用户无需刷新,服务器主动将公告推送到浏览器(实时性强,适合紧急通知、系统维护)。

方案详解

方案1:轮询(Polling)—— 最简单,适合小项目(<1000用户)

原理:前端定时(如每5秒)向服务器发起AJAX请求,查询是否有新公告。

优点:实现简单,兼容所有浏览器。 缺点:浪费带宽,有一定延迟;高并发时服务器压力大。

实现步骤

  1. 数据库表 announcements
    • id (INT, PK, AUTO_INCREMENT)
    • title (VARCHAR)
    • content (TEXT)
    • created_at (DATETIME, 索引)
    • status (TINYINT, 1=发布)
  2. PHP API(get_latest_announcement.php
    <?php
    header('Content-Type: application/json');
    $lastId = $_GET['last_id'] ?? 0;
    $conn = new PDO('mysql:host=localhost;dbname=test', 'user', 'pass');
    $stmt = $conn->prepare("SELECT * FROM announcements WHERE id > ? AND status=1 ORDER BY id DESC LIMIT 1");
    $stmt->execute([$lastId]);
    $announcement = $stmt->fetch(PDO::FETCH_ASSOC);
    echo json_encode($announcement ?: ['new' => false]);
  3. 前端JavaScript
    let lastId = 0;
    setInterval(() => {
        fetch(`get_latest_announcement.php?last_id=${lastId}`)
            .then(res => res.json())
            .then(data => {
                if (data.new !== false) {
                    showAnnouncement(data);
                    lastId = data.id;
                }
            });
    }, 5000); // 5秒一次

方案2:长轮询(Long Polling)—— 折中方案

原理:前端发起请求后,PHP服务器保持连接,直到有新公告才返回响应,之后前端立即发起新请求。

优点:比普通轮询实时性更好,消息到达即推送。 缺点:服务器需要保持大量连接(消耗内存/进程),PHP本身不适合长时间挂起。

实现(简化版,需搭配 sleep+数据库检查)

<?php
set_time_limit(30); // 允许脚本运行30秒
$lastId = $_GET['last_id'] ?? 0;
$timeout = 25; // 最长等待25秒
$start = time();
while (time() - $start < $timeout) {
    // 查询数据库
    $stmt = $pdo->prepare("SELECT * FROM announcements WHERE id > ?");
    $stmt->execute([$lastId]);
    $data = $stmt->fetch();
    if ($data) {
        echo json_encode($data);
        exit;
    }
    sleep(2); // 每2秒检查一次,避免疯狂查库
}
echo json_encode(['timeout' => true]); // 超时,客户端重连

注意:PHP长轮询在高并发下性能较差,建议用Swoole/Workerman或Node.js替代。

方案3:WebSocket(推荐用于高实时性需求)

原理:建立持久TCP连接,服务器可以主动推送数据,这是真正的“推送”。

优点:真正的实时推送,延迟极低(毫秒级),节省带宽。 缺点:需要额外的WebSocket服务器(通常不是Apache/Nginx),实现稍复杂。

推荐工具

  1. Swoole(PHP扩展) —— 直接在PHP生态内实现WebSocket服务器。
  2. Workerman —— 纯PHP的socket框架,简单易用。
  3. Node.js + Socket.IO —— 如果团队熟悉Node,这是最成熟的选择。

以Workerman为例

  • 安装composer require workerman/workerman

  • 服务器端(server.php

      <?php
      require_once __DIR__ . '/vendor/autoload.php';
      use Workerman\Worker;
      use Workerman\Lib\Timer;
      $ws_worker = new Worker('websocket://0.0.0.0:2346');
      $ws_worker->count = 4; // 进程数
      // 存储所有连接的客户端
      $ws_worker->onConnect = function($connection) {
          // 可以选择将连接加入群组,或标记用户
      };
      $ws_worker->onMessage = function($connection, $data) {
          // 通常客户端只认证,不发送消息
      };
      // 定时器:每10秒检查数据库是否有新公告
      $ws_worker->onWorkerStart = function($worker) {
          Timer::add(10, function() use ($worker) {
              // 查询数据库最新公告(需带上次推送的ID)
              // 如果有新公告,遍历$worker->connections并推送
              foreach ($worker->connections as $conn) {
                  $conn->send(json_encode(['title' => '新公告', 'content' => '...']));
              }
          });
      };
      Worker::runAll();
  • 客户端JavaScript

      let ws = new WebSocket('ws://yourdomain.com:2346');
      ws.onmessage = function(event) {
          let data = JSON.parse(event.data);
          showAnnouncement(data);
      };

方案4:Server-Sent Events (SSE) —— 服务器单向推送

原理:HTML5标准,客户端通过EventSource对象订阅服务器事件流,服务器返回text/event-stream格式的数据。

优点:比WebSocket简单(不需要额外协议),原生支持,自动重连;非常适合“公告”这种服务器单向推送场景。 缺点:不支持IE(支持Edge),只能是文本消息,不适合双向通信。

实现

  • PHP端点(sse.php

      <?php
      header('Content-Type: text/event-stream');
      header('Cache-Control: no-cache');
      header('Connection: keep-alive');
      $lastId = $_GET['last_id'] ?? 0;
      while (true) {
          $data = checkDatabaseForNewAnnouncement($lastId); // 你的查询逻辑
          if ($data) {
              echo "id: {$data['id']}\n";
              echo "event: announcement\n";
              echo "data: " . json_encode($data) . "\n\n";
              ob_flush();
              flush();
          }
          sleep(5); // 每5秒检查一次
          if (connection_aborted()) break;
      }
  • 前端

      var source = new EventSource('sse.php');
      source.addEventListener('announcement', function(e) {
          var data = JSON.parse(e.data);
          showAnnouncement(data);
      });

技术选型建议

场景 推荐方案 原因
企业内部系统、管理后台 轮询 或 SSE 实现简单,用户数少,实时性要求不高
社区、论坛、新闻门户 SSE 或 WebSocket (Workerman) 中等实时性,支持自动重连,兼容性好
即时聊天、直播互动、游戏 WebSocket (Swoole/Node) 毫秒级延迟,双向通信,高并发
系统维护通知、紧急公告 WebSocket + 消息队列 低延迟,可配合Redis发布订阅实现跨进程推送
不希望引入额外服务器/进程 轮询 最兼容,无需额外维护,适合传统LAMP架构

升级与优化

  1. 消息队列(Redis Pub/Sub, RabbitMQ):当公告发布时,后台将消息推送到队列,WebSocket服务器从队列中消费并推送给客户端,解耦发布和推送,避免每次轮询数据库。
  2. 用户分组推送:例如只向在线用户或特定用户组(VIP)推送公告,可以在WebSocket连接握手时,解析用户身份并分组。
  3. 断线重连:WebSocket客户端(使用socket.io或原生)应实现自动重连逻辑,并带上last_message_id,重连后拉取离线期间错过的公告。
  4. 安全与鉴权:对于SSE/WebSocket,应在连接建立时校验用户token(例如通过URL参数或WebSocket握手头),防止任意客户端接入。

最终推荐(懒人版)

  • 快速集成:如果项目已使用Laravel,推荐 Laravel WebSocketsLaravel Reverb(Laravel 11官方推荐),结合其广播系统。
  • 小项目自建:使用 SSE,PHP原生支持,代码量最少,适合公告推送。
  • 大型项目:单独起一个 Node.jsGo 服务做WebSocket推送,PHP只负责发布消息到Redis/消息队列。

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