Resumable downloads when using PHP to send the file?

后端 未结 13 861
梦毁少年i
梦毁少年i 2020-11-22 12:22

We are using a PHP scripting for tunnelling file downloads, since we don\'t want to expose the absolute path of downloadable file:

header(\"Content-Type: $ct         


        
相关标签:
13条回答
  • 2020-11-22 13:08

    Resuming downloads in HTTP is done through the Range header. If the request contains a Range header, and if other indicators (e.g. If-Match, If-Unmodified-Since) indicate that the content hasn't changed since the download was started, you give a 206 response code (rather than 200), indicate the range of bytes you're returning in the Content-Range header, then provide that range in the response body.

    I don't know how to do that in PHP, though.

    0 讨论(0)
  • 2020-11-22 13:13

    Yes. Support byteranges. See RFC 2616 section 14.35 .

    It basically means that you should read the Range header, and start serving the file from the specified offset.

    This means that you can't use readfile(), since that serves the whole file. Instead, use fopen() first, then fseek() to the correct position, and then use fpassthru() to serve the file.

    0 讨论(0)
  • 2020-11-22 13:18

    Yes, you can use the Range header for that. You need to give 3 more headers to the client for a full download:

    header ("Accept-Ranges: bytes");
    header ("Content-Length: " . $fileSize);
    header ("Content-Range: bytes 0-" . $fileSize - 1 . "/" . $fileSize . ";");
    

    Than for an interrupted download you need to check the Range request header by:

    $headers = getAllHeaders ();
    $range = substr ($headers['Range'], '6');
    

    And in this case don't forget to serve the content with 206 status code:

    header ("HTTP/1.1 206 Partial content");
    header ("Accept-Ranges: bytes");
    header ("Content-Length: " . $remaining_length);
    header ("Content-Range: bytes " . $start . "-" . $to . "/" . $fileSize . ";");
    

    You'll get the $start and $to variables from the request header, and use fseek() to seek to the correct position in the file.

    0 讨论(0)
  • 2020-11-22 13:26

    If you're willing to install a new PECL module, the easiest way to support resumeable downloads with PHP is through http_send_file(), like this

    <?php
    http_send_content_disposition("document.pdf", true);
    http_send_content_type("application/pdf");
    http_throttle(0.1, 2048);
    http_send_file("../report.pdf");
    ?>
    

    source : http://www.php.net/manual/en/function.http-send-file.php

    We use it to serve database-stored content and it works like a charm !

    0 讨论(0)
  • 2020-11-22 13:26

    This worked very well for me: https://github.com/pomle/php-serveFilePartial

    0 讨论(0)
  • 2020-11-22 13:27

    You could use the below code for byte range request support across any browser

        <?php
    $file = 'YouTube360p.mp4';
    $fileLoc = $file;
    $filesize = filesize($file);
    $offset = 0;
    $fileLength = $filesize;
    $length = $filesize - 1;
    
    if ( isset($_SERVER['HTTP_RANGE']) ) {
        // if the HTTP_RANGE header is set we're dealing with partial content
    
        $partialContent = true;
        preg_match('/bytes=(\d+)-(\d+)?/', $_SERVER['HTTP_RANGE'], $matches);
    
        $offset = intval($matches[1]);
        $tempLength = intval($matches[2]) - 0;
        if($tempLength != 0)
        {
            $length = $tempLength;
        }
        $fileLength = ($length - $offset) + 1;
    } else {
        $partialContent = false;
        $offset = $length;
    }
    
    $file = fopen($file, 'r');
    
    // seek to the requested offset, this is 0 if it's not a partial content request
    fseek($file, $offset);
    
    $data = fread($file, $length);
    
    fclose($file);
    
    if ( $partialContent ) {
        // output the right headers for partial content
        header('HTTP/1.1 206 Partial Content');
    }
    
    // output the regular HTTP headers
    header('Content-Type: ' . mime_content_type($fileLoc));
    header('Content-Length: ' . $fileLength);
    header('Content-Disposition: inline; filename="' . $file . '"');
    header('Accept-Ranges: bytes');
    header('Content-Range: bytes ' . $offset . '-' . $length . '/' . $filesize);
    
    // don't forget to send the data too
    print($data);
    ?>
    
    0 讨论(0)
提交回复
热议问题