1

I wanted to create a .php file, that streams a video! Now, the problem is, that it works, only if i use a normal readfile(), but then, you can not go back and forward in the video, so i searched on google, to find this code:

(basically, the HTTP_RANGE does not work, NEVER, i do not know why, when testing it, it always fires my die("lol?");, so it clearly does not support it for some reason) (the die() function is left there on purpose, it will be taken out if it would work..)

(note that i changed "$size = filesize($file);" to "$size = filesize(".".$file);", because someone mentioned that this is required, and "filesize($file);" does not work for me anyways, it always fires an error)!

(and, the $file, shows the actual path for my file, nothing replaced, its how it looks in the original php of me!)

<?php
// Clears the cache and prevent unwanted output
ob_clean();
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
apache_setenv('no-gzip', 1);
ini_set('zlib.output_compression', 'Off');

$file = "/cdn4-e663/zw4su8jiy8skgvizihsjehj/2038tkusi9u848sui7zh/2q3z6hjk97ujduz/a1-cdn/9zw35jbmhkk47wi63uu7.mp4"; // The media file's location
$mime = "application/octet-stream"; // The MIME type of the file, this should be replaced with your own.
$size = filesize(".".$file); // The size of the file

// Send the content type header
header('Content-type: ' . $mime);

// Check if it's a HTTP range request
if(isset($_SERVER['HTTP_RANGE'])){
    // Parse the range header to get the byte offset
    $ranges = array_map(
        'intval', // Parse the parts into integer
        explode(
            '-', // The range separator
            substr($_SERVER['HTTP_RANGE'], 6) // Skip the `bytes=` part of the header
        )
    );

    // If the last range param is empty, it means the EOF (End of File)
    if(!$ranges[1]){
        $ranges[1] = $size - 1;
    }

    // Send the appropriate headers
    header('HTTP/1.1 206 Partial Content');
    header('Accept-Ranges: bytes');
    header('Content-Length: ' . ($ranges[1] - $ranges[0])); // The size of the range

    // Send the ranges we offered
    header(
        sprintf(
            'Content-Range: bytes %d-%d/%d', // The header format
            $ranges[0], // The start range
            $ranges[1], // The end range
            $size // Total size of the file
        )
    );

    // It's time to output the file
    $f = fopen($file, 'rb'); // Open the file in binary mode
    $chunkSize = 8192; // The size of each chunk to output

    // Seek to the requested start range
    fseek($f, $ranges[0]);
    die("working?");
    // Start outputting the data
    while(true){
        // Check if we have outputted all the data requested
        if(ftell($f) >= $ranges[1]){
            break;
        }

        // Output the data
        echo fread($f, $chunkSize);

        // Flush the buffer immediately
        ob_flush();
        flush();
    }
}
else {
    die("lol?");
    header('Content-Length: ' . $size);

    // Read the file
    readfile($file);

    // and flush the buffer
    ob_flush();
    flush();
}
?>

so, the die("lol?"); was added by me to see if the

if(isset($_SERVER['HTTP_RANGE'])){ 
   /*function fires or not, and no, as it seems it returns FALSE every time..8/ 
}

so i wanted to ask you all, how can i fix this? i really want to use php to stream my video, because of security reasons, and because i like it, i already use this methode with images but its a different code(and working)!

I am using Apache 2.4 (Windows 10 - 64bit PC) with the latest version of PHP7, but it seems that apache does not support HTTP_RANGE? am i missing something, is there something i need to enable inside either the php.ini or the httpd.conf??

Thank you in advance, i hope someone can tells me what to do, because i really am stuck here, and i tried ALL examples of mp4 video streaming i could find on google, and none worked for me :/

Pradeep
  • 9,667
  • 13
  • 27
  • 34
Thromet
  • 35
  • 8
  • So the only reason it could be going into the `die` part is because `$_SERVER['HTTP_RANGE']` is not set. But that comes from the request made by the user agent, so is not guaranteed. https://stackoverflow.com/questions/35337958/serverhttp-range-returns-null-every-time – Andy Aug 04 '17 at 15:09
  • @Andy soo? i am very unexperienced with php, apache and so on, what could be the solution for this? i tested it in google chrome, and internet explorer! – Thromet Aug 04 '17 at 15:17
  • If you're inexperienced with Apache/PHP then I'm afraid you have little chance of getting this working. There's a good overview of it here: https://stackoverflow.com/questions/157318/resumable-downloads-when-using-php-to-send-the-file. You need to understand it's not just based on the *response* given by the server, it is very much also based on the *request* headers sent from the client. You don't show anywhere in your code how you are making the request which is where I suspect the problem may be. – Andy Aug 04 '17 at 15:28
  • @Andy well, i can very much assure you, that i know how to set content headers, and that it does not make it working, i tried setting te accept range, the content type, the content length and so on, but as all of these methodes did not work for me either, i thought it would not make a difference then, thus why in the code shown in this post from me, does not contain them – Thromet Aug 04 '17 at 15:31
  • Try this: https://stackoverflow.com/questions/10189811/how-to-enable-the-use-of-http-range-on-server. If the output from that script is "no" then you are not setting the request headers properly. What output do you get from this please? – Andy Aug 04 '17 at 15:34
  • @Andy i am getting a clear "no" when running it – Thromet Aug 04 '17 at 15:36
  • Right, so you aren't setting the *REQUEST* (not the response!) headers properly... even though in your previous comment you were quite sure you were. Maybe take a look into that. There's plenty of info on that link. – Andy Aug 04 '17 at 15:36
  • @Andy ,look, shouldn't that be considered setting headers properly ? – Thromet Aug 04 '17 at 15:38
  • Do you understand the difference between request and response? As in the request your browser/client is making, and the response that the server (php/apache) is giving - are two totally separate things? The script you've posted is on the server and generates a response. However, your client is not sending the appropriate request headers (note REQUEST headers - nothing to do with *response* headers), which is why it goes into the `die` statement. Sorry I can't help you beyond this if you don't know the difference between these 2 fundamental things. – Andy Aug 04 '17 at 15:39
  • @Andy mhm ok.. sad to hear that, maybe i can get it to work someday then, thank you for trying to help anyways – Thromet Aug 04 '17 at 15:43
  • I'm going to post a screenshot that may help you as an answer, 1 min... – Andy Aug 04 '17 at 15:44
  • I've posted an answer, hope this helps you. – Andy Aug 04 '17 at 15:52

1 Answers1

1

There are 2 parts to this:

  • The request made by the browser/client. This must send appropriate request headers.
  • The response given by your server. This is done by your PHP script and must also send the appropriate response headers

When you try and stream your video (or whatever the content is) open the Network tab in your browser.

Look at the Request Headers (in Chrome this is under the Network tab). I've posted a screenshot below. Note that in the request there is a Range: parameter. If this is not present in the request, you'll have problems. This is what tells the PHP script on the server that you are doing a range request in the first place. If the server does not see this header in the request then it will just bypass the if statement and go into the die.

Note that the Range: request header is not normally included in requests by default, so unless you are specifying this, it will never work. If you don't see it in the Request Headers on your Network tab, it is not present, and you need to fix that.

enter image description here

You may also want to examine the response headers - which are totally different from the request headers. Again, these can be seen in the Network tab in your browser. See below for the appropriate headers that must be set:

enter image description here

Going back to the original question, none of it has anything to do with the response (which is what you were describing). The initial problem you are having is all to do with how you're making the request and the fact it does not contain a Range: header, when it must do so.

Community
  • 1
  • 1
Andy
  • 5,142
  • 11
  • 58
  • 131