<?php
   require_once 'video_streamer_base.php';

   class VideoStreamerRangeBasic extends VideoStreamerBase {
      protected $_video_size = 0;
      protected $_chunk_size = 0;
      protected $_should_stream = false;
      private $_start_byte = 0;
      private $_end_byte = 0;

      public function __construct($video_path, $require_cookie, $chunk_size) {
         parent::__construct($video_path, $require_cookie);
         $this->_video_size = filesize($this->_video_path);
         $this->_chunk_size = $chunk_size;
      }

      protected function setResponseHeaders() {
         header("Content-Type: video/mp4");
         header("Accept-Ranges: bytes");
         if (isset($_SERVER['HTTP_RANGE'])) {
            if (!$this->parseRangeRequestHeader()) {
               header("HTTP/1.1 416 Requested Range Not Satisfiable");
               header("Content-Range: bytes {$this->_start_byte}-{$this->_end_byte}/{$this->_video_size}");
               $this->_should_stream = false;
               return;
            }
            $content_length = $this->_end_byte - $this->_start_byte + 1;
            header("HTTP/1.1 206 Partial Content");
            header("Content-Range: bytes {$this->_start_byte}-{$this->_end_byte}/{$this->_video_size}");
            header("Content-Length: {$content_length}");
            $this->_should_stream = true;
         } else {
            header("HTTP/1.1 200 OK");
            header("Content-Length: {$this->_video_size}");
            $this->_should_stream = false;
         }
      }

      protected function doVideoStream() {
         if (!$this->_should_stream) {
            return;
         }
         set_time_limit(0);
         fseek($this->_video_stream, $this->_start_byte);
         $i = $this->_start_byte;
         while (!feof($this->_video_stream) && $i <= $this->_end_byte) {
            $this->beforeByteSend();
            $bytes_to_read = min($this->_chunk_size, $this->_end_byte - $i + 1);
            $data = fread($this->_video_stream, $bytes_to_read);
            echo $data;
            flush();
            $i += $bytes_to_read;
            $this->afterByteSend();
         }
      }

      protected function beforeByteSend() {}
      protected function afterByteSend() {}

      private function parseRangeRequestHeader() {
         list(, $req_range) = explode('=', $_SERVER['HTTP_RANGE'], 2);
         if (strpos($req_range, ',') !== false) {
            // Multi-range request not supported.
            return false;
         }
         $max_end_byte = $this->_video_size - 1;
         $req_ranges = explode('-', $req_range);
         $this->_start_byte = $req_ranges[0];
         $this->_end_byte = (isset($req_ranges[1]) && is_numeric($req_ranges[1])) ? $req_ranges[1] : $max_end_byte;
         $this->_end_byte = min($this->_end_byte, $max_end_byte);
         if ($this->_start_byte > $this->_end_byte) {
            // Invalid range requested.
            return false;
         }
         return true;
      }
   }
?>