Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
PHP VideoStream class for HTML5 video streaming
<?php
/**
* Description of VideoStream
*
* @author Rana
* @link http://codesamplez.com/programming/php-html5-video-streaming-tutorial
*/
class VideoStream
{
private $path = "";
private $stream = "";
private $buffer = 102400;
private $start = -1;
private $end = -1;
private $size = 0;
function __construct($filePath)
{
$this->path = $filePath;
}
/**
* Open stream
*/
private function open()
{
if (!($this->stream = fopen($this->path, 'rb'))) {
die('Could not open stream for reading');
}
}
/**
* Set proper header to serve the video content
*/
private function setHeader()
{
ob_get_clean();
header("Content-Type: video/mp4");
header("Cache-Control: max-age=2592000, public");
header("Expires: ".gmdate('D, d M Y H:i:s', time()+2592000) . ' GMT');
header("Last-Modified: ".gmdate('D, d M Y H:i:s', @filemtime($this->path)) . ' GMT' );
$this->start = 0;
$this->size = filesize($this->path);
$this->end = $this->size - 1;
header("Accept-Ranges: 0-".$this->end);
if (isset($_SERVER['HTTP_RANGE'])) {
$c_start = $this->start;
$c_end = $this->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 $this->start-$this->end/$this->size");
exit;
}
if ($range == '-') {
$c_start = $this->size - substr($range, 1);
}else{
$range = explode('-', $range);
$c_start = $range[0];
$c_end = (isset($range[1]) && is_numeric($range[1])) ? $range[1] : $c_end;
}
$c_end = ($c_end > $this->end) ? $this->end : $c_end;
if ($c_start > $c_end || $c_start > $this->size - 1 || $c_end >= $this->size) {
header('HTTP/1.1 416 Requested Range Not Satisfiable');
header("Content-Range: bytes $this->start-$this->end/$this->size");
exit;
}
$this->start = $c_start;
$this->end = $c_end;
$length = $this->end - $this->start + 1;
fseek($this->stream, $this->start);
header('HTTP/1.1 206 Partial Content');
header("Content-Length: ".$length);
header("Content-Range: bytes $this->start-$this->end/".$this->size);
}
else
{
header("Content-Length: ".$this->size);
}
}
/**
* close curretly opened stream
*/
private function end()
{
fclose($this->stream);
exit;
}
/**
* perform the streaming of calculated range
*/
private function stream()
{
$i = $this->start;
set_time_limit(0);
while(!feof($this->stream) && $i <= $this->end) {
$bytesToRead = $this->buffer;
if(($i+$bytesToRead) > $this->end) {
$bytesToRead = $this->end - $i + 1;
}
$data = fread($this->stream, $bytesToRead);
echo $data;
flush();
$i += $bytesToRead;
}
}
/**
* Start streaming video content
*/
function start()
{
$this->open();
$this->setHeader();
$this->stream();
$this->end();
}
}

line 39: header("Content-Type: video/mp4");
cannot play .webm file format

you should add:

$ext = strtolower(pathinfo($this->path, PATHINFO_EXTENSION));
switch ($ext)
{
case "mp4":
header("Content-Type: video/mp4");
break;
case "webm":
header("Content-Type: video/webm");
break;
}

I play only 40 second of video?

Why?

ziggi commented May 31, 2015

Very useful. Thank you.

scipper commented Jun 2, 2015

Very nice! solved my problems :)

dirkx commented Sep 1, 2015

May be an idea to add a if(connection_aborted()) near line 104 or as part of the while().

all type video formats are not supported in this code... so please any body help me for all types of video supported streaming code..

Very nice! But The user reload video when streaming ...

too much helpful ,thanks alot.....

harish40 commented Feb 1, 2016

How to use the code & where to replace the video path plzz let me know

nalmada commented Mar 4, 2016

@ranacseruet
works great !!
do you have the same thing for players like VLC and DivX ?

@ghost

ghost commented Mar 8, 2016

Thank you!

Lixus commented Mar 10, 2016

@ranacseruet Thanks for this script! I just noticed that video streaming with this does not work on Android 5 and 6 devices... Any ideas?

Thank you, very nice solution

lynxfg commented Jul 29, 2016

Very nice class !
But the url with http doesn't work :
$stream = new VideoStream(".http://www.exemple.com/video.mp4");
i need a help.
thanks

inanbayram commented Sep 6, 2016

@ranacseruet It's possible to stream multiple video files in one php script?

$stream1 = new VideoStream($file1);
$stream1->start();

$stream2 = new VideoStream($file2);
$stream2->start();

If I try the following code, the script is just serving the first video file. Of course I removed the exit's in the class

ImSeaWorld commented Oct 8, 2016

@annopnod Why are you making an extra variable?

Turn this:
$ext = strtolower(pathinfo($this->path, PATHINFO_EXTENSION)); switch ($ext) { etc etc

Into this:
switch (strtolower(pathinfo($this->path, PATHINFO_EXTENSION))) { etc etc

You are never going to use $ext again. No point in adding variables that are not going to be used.

EDIT: A better way you could do this, is use an array. Line 39 with the Content-Type header can be turned into a "one-liner".

I added on line 16, the video formats allowed for html(could be more than listed):
private $videoFormats = array("mp4"=>"video/mp4", "webm"=>"video/webm", "ogg"=>"video/ogg");

On line 39 or the Content-Type line I replaced-
This: header("Content-Type: video/mp4");
With this: header("Content-Type: ".($this->videoFormats[strtolower(pathinfo($this->path, PATHINFO_EXTENSION))]));

I would like to use this code in a GNU GPLv3 licensed project. Can you please license this code as GNU GPLv3 ?

Hello,

how to use this class in codeigniter? I tried but I didn't response.

Regards
Gokhan

This basically just saved my life. Thank you.

Hello,

This is a really awesome class you've done here. But I am asking myself if there is a way to find when the video ends streaming ? Thank you a lot.

lk77 commented Jul 6, 2017

Hello,

the seeking don't working on chrome.

I think you need to change line 48 :
header("Accept-Ranges: 0-".$this->end);
by
header("Accept-Ranges: bytes 0-".$this->end);

reszko commented Jul 6, 2017

Hi. Add this statement in stream method before while: session_write_close(). Without it, the browser freezes when a file is streaming when you make new requests, like click to go to another page for example. Before I use session_write_close(), a new request only worked in Firefox. In another browsers all new requests make browser keeps loading until the stream finishes.

If you're using PHP5+

remove Line 76 (fseek($this->stream, $this->start);)

Line 109 change to $data = @stream_get_contents($this->stream, $bytesToRead, $i);

tested on Chrome, Safari and FF

Is there an option to stream multiple video files one after the other, like it is for audio files?

AlexandrBabich commented Oct 13, 2017

Hello guys. I had same error in IE11. To solve this issue you need add header("Accept-Ranges: bytes"); after 83 string.
This header is important for IE browsers.

TRC4 commented Oct 21, 2017

@lynxfg insert this code on top

start();exit; // starting classes class VideoStream **php script has problem with real time ![1](https://user-images.githubusercontent.com/17369574/31848516-0059aab8-b635-11e7-9884-32cf692c2677.png) ![2](https://user-images.githubusercontent.com/17369574/31848517-00824c70-b635-11e7-8a77-0dc3cbed8458.png) **
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment