0

Good day here,

I'm actually dealing with miming videos from one domain to an other-one, here is what I want to do:

  • myfirstdomain.com/index.html sources a video from myfirstdomain.com/video.php?id=xxx where xxx will be the file path of the video file.
  • myfirstdomain.com/video.php?id=xxx mirrors myseconddomain.com/video.php?id=xxx.
  • myseconddomain.com/video.php?id=xxx open and read the target video file to mime it.

===== ===== ===== ===== =====

Actually my file myseconddomain.com/video.php?id=xxx provide a valid mp4 video mimed content, read from the original file xxx.

I tested sourcing it with a HTML video tag, and opening directly from the link, it works.

Once I got the file path here is the function I call to do that (myseconddomain.com/video.php?id=xxx):

function mimeVideo( $pPath ) {
    $file = $pPath;
    $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]) && is_numeric($range[1])) ? $range[1] : $size;
        }
        $c_end = ($c_end > $end) ? $end : $c_end;
        if ($c_start > $c_end || $c_start > $size - 1 || $c_end >= $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) && ($p = ftell($fp)) <= $end) {
        if ($p + $buffer > $end) {
            $buffer = $end - $p + 1;
        }
        
        set_time_limit(0);
        echo fread($fp, $buffer);
        flush();
    }
    
    fclose($fp);
    exit();
}

===== ===== ===== ===== =====

Here is my issue:

Now I want to read the video from myseconddomain.com/video.php?id=xxx with myfirstdomain.com/video.php?id=xxx, so I wanted to copy its headers and print its content:

So I wrote that in order to get the headers and number of bytes read (myfirstdomain.com/video.php?id=xxx):

    $arrContextOptions = array(
        'http' => array(
            'header' => array( 'Referer: https://myfirstdomain.com'."\r\n" )
        ),
        'ssl' => array(
            'verify_peer' => false,
            'verify_peer_name' => false,
        )
    );
    
    $headers = get_headers( 'https://myseconddomain.com/video.php?id='.urlencode( $_GET['id'] ), false, stream_context_create( $arrContextOptions ) );
    print_r( $headers );

This works properly and displays the right headers (gotten from myseconddomain.com/video.php?id=xxx):

Array (
    [0] => HTTP/1.1 200 OK
    [1] => Date: Tue, 01 Feb 2022 14:28:50 GMT
    [2] => Server: Apache/2.4.38 (Win32) OpenSSL/1.1.1a PHP/7.3.2
    [3] => X-Powered-By: PHP/7.3.2
    [4] => Access-Control-Allow-Origin: https://myfirstdomain.com
    [5] => Accept-Ranges: 0-267912903
    [6] => Content-Range: bytes 0-267912902/267912903
    [7] => Content-Length: 267912903
    [8] => Connection: close
    [9] => Content-Type: video/mp4
)

Then I tried to read directly the content from the file with:

$response = file_get_contents( 'https://myseconddomain.com/video.php?id='.urlencode( $_GET['id'] ), false, stream_context_create( $arrContextOptions ) );

And from here my page started to load during an infinite time, I guess I have to provide more headers, or to add to the context the number of bytes to be read.

But in addition to this I have the feeling there is a better way to do this, any idea about how to solve my issue please?

Thank you in advance for you help and you time.

EDIT

I actually changed my mimeVideo() script to use the one from this post:

Streaming a large file using PHP

(support large video file transfers)

Lucas F
  • 15
  • 6
  • I'm not a specialist in mirroring but why doing it in PHP? Can't you sync your videos with *rsync*, *FreeFileSync*, *Robocopy* or any other kind of syncing software? If I understand, you need to do a kind of "origin pull" like it's often done with CDNs? In this case, you may could use NGINX as a reverse proxy and your origin server as kind of backend server. Another point: serving big files with PHP is quite problematic since it locks the process and can timeout. [You may try using X-Sendfile](https://stackoverflow.com/a/70923574/653182) to let your HTTP daemon serve the video instead of PHP. – Patrick Janser Feb 01 '22 at 15:25
  • Thank you for your reply @PatrickJanser , I actually wanted to do that with PHP because one of my servers (2nd one) is using an old Windows 7, and I don't have access to the computer for the other one (1st one) I can only edit files via FTP. Can one of this softwares work even without installing it on one side? Othewise I don't think so I'll be able to use them. – Lucas F Feb 01 '22 at 16:03
  • Maybe your MP4 has its metadata at the back of file, so it takes a full download before it can play. Try a smaller file and see if it plays if you wait long enough? – VC.One Feb 01 '22 at 16:52
  • @LucasF: *FreeFileSync* can connect to FTP but it will take a long time to scan for changes. Ideally, it should be the source server that has the "new video" event and should fire the copy to the slave server. In this case the "origin pull" technique from the slave is ok. I just think that you should serve your videos with *Sendfile*. Your PHP can set the MIME headers first and then the transfer is done by the HTTP server. But I don't know if it can handle seeking. You may have to give it a try. Should the slave also copy the video locally if it hasn't got it? Is your slave already doing that? – Patrick Janser Feb 01 '22 at 17:35
  • 1
    @VC.One In any case, I think that the `file_get_contents(...)` on the slave will download all the video, which is problematic as it will last a long time and the browser won't get a single portion of the file before the video is completely downloaded to the slave server (and put inside a variable that could be bigger than the memory limit set on PHP). – Patrick Janser Feb 01 '22 at 17:39
  • Hi, I actually do not want to save the file on the firstdomain server, just to stream it with the second one – Lucas F Feb 04 '22 at 10:08

0 Answers0