本文目录导读:

- 方案一:使用现成的推流软件 + PHP调用(最简单,适合初级项目)
- 方案二:PHP 作为 WebRTC 的信令服务器(适合基于浏览器的推流)
- 方案三:集成第三方云直播服务(最推荐,适合大多数商业项目)
- 方案四:使用 Swoole / Workerman 实现高性能推流服务
- 最佳选择
在PHP项目中实现直播推流,通常不是直接由PHP本身完成(因为PHP是脚本语言,不适合处理高并发的视频流媒体数据),而是通过调用外部程序或集成成熟的流媒体服务SDK来实现。
以下是几种主流的实现方案,从简单到复杂排列:
使用现成的推流软件 + PHP调用(最简单,适合初级项目)
这是最快速的方式,PHP只负责发送命令,实际的视频编码和推流由专业软件(如OBS Studio、FFmpeg)完成。
流程:
- 部署流媒体服务器:如 SRS、Nginx-rtmp-module、Wowza、Red5,推荐使用 SRS(Simple-Rtmp-Server),轻量且功能强大。
- PHP 启动推流进程:在PHP代码中,当管理员点击“开始直播”按钮时,使用
exec()或shell_exec()函数调用FFmpeg命令。
<?php
// 假设已经从数据库获取了推流地址和密钥
$rtmpUrl = 'rtmp://your-rtmp-server.com/live';
$streamKey = 'your-stream-key';
// 需要执行的FFmpeg命令
// 这里使用一个示例:推流本地的一个视频文件(也可以推摄像头,但需要设备权限)
// 实际项目中,更常见的是管理员使用OBS手动推流,PHP只做触发或鉴权
$command = "ffmpeg -re -i /path/to/your/video.mp4 -c:v libx264 -preset veryfast -c:a aac -f flv \"{$rtmpUrl}/{$streamKey}\" 2>&1 &";
// 执行命令并在后台运行(& 符号表示后台运行)
exec($command, $output, $return_var);
if ($return_var === 0) {
echo "推流已启动";
} else {
echo "推流启动失败: " . implode("\n", $output);
}
// 注意:这样启动的进程在PHP请求结束后可能结束,实际生产环境需要更健壮的后台进程管理(如supervisor)。
?>
缺点:
- 依赖服务器上必须安装FFmpeg。
- PHP处理耗时任务容易超时。
- 无法直接处理来自浏览器或移动端的实时视频流。
PHP 作为 WebRTC 的信令服务器(适合基于浏览器的推流)
如果希望用户直接在网页上点击“开始直播”,让浏览器推流到服务器,最好的方案是 WebRTC,PHP在这里的角色是信令服务器(交换SDP、ICE Candidate),不处理媒体流本身。
技术栈:
- 前端:WebRTC API (JavaScript)
- 信令:PHP + WebSocket (推荐使用 Ratchet 或 Swoole)
- 媒体转发:Janus-Gateway / LiveKit / MediaSoup
简化流程:
- 用户打开网页,点击“开始直播”。
- 前端JavaScript调用
getUserMedia获取摄像头/麦克风。 - 创建
RTCPeerConnection连接。 - 生成的
Offer SDP通过 AJAX 发送给PHP服务器。 - PHP接收SDP,通过WebSocket 转发给流媒体服务器(如Janus)或其他客户端。
- 流媒体服务器处理后,将视频流转分发出去。
PHP示例(信令部分):
<?php
// 假设这是接收Offer SDP的API接口
if ($_SERVER['REQUEST_METHOD'] === 'POST' && $_POST['action'] === 'offer') {
$sdp = $_POST['sdp'];
$roomId = $_POST['room_id'];
// 将SDP保存到数据库或缓存,或通过WebSocket发送给匹配的参与者
$redis->set("webrtc:offer:{$roomId}", $sdp);
// 等待回答(通常用长轮询或WebSocket实现,这里简化)
while (!$answer = $redis->get("webrtc:answer:{$roomId}")) {
sleep(1);
if (timeout) break;
}
echo json_encode(['sdp' => $answer]);
}
?>
优点:延迟极低(秒级/毫秒级),直接支持浏览器。
缺点:实现复杂,PHP处理WebSocket或长轮询性能开销大,通常建议用Node.js、Go或Python替代PHP的信令功能。
集成第三方云直播服务(最推荐,适合大多数商业项目)
直接使用云服务商提供的SDK和API,PHP只需调用其REST API。
常见服务:腾讯云直播、阿里云直播、七牛云、又拍云、声网(Agora)
流程:
- 在云服务商控制台创建直播推流和播放域名。
- PHP生成推流地址:根据服务商提供的鉴权算法生成带有效期的推流URL。
- 客户端推流:移动端(Android/iOS)或Web端使用服务商提供的SDK进行推流(SDK自带编码和传输)。
- PHP接收回调:云服务商会把推流状态(开始、结束、断流)通过HTTP回调通知你的PHP服务器。
PHP代码示例(生成推流地址 - 以腾讯云为例):
<?php
// 腾讯云直播推流地址生成
function generatePushUrl($domain, $appName, $streamName, $key, $txTime) {
$txSecret = md5($key . $streamName . $txTime);
$ext = "?txSecret={$txSecret}&txTime={$txTime}";
return "rtmp://{$domain}/{$appName}/{$streamName}{$ext}";
}
// 使用
$pushUrl = generatePushUrl(
'your.push.live.com', // 推流域名
'live', // AppName
'stream_key_123', // 流名称
'your_api_key', // 鉴权Key
strtoupper(gmdate('Ymd\THis\Z', time() + 86400)) // 过期时间
);
?>
优点:
- 稳定性极高,BGP加速,全球可用。
- 无需自己维护流媒体服务器。
- PHP代码量极少,只需管理URL和回调。
缺点:按流量/并发收费。
使用 Swoole / Workerman 实现高性能推流服务
如果你必须使用纯PHP并希望处理大量并发流,可以借助 Swoole 扩展,Swoole能让PHP具备常驻内存、异步IO、协程的能力,可以自己实现RTMP协议的接收。
示例(伪代码):
<?php
// 需要一个RTMP协议解析库(如 swoole/rtmp)
$server = new Swoole\Server("0.0.0.0", 1935, SWOOLE_PROCESS, SWOOLE_SOCK_TCP);
$server->on('Receive', function ($server, $fd, $reactor_id, $data) {
// 解析RTMP握手、连接、发布流命令
// 将接收到的视频帧保存到文件或转发
// 这非常复杂,几乎没有人会从零实现
});
$server->start();
?>
警告:
- 不推荐,开发周期长,bug多,性能远不如C++编写的SRS或Nginx。
- 只有在需要深度定制流媒体逻辑且团队有Swoole大牛时才考虑。
最佳选择
| 场景 | 推荐方案 | 说明 |
|---|---|---|
| 课程/会议系统 | 云服务(声网、腾讯云) | 用SDK,成熟度高,延迟低 |
| 企业内部直播 | FFmpeg + SRS | 低成本,部署简单 |
| Web端互动直播 | WebRTC + 信令服务 | 技术挑战大,但能力强 |
| 高并发社交直播 | 云服务 / 方案一(SRS集群) | 建议直接买云服务 |
对于95%的PHP项目,建议采用“方案三:集成第三方云直播服务”,PHP只需要负责业务逻辑(生成推流地址、接收回调、管理用户权限),让专业的流媒体服务做专业的事。