PHP项目怎么实现直播推流?

wen java案例 3

本文目录导读:

PHP项目怎么实现直播推流?

  1. 方案一:第三方云平台(最推荐,成本最低、最稳定)
  2. 方案二:自建服务器 + Nginx-RTMP 模块(中小规模,适合内网或开发环境)
  3. 方案三:WebRTC 推流到自建服务器(低延迟,现代方案)
  4. 方案四:纯 PHP 尝试推流(极不推荐,仅供了解)
  5. 总结与建议

在PHP项目中实现直播推流,通常遵循一个核心原则:PHP本身不擅长处理长时间、高并发的流媒体数据,因此PHP的角色通常是作为“控制层”或“业务调度层”,而真正的推流工作由专门的流媒体服务器(如Nginx + RTMP、SRS、ZLMediaKit)或第三方云平台完成。

下面是几种主流且可行的实现方案,按推荐度从高到低排列:

第三方云平台(最推荐,成本最低、最稳定)

这是企业级项目最常用的方式,PHP只负责生成推流地址(鉴权)和调用API,推流由客户端(OBS、手机APP、浏览器)直接完成。

流程:

  1. PHP后端:调用腾讯云/阿里云/声网等平台的API,生成一路“推流地址”和“播流地址”,存入数据库,通常包含 rtmp://publish.com/live/streamName?txSecret=xxx 格式。
  2. 客户端(前端):从PHP后端获取推流地址,如果是OBS,直接填入地址;如果是Web,使用WebRTCFlv.js+MediaRecorder推流。
  3. 云平台:负责接收RTMP/WebRTC流,进行转码、分发。
  4. 播放器:PHP输出播放地址(HLS/FLV/WebRTC)给前端。

PHP代码示例(以腾讯云为例):

<?php
// 假设使用腾讯云云直播 (CSS)
require_once 'vendor/autoload.php'; // 引入SDK
function generatePushUrl($streamName, $key, $domain = 'yourpushdomain.com') {
    $appName = 'live';
    $txTime = strtoupper(dechex(strtotime('+1 day'))); // 过期时间
    $txSecret = md5($key . $streamName . $txTime);
    return "rtmp://{$domain}/{$appName}/{$streamName}?txSecret={$txSecret}&txTime={$txTime}";
}
// 使用
$pushUrl = generatePushUrl('stream_123', 'your_secret_key');
echo $pushUrl; // 返回RTMP地址给前端

适用场景: 任何需要快速上线、稳定可靠的直播项目,缺点是有流量费用。

自建服务器 + Nginx-RTMP 模块(中小规模,适合内网或开发环境)

在服务器上搭建nginx-rtmp-module,PHP通过执行系统命令或FFmpeg进行推流。

环境搭建:

# 安装 Nginx 及 RTMP 模块(以 Ubuntu 为例)
sudo apt install nginx libnginx-mod-rtmp

Nginx配置(/etc/nginx/nginx.conf):

rtmp {
    server {
        listen 1935; # RTMP默认端口
        chunk_size 4096;
        application live { # 应用名,推拉流时使用
            live on;
            record off;
        }
    }
}

PHP实现推流:

PHP通过 exec()proc_open() 调用 ffmpeg 将本地文件或摄像头流转发给Nginx-RTMP,注意:这会导致PHP进程长时间阻塞,因此必须使用异步方式,

<?php
// 方案A:后台执行FFmpeg(不推荐,会产生僵尸进程)
$streamUrl = 'rtmp://你自己的服务器IP/live/stream123';
$inputFile = '/tmp/input_video.mp4'; // 循环推一个视频文件
$ffmpegCmd = "ffmpeg -re -i {$inputFile} -c:v libx264 -f flv {$streamUrl} > /dev/null 2>&1 &";
exec($ffmpegCmd, $output, $returnVar);
echo "推流进程已启动(状态码:$returnVar)";
// 方案B(推荐):使用消息队列 + 守护进程
// 1. PHP 将推流任务发布到 Redis 队列: "push_task:{stream_id}"
// 2. 一个独立的 PHP 脚本或 Go 进程(worker)从队列中读取任务,运行FFmpeg
// 这样PHP请求瞬间返回,不做耗时操作。

适用场景: 学习测试、内网监控直播、对成本敏感但能接受服务器资源消耗的小项目。

WebRTC 推流到自建服务器(低延迟,现代方案)

利用SRSZLMediaKit等支持WebRTC的流媒体服务器,PHP作为信令服务器。

流程:

  1. PHP WebSocket Server(如Workerman/Swoole):处理信令(offer/answer/ICE)。
  2. 客户端浏览器:获取麦克风/摄像头(getUserMedia),创建RTCPeerConnection
  3. PHP将客户端的SDP转发给流媒体服务器,建立P2P连接。
  4. 服务器将WebRTC流转为RTMP或HLS分发。

PHP + Workerman 信令伪代码:

use Workerman\Worker;
$ws_worker = new Worker('websocket://0.0.0.0:8080');
$ws_worker->onMessage = function($connection, $data) {
    $msg = json_decode($data, true);
    if ($msg['type'] == 'offer') {
        // 转发给流媒体服务器指定的端口
        $mediaServer = stream_socket_client('tcp://127.0.0.1:9000');
        fwrite($mediaServer, json_encode(['stream_id' => $msg['id'], 'sdp' => $msg['sdp']]));
    }
    // ...
};

适用场景: 需要毫秒级延迟的互动直播(教育、直播带货PK),但开发难度较大。

纯 PHP 尝试推流(极不推荐,仅供了解)

PHP可以通过解析FLV格式、塞入RTMP协议包来推流,但几乎不可用

// 使用第三方库如 php-rtmp
// 这种方式性能极差,内存泄漏严重,没有实际生产价值。

总结与建议

需求 推荐方案 PHP角色
快速上线,不想管服务器 云平台(推荐) 生成推流地址,调用API
内网/监控/教学演示 Nginx-RTMP 调用FFmpeg后台推流
毫秒级延迟、Web端互动 ZLMediaKit + WebSocket 信令调度 + 业务处理
高性能自建流媒体 SRS + PHP守护进程 业务管理,不参与流数据处理

关键避坑提示:

  1. 绝对不要在PHP的HTTP请求(fpmapache module)中直接执行ffmpeg推流并等待它结束,这会阻塞整个PHP进程,导致超时。
  2. 推荐使用 消息队列(Redis/Beanstalkd)+ 独立的Producer/Consumer架构,PHP只负责推送任务,Worker进程负责长时间推流。
  3. 如果需要从摄像头或屏幕推流(Web端),请使用前端JS的WebRTCFlv.js,PHP只负责提供规则。

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