嵌入远程媒体文件

I have a slightly unusual problem here. I have a php server that is reachable from the internet. This server hosts a small control panel that allows me to do a few things, but I mostly use it to turn on my PC remotely. This system is password-protected, and I have it this way because wake-on-lan commands do not have any form of authentication.

I have an IP camera that is not accessible from the internet, but it is reachable from the local network via HTTP. It serves a webpage, and several ways to view the camera stream. One of them is a "video.mp4" file that shows the camera stream. I want to make this accessible from my server, by embedding the video.mp4 file in a php page. There are two problems with this, however:

  • First, the camera view is not accessible from outside the network, so the browser can't access the file (meaning no video tags) - I need some way to read the file server-side and then serve it to the client.
  • Second, the camera is also password-protected. Fortunately it is configured to let me in by entering the password in the URL, like "http://username:password@192.168.2.7/video.mp4".

I've tried include()-ing the remote file, but this gave an error message:

PHP Warning:  include(http://...@192.168.2.7/video.mp4): failed to open stream: no suitable wrapper could be found in /var/www/html/camera.php
PHP Warning:  include(): Failed opening 'http://...@192.168.2.7/video.mp4' for inclusion (include_path='.:/usr/share/php:/usr/share/pear') in /var/www/html/camera.php

This probably means that I can't just copy an mp4 stream into a php file. I didn't really expect it to work to be honest, it was more to see if the error message would give me a hint on how to do this properly.

I thought about opening a port to the camera, but since its web interface does not support SSL I consider that too insecure.

To allow inclusion of remote files, the directive allow_url_include must be set to On in php.ini

But it is bad, in a security-oriented point of view ; and, so, it is generally disabled (I've never seen it enabled, actually)

It is not the same as allow_url_fopen, which deals with opening (and not including) remote files -- and this one is generally enabled, because it makes fetching of data through HTTP much easier (easier than using curl)

Basic example of reading a mp4 file

<?php
// replace 'file.mp4' to your file in the line bellow
$path = 'file.mp4';

$size=filesize($path);

$fm=@fopen($path,'rb');
if(!$fm) {
  // You can also redirect here
  header ("HTTP/1.0 404 Not Found");
  die();
}

$begin=0;
$end=$size;

if(isset($_SERVER['HTTP_RANGE'])) {
  if(preg_match('/bytes=\h*(\d+)-(\d*)[\D.*]?/i', $_SERVER['HTTP_RANGE'], $matches)) {
    $begin=intval($matches[0]);
    if(!empty($matches[1])) {
      $end=intval($matches[1]);
    }
  }
}

if($begin>0||$end<$size)
  header('HTTP/1.0 206 Partial Content');
else
  header('HTTP/1.0 200 OK');

header("Content-Type: video/mp4");
header('Accept-Ranges: bytes');
header('Content-Length:'.($end-$begin));
header("Content-Disposition: inline;");
header("Content-Range: bytes $begin-$end/$size");
header("Content-Transfer-Encoding: binary
");
header('Connection: close');

$cur=$begin;
fseek($fm,$begin,0);

while(!feof($fm)&&$cur<$end&&(connection_status()==0))
{ print fread($fm,min(1024*16,$end-$cur));
  $cur+=1024*16;
  usleep(1000);
}
die();

You can also use

readfile('http://example.com/file.mp4');

readfile() reads a file (even remotely over http) and immediately outputs it's contents.