It took me a long time to find how to stream video(video stream, my keyword, so I put this here so Yoast SEO will give me a higher score) via PHP without giving the URL to the end user.I needed to find a solution, as me and NerdOfCode are working on a streaming service, which is top secret for now, so I won’t put our plans here. Anyways, I hope this helps you.

Why would you need to do this?

The biggest reason you might need to ever do this is if you want to create content that’s only accessible to logged in users. You want to make sure they can’t just go to, because then they can just bypass your login system.

Let’s get to the video stream code!

First things first, disable directory indexing. If you want people to not find out where your filenames are, be sure to add the following in your apache config or .htaccess file:

Options -Indexes

and a 403 page will appear instead of a list of all your member-only content. Now, it’s important to mention that you will need PHP, and this will add strain to your server, because PHP needs to process the video, instead of just having the browser do all the hard work. The following works for files that are really small:

$file = "test.mp4";

but, this requires PHP to load the whole thing at once, which you don’t want. So, here’s how you do it more efficiently:

$file = 'video360p.mp4';
$fp = @fopen($file, 'rb');
$size = filesize($file); // File size
$length = $size; // Content length
$start = 0; // Start byte
$end = $size - 1; // End byte
header('Content-type: video/mp4');
//header("Accept-Ranges: 0-$length");
header("Accept-Ranges: bytes");
if (isset($_SERVER['HTTP_RANGE'])) {
    $c_start = $start;
    $c_end = $end;
    list(, $range) = explode('=', $_SERVER['HTTP_RANGE'], 2);
    if (strpos($range, ',') !== false) {
        header('HTTP/1.1 416 Requested Range Not Satisfiable');
        header("Content-Range: bytes $start-$end/$size");

    if ($range == '-') {
        $c_start = $size - substr($range, 1);
        $range = explode('-', $range);
        $c_start = $range[0];
        $c_end = (isset($range[1]) && is_numeric($range[1])) ? $range[1] : $size;
    $c_end = ($c_end > $end) ? $end : $c_end;

    if ($c_start > $c_end || $c_start > $size - 1 || $c_end >= $size) {
        header('HTTP/1.1 416 Requested Range Not Satisfiable');
        header("Content-Range: bytes $start-$end/$size");
    $start = $c_start;
    $end = $c_end;
    $length = $end - $start + 1;
    fseek($fp, $start);
    header('HTTP/1.1 206 Partial Content');
header("Content-Range: bytes $start-$end/$size");
header("Content-Length: ".$length);
$buffer = 1024 * 8;
while(!feof($fp) && ($p = ftell($fp)) <= $end) {
    if ($p + $buffer > $end) {
        $buffer = $end - $p + 1;
    echo fread($fp, $buffer);

Thanks to

I did NOT write this, I found this on GitHub here. It’s licensed under the MIT license, so you can use it for commercial use, as long as you mention that TuxxIn made it.

Leave any alternatives or better ways in the comments!