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
  • 2
  • 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
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,838
  • 8
  • 35
  • 55
  • 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