cinema-studio-pro/backend/stream_video.php
2026-01-13 14:52:37 +05:30

98 lines
2.5 KiB
PHP

<?php
/**
* Video Streaming with Range Request Support
* Enables proper video seeking in browsers
*/
$videoDir = __DIR__ . '/generated_videos';
// Get the requested video file
$file = isset($_GET['file']) ? basename($_GET['file']) : null;
if (!$file) {
http_response_code(400);
die('No file specified');
}
$filePath = $videoDir . '/' . $file;
// Security: ensure file is within video directory
$realPath = realpath($filePath);
$realVideoDir = realpath($videoDir);
if ($realPath === false || strpos($realPath, $realVideoDir) !== 0) {
http_response_code(404);
die('File not found');
}
if (!file_exists($filePath)) {
http_response_code(404);
die('File not found');
}
$fileSize = filesize($filePath);
$mimeType = 'video/mp4';
// Check for Range header
$range = isset($_SERVER['HTTP_RANGE']) ? $_SERVER['HTTP_RANGE'] : null;
if ($range) {
// Parse Range header
list($unit, $rangeSpec) = explode('=', $range, 2);
if ($unit !== 'bytes') {
http_response_code(416);
header("Content-Range: bytes */$fileSize");
die('Invalid range unit');
}
// Parse the range values
$ranges = explode(',', $rangeSpec);
$rangeSpec = trim($ranges[0]); // Only handle first range
list($start, $end) = explode('-', $rangeSpec);
$start = $start === '' ? 0 : intval($start);
$end = $end === '' ? $fileSize - 1 : intval($end);
// Validate range
if ($start < 0 || $start >= $fileSize || $end >= $fileSize || $start > $end) {
http_response_code(416);
header("Content-Range: bytes */$fileSize");
die('Invalid range');
}
$length = $end - $start + 1;
// Send partial content headers
http_response_code(206);
header('Content-Type: ' . $mimeType);
header('Accept-Ranges: bytes');
header("Content-Range: bytes $start-$end/$fileSize");
header("Content-Length: $length");
header('Cache-Control: public, max-age=86400');
// Output the requested range
$fp = fopen($filePath, 'rb');
fseek($fp, $start);
$bytesRemaining = $length;
$bufferSize = 8192;
while ($bytesRemaining > 0 && !feof($fp)) {
$readSize = min($bufferSize, $bytesRemaining);
echo fread($fp, $readSize);
$bytesRemaining -= $readSize;
flush();
}
fclose($fp);
} else {
// No range requested - send full file
header('Content-Type: ' . $mimeType);
header('Accept-Ranges: bytes');
header("Content-Length: $fileSize");
header('Cache-Control: public, max-age=86400');
readfile($filePath);
}