2

Let's say I have a video on a remote server and this its url

"http://domain/video-path/video.mp4"

What is the correct way to stream this video using php with seekable..

I know how to stream the video using fopen and fread but it can't seek with remote file

Mr Faisal
  • 74
  • 1
  • 6

2 Answers2

7

I'm using this, working both local & external video, seekable & resumable

ini_set('max_execution_time', 0);
$useragent = "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.96 Safari/537.36";
$v = $_GET['url'];
$ch = curl_init();
curl_setopt($ch, CURLOPT_VERBOSE, 1);
curl_setopt($ch, CURLOPT_TIMEOUT, 222222);
curl_setopt($ch, CURLOPT_URL, $v);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_HEADER, true);
curl_setopt($ch, CURLOPT_FRESH_CONNECT, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($ch, CURLOPT_USERAGENT, $useragent);
curl_setopt($ch, CURLOPT_NOBODY, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$info = curl_exec($ch);
$size2 = curl_getinfo($ch, CURLINFO_CONTENT_LENGTH_DOWNLOAD);
header("Content-Type: video/mp4");
$filesize = $size2;
$offset = 0;
$length = $filesize;
if (isset($_SERVER['HTTP_RANGE'])) {
    $partialContent = "true";
    preg_match('/bytes=(\d+)-(\d+)?/', $_SERVER['HTTP_RANGE'], $matches);
    $offset = intval($matches[1]);
    $length = $size2 - $offset - 1;
} else {
    $partialContent = "false";
}
if ($partialContent == "true") {
    header('HTTP/1.1 206 Partial Content');
    header('Accept-Ranges: bytes');
    header('Content-Range: bytes '.$offset.
        '-'.($offset + $length).
        '/'.$filesize);
    header("Content-length: ".$length); // added
} else {
    header('Accept-Ranges: bytes');
    header("Content-length: ".$size2); // added
}

// header("Content-length: ".$size2); // removed
$ch = curl_init();
if (isset($_SERVER['HTTP_RANGE'])) {
    // if the HTTP_RANGE header is set we're dealing with partial content
    $partialContent = true;
    // find the requested range
    // this might be too simplistic, apparently the client can request
    // multiple ranges, which can become pretty complex, so ignore it for now
    preg_match('/bytes=(\d+)-(\d+)?/', $_SERVER['HTTP_RANGE'], $matches);
    $offset = intval($matches[1]);
    $length = $filesize - $offset - 1;
    $headers = array(
        'Range: bytes='.$offset.
        '-'.($offset + $length).
        ''
    );
    curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
}
curl_setopt($ch, CURLOPT_VERBOSE, 1);
curl_setopt($ch, CURLOPT_TIMEOUT, 222222);
curl_setopt($ch, CURLOPT_URL, $v);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_HEADER, false);
curl_setopt($ch, CURLOPT_FRESH_CONNECT, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($ch, CURLOPT_USERAGENT, $useragent);
curl_setopt($ch, CURLOPT_NOBODY, false);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, false);
curl_exec($ch);
John Doe
  • 245
  • 3
  • 14
  • 1
    same @Milad -- i've come up with a new solution that works for me https://stackoverflow.com/a/54884346/296346 – Tim Feb 26 '19 at 14:25
  • this work very well for youtube video (*.googlevideo.com) – Fthr Sep 13 '19 at 01:49
  • hi John Doe, this script working on my local pc but when I run this on my server its not working. its just loading and after some time showing 500 internal server error Request Timeout. can you please help me to run this on my server. – Pawan Developers Sep 01 '22 at 14:31
3

After the other answers on this hadn't been working for me, I've finally found (after much tweaking) a new solution to this which is working for remote/local files.

<?php 

$file = 'https://yourfilelocation';

$head = array_change_key_case(get_headers($file, TRUE));
$size = $head['content-length']; // because filesize() won't work remotely

header('Content-Type: video/mp4');
header('Accept-Ranges: bytes');
header('Content-Disposition: inline');
header('Content-Length:'.$size);

readfile($file);

exit;

?>

This allows tracking etc. too, enjoy!

Tim
  • 6,986
  • 8
  • 38
  • 57
  • It works, it plays the video when it's downloaded completely on your server but still doesn't stream the video. – Milad Rahimi Feb 27 '19 at 06:24
  • i've found that with the `accept-ranges: bytes` header it will show the content as it downloads (streams) – Tim Feb 27 '19 at 10:54