title: Using php to output an mp4 video
body: <p>Ok basically I have a project that requires that videos are hidden from the users while still able to see them (by using php).  here's what i got so far:</p>
  
  <p>The video.php file has this: </p>
  
  <pre><code>&lt;?php
  $ch = curl_init();
  curl_setopt($ch, CURLOPT_URL, 'path/to/movie.mp4');
  curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); 
  curl_setopt($ch, CURLOPT_HEADER, 0);
  $out = curl_exec($ch);
  curl_close($ch);
  
  
  header('Content-type: video/mp4');
  header('Content-type: video/mpeg');
  header('Content-disposition: inline');
  header("Content-Transfer-Encoding:­ binary");
  header("Content-Length: ".filesize($out));
  echo $out;
  exit();
  ?&gt;
  </code></pre>
  
  <p>and the html file that is supposed to display this is using  html5 as it would expect.  now here's the thing.. when I straight embed this (not ) it works.  but it doesn't work on my iPhone and doesn't work in the  tag... if I use the direct file instead of the php wrapper, everything works fine, on my iPhone too...</p>
  
  <p>so I guess my question for this one is this:  what are the proper header() information to perfectly replicate an mp4 that can be streamed via iPhone and HMTL5?</p>
  
  <p>Solution derived from: <a href="http://mobiforge.com/developing/story/content-delivery-mobile-devices" rel="noreferrer">http://mobiforge.com/developing/story/content-delivery-mobile-devices</a></p>
  
  <p>video.php file:</p>
  
  <pre><code>&lt;?php
  $file = 'path/to/videofile.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");
  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");
          exit;
      }
      if ($range == '-') {
          $c_start = $size - substr($range, 1);
      }else{
          $range  = explode('-', $range);
          $c_start = $range[0];
          $c_end   = (isset($range[1]) &amp;&amp; is_numeric($range[1])) ? $range[1] : $size;
      }
      $c_end = ($c_end &gt; $end) ? $end : $c_end;
      if ($c_start &gt; $c_end || $c_start &gt; $size - 1 || $c_end &gt;= $size) {
          header('HTTP/1.1 416 Requested Range Not Satisfiable');
          header("Content-Range: bytes $start-$end/$size");
          exit;
      }
      $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) &amp;&amp; ($p = ftell($fp)) &lt;= $end) {
  
      if ($p + $buffer &gt; $end) {
          $buffer = $end - $p + 1;
      }
      set_time_limit(0);
      echo fread($fp, $buffer);
      flush();
  }
  
  fclose($fp);
  exit();
  ?&gt;
  </code></pre>