php 实现边播边下载
边播边下载的实现原理
边播边下载(也称为流式下载或渐进式下载)的核心是将媒体文件分块下载并实时播放。PHP作为服务端语言,主要负责处理文件的分块传输和响应客户端的范围请求(Range Request)。
设置HTTP头部支持范围请求
服务端需要正确响应客户端的Range头部,返回206 Partial Content状态码和Content-Range头部。以下是一个简单的PHP实现示例:
$filePath = 'path/to/video.mp4';
$fileSize = filesize($filePath);
$chunkSize = 1024 * 1024; // 1MB chunks
if (isset($_SERVER['HTTP_RANGE'])) {
$range = $_SERVER['HTTP_RANGE'];
$range = str_replace('bytes=', '', $range);
list($start, $end) = explode('-', $range);
$start = intval($start);
$end = $end ? intval($end) : min($start + $chunkSize, $fileSize - 1);
header('HTTP/1.1 206 Partial Content');
header('Content-Rength: ' . ($end - $start + 1));
header('Content-Range: bytes ' . $start . '-' . $end . '/' . $fileSize);
} else {
$start = 0;
$end = min($chunkSize, $fileSize - 1);
header('Content-Length: ' . $fileSize);
}
header('Content-Type: video/mp4');
header('Accept-Ranges: bytes');
读取并输出文件块
在设置好头部后,需要读取文件的指定部分并输出给客户端:

$handle = fopen($filePath, 'rb');
fseek($handle, $start);
$bufferSize = 8192;
$currentPosition = $start;
while (!feof($handle) && $currentPosition <= $end) {
if (connection_aborted()) {
break;
}
$readSize = min($bufferSize, $end - $currentPosition + 1);
echo fread($handle, $readSize);
flush();
$currentPosition += $readSize;
}
fclose($handle);
客户端HTML5视频实现
在客户端使用HTML5的<video>标签即可实现边播边下载:
<video controls width="640" height="360">
<source src="video_stream.php" type="video/mp4">
Your browser does not support the video tag.
</video>
优化下载性能
对于大文件,可以调整$chunkSize的值来优化性能。较小的块可以更快开始播放,但可能增加服务器负载。较大的块可以减少请求次数,但延迟初始播放。

// 根据网络条件动态调整块大小
$connectionSpeed = 0; // 可以添加逻辑检测连接速度
$chunkSize = $connectionSpeed > 1024 ? 2 * 1024 * 1024 : 1024 * 1024;
处理并发请求
对于高并发场景,可以考虑使用内存映射文件提高性能:
$fd = fopen($filePath, 'rb');
$mmap = mmap($fd, $end - $start + 1, PROT_READ, MAP_SHARED);
echo substr($mmap, $start, $end - $start + 1);
munmap($mmap);
fclose($fd);
安全注意事项
确保对文件路径进行验证,防止目录遍历攻击:
$requestedFile = basename($_GET['file']);
$filePath = 'videos/' . $requestedFile;
if (!file_exists($filePath) || !is_file($filePath)) {
header('HTTP/1.1 404 Not Found');
exit;
}
缓存控制
添加适当的缓存控制头部可以减少重复请求:
header('Cache-Control: max-age=3600, public');
header('Expires: ' . gmdate('D, d M Y H:i:s', time() + 3600) . ' GMT');
以上实现提供了PHP边播边下载的基本框架,可以根据具体需求进一步优化和扩展。






