PHP项目直播后台如何使用PHP开发

wen PHP项目 24

本文目录导读:

PHP项目直播后台如何使用PHP开发

  1. 核心技术栈选型
  2. 核心业务流程与PHP代码实现
  3. 关键架构图
  4. 注意事项与性能优化
  5. 如果不会用SRS/Nginx配置怎么办?

开发一个PHP直播后台系统,主要涉及推流管理直播流调度用户鉴权录制/转码以及播放器对接等核心功能。

由于PHP本身不擅长直接处理底层的RTMP/RTSP协议(这类工作通常由Nginx、SRS、FFmpeg等工具完成),PHP在直播后台中的角色通常是业务逻辑层(API服务)和控制管理后台

以下是使用PHP开发直播后台的完整技术方案和核心代码思路:

核心技术栈选型

功能模块 推荐技术/工具 说明
流媒体服务器 SRS、Nginx-RTMP、ZLMediaKit 核心推流/拉流,PHP不直接实现,通过API控制
视频处理 FFmpeg 转码、截图、录制
PHP框架 Laravel、ThinkPHP 6/8、Webman 快速开发API和后台管理
协议支持 HLS、HTTP-FLV、WebRTC(转) 前端播放,PHP生成鉴权URL
消息队列 Redis Stream、RabbitMQ 异步处理录制、转码、回调
实时通信 WebSocket + PHP (Workerman/Swoole) 实时推送在线人数、弹幕、状态变更

核心业务流程与PHP代码实现

直播流创建与推流地址生成(鉴权)

用户发起直播时,后台需要生成唯一的推流地址(rtmp://domain/live/{stream_key}),并验证用户身份。

// 使用Laravel框架示例
namespace App\Services;
use Illuminate\Support\Str;
use Illuminate\Support\Facades\Cache;
use App\Models\LiveRoom;
class LiveStreamService
{
    /**
     * 创建一场直播并生成推流地址
     * @param int $userId 主播用户ID
     * @return array
     */
    public function createStream(int $userId): array
    {
        // 1. 生成唯一的流密钥(Stream Key)
        $streamKey = Str::uuid()->toString();
        // 2. 生成推流鉴权签名(预防盗推)
        $secret = env('PUSH_SECRET_KEY'); // 后台配置的密钥
        $expire = time() + 3600; // 1小时有效
        $sign = md5("/live/{$streamKey}-{$expire}-{$secret}");
        $pushUrl = "rtmp://push.yourdomain.com/live/{$streamKey}?txSecret={$sign}&txTime={$expire}";
        // 3. 写入数据库(状态为待推流)
        LiveRoom::create([
            'user_id' => $userId,
            'stream_key' => $streamKey,
            'status' => 'waiting',
            'created_at' => now()
        ]);
        return [
            'push_url' => $pushUrl,
            'play_urls' => [
                'hls' => "https://play.yourdomain.com/live/{$streamKey}.m3u8",
                'flv' => "https://play.yourdomain.com/live/{$streamKey}.flv"
            ]
        ];
    }
}

回调处理(PHP接收流媒体服务器通知)

流媒体服务器(如SRS)在推流开始、结束、录制完成时会POST请求你PHP服务器的回调地址。

// routes/api.php
Route::post('/callback/streaming', [StreamCallbackController::class, 'handle']);
// StreamCallbackController.php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Models\LiveRoom;
class StreamCallbackController extends Controller
{
    public function handle(Request $request)
    {
        // 验证签名(防止伪造回调)
        // 此处省略验证逻辑
        $event = $request->input('action'); // publish, unpublish, record_mp4等
        $streamKey = $request->input('stream_id');
        $clientIp = $request->input('client_ip');
        $room = LiveRoom::where('stream_key', $streamKey)->first();
        if (!$room) {
            return response()->json(['code' => 404]);
        }
        switch ($event) {
            case 'publish': // 推流开始
                $room->update([
                    'status' => 'live',
                    'stream_start_time' => now(),
                    'push_ip' => $clientIp
                ]);
                // 可以发送WebSocket通知前端主播已开播
                break;
            case 'unpublish': // 推流结束
                $room->update([
                    'status' => 'end',
                    'stream_end_time' => now(),
                    'duration' => $room->stream_start_time->diffInSeconds(now())
                ]);
                // 触发录制文件转存逻辑
                break;
            case 'record_mp4': // 录制文件生成完成
                $recordFile = $request->input('file_path');
                // 异步转换为点播视频(可投递到队列)
                break;
        }
        return response()->json(['code' => 0]);
    }
}

播放鉴权与防盗链

播放地址同样需要签名,防止被任意盗用。

public function generatePlayUrl(string $streamKey): string
{
    $secret = env('PLAY_SECRET_KEY');
    $expire = time() + 3600;
    $sign = md5("/live/{$streamKey}-{$expire}-{$secret}");
    return "https://play.yourdomain.com/live/{$streamKey}.flv?sign={$sign}&expire={$expire}";
}
// 在Nginx层验证播放签名(使用Lua或Nginx Secure Link模块)
// 或者PHP写一个中间件验证(不推荐,性能较差)

在线人数与实时消息(WebSocket + PHP)

推荐使用Workerman(纯PHP)或Swoole WebSocket服务器处理实时推送。

// 基于Workerman的WebSocket服务(需要独立运行)
use Workerman\Worker;
use Workerman\Lib\Timer;
$ws_worker = new Worker('websocket://0.0.0.0:8282');
$ws_worker->count = 4;
// 存储所有连接的客户端(按直播间分组)
$connections = [];
$ws_worker->onConnect = function ($connection) {
    // 客户端连接时,等待发送join房间消息
};
$ws_worker->onMessage = function ($connection, $data) use (&$connections) {
    $msg = json_decode($data, true);
    if ($msg['type'] == 'join') {
        $roomId = $msg['room_id'];
        $connections[$roomId][] = $connection;
        $connection->roomId = $roomId;
        // 广播在线人数
        $count = count($connections[$roomId]);
        $msg = json_encode(['type' => 'online_count', 'count' => $count]);
        foreach ($connections[$roomId] as $conn) {
            $conn->send($msg);
        }
    }
};
$ws_worker->onClose = function ($connection) use (&$connections) {
    if (isset($connection->roomId, $connections[$connection->roomId])) {
        // 移除断开的客户端
        $connections[$connection->roomId] = array_filter($connections[$connection->roomId], function($c) use ($connection) {
            return $c != $connection;
        });
    }
};
Worker::runAll();

PHP后台可以通过Redis Pub/Sub 发送消息到WebSocket服务器,实现弹幕、礼物通知等。

异步任务处理(录制转码、截图等)

使用队列(Laravel Job 或 ThinkPHP Queue)异步执行耗时操作。

// 触发转码任务
namespace App\Jobs;
use Illuminate\Bus\Queueable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
class TranscodeVideoJob implements ShouldQueue
{
    use InteractsWithQueue, Queueable, SerializesModels;
    protected $inputPath;
    protected $outputPath;
    public function handle()
    {
        // 调用FFmpeg
        $command = "ffmpeg -i {$this->inputPath} -c:v libx264 -c:a aac -hls_time 10 -hls_list_size 0 -f hls {$this->outputPath}";
        exec($command, $output, $returnCode);
        // 更新数据库状态
    }
}

关键架构图

sequenceDiagram
    participant 主播
    participant 推流端(OBS)
    participant PHP后端
    participant 流媒体服务器(SRS)
    participant 观众前端
    participant WebSocket服务器
    主播->>PHP后端: 创建直播 (生成推流地址)
    PHP后端-->>主播: 返回推流URL
    主播->>推流端: 输入RTMP地址
    推流端->>流媒体服务器: 推流
    流媒体服务器->>PHP后端: 回调 (on_publish)
    PHP后端->>数据库: 更新状态为直播中
    PHP后端->>WebSocket服务器: 发布开播事件
    WebSocket服务器-->>观众前端: 推送主播开播通知
    观众前端->>PHP后端: 请求播放地址 (带鉴权)
    PHP后端-->>观众前端: 返回签名后的FLV/HLS地址
    观众前端->>流媒体服务器: 拉流播放
    WebSocket服务器-->>观众前端: 实时推送聊天/礼物/人数

注意事项与性能优化

  1. 不要在PHP中直接处理RTMP数据包,PHP的IO模型不适合,所有流媒体工作交给Nginx-rtmp、SRS或M7s。
  2. 回调验证:务必验证流媒体服务器回调的iptoken,防止恶意伪造请求。
  3. 数据库设计:直播流表要有stream_keystatus(live/end/replay)、start_timeend_time索引。
  4. 大并发:PHP-FPM不擅长长连接,在线人数、聊天请务必使用Swoole/Workerman维护长连接。
  5. 录制存储:录制文件建议直接写到OSS(阿里云/腾讯云/COS),并用PHP生成临时访问URL
  6. 转码:如果只有PHP开发能力,腾讯云/阿里云直播服务提供现成的转码API(LVB),可以直接调用SDK。

如果不会用SRS/Nginx配置怎么办?

推荐使用腾讯云直播(CSS)阿里云直播的API:

  • 前端推流地址:rtmp://push.xxx.com/live/{stream_id}?bizid=xxx&txSecret=xxx
  • PHP只需要调用云厂商的CreateLiveStream等API,无需自己搭流媒体服务器。
  • 回调处理逻辑与自建完全一致,只是请求参数不同。

这种方案PHP开发量最少,但会产生云服务费用。


PHP直播后台的核心是鉴权生成推拉流地址处理回调管理直播间状态以及实时消息推送,流媒体转发和视频编解码依赖SRS/FFmpeg等外部服务,使用Laravel+Workerman可以开发出一个功能完整的直播后台管理系统。

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