<?php
/**
* Stream videos
*
* @category PHP
* @package VenoFileManager
* @author Nicola Franchini <info@veno.it>
* @license Exclusively sold on CodeCanyon
* @link http://filemanager.veno.it/
*/
if (!class_exists('VideoStream', false)) {
/**
* VideoStream class
*
* PHP version >= 5.3
*
* @category PHP
* @package VenoFileManager
* @author Nicola Franchini <info@veno.it>
* @license Exclusively sold on CodeCanyon
* @link http://filemanager.veno.it/ - https://gist.github.com/ranacseruet/9826293
*/
class VideoStream
{
private $_path = "";
private $_stream = "";
private $_buffer = 8 * 1024;
private $_start = -1;
private $_end = -1;
private $_size = 0;
private $_videoFormats = array(
"mp4"=>"video/mp4",
"webm"=>"video/webm",
"ogg"=>"video/ogg",
"ogv"=>"video/ogg",
// "flv"=>"video/x-flv",
);
/**
* Construct.
*
* @param string $filePath file path
*/
function __construct($filePath)
{
$path = dirname(dirname(dirname(__FILE__))).'/'.urldecode(base64_decode($filePath));
$this->_path = $path;
}
/**
* The safe way
*
* @return true/false
*/
public function checkVideo()
{
global $setUp;
$realsetup = realpath('../.'.$setUp->getConfig('starting_dir'));
$realfile = realpath($this->_path);
if (strpos($realfile, $realsetup) !== false && file_exists($this->_path)) {
return true;
}
return false;
}
/**
* Open stream
*
* @return fopen 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.
*
* @return video headers
*/
private function _setHeader()
{
ob_get_clean();
header("Content-Type: ".($this->_videoFormats[strtolower(pathinfo($this->_path, PATHINFO_EXTENSION))]));
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
*
* @return fclose stream
*/
private function _end()
{
fclose($this->_stream);
exit;
}
/**
* Perform the streaming of calculated range
*
* @return stream
*/
private function _stream()
{
if ($this->checkVideo()) {
$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
*
* @return start stream
*/
function _start()
{
$this->_open();
$this->_setHeader();
$this->_stream();
$this->_end();
}
}
}