Resumable downloads when using PHP to send the file?

后端 未结 13 1172
梦毁少年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:02

    The first thing you need to do is to send the Accept-Ranges: bytes header in all responses, to tell the client that you support partial content. Then, if request with a Range: bytes=x-y header is received (with x and y being numbers) you parse the range the client is requesting, open the file as usual, seek x bytes ahead and send the next y - x bytes. Also set the response to HTTP/1.0 206 Partial Content.

    Without having tested anything, this could work, more or less:

    $filesize = filesize($file);
    
    $offset = 0;
    $length = $filesize;
    
    if ( isset($_SERVER['HTTP_RANGE']) ) {
        // if the HTTP_RANGE header is set we're dealing with partial content
    
        $partialContent = true;
    
        // find the requested range
        // this might be too simplistic, apparently the client can request
        // multiple ranges, which can become pretty complex, so ignore it for now
        preg_match('/bytes=(\d+)-(\d+)?/', $_SERVER['HTTP_RANGE'], $matches);
    
        $offset = intval($matches[1]);
        $length = intval($matches[2]) - $offset;
    } else {
        $partialContent = false;
    }
    
    $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');
    
        header('Content-Range: bytes ' . $offset . '-' . ($offset + $length) . '/' . $filesize);
    }
    
    // output the regular HTTP headers
    header('Content-Type: ' . $ctype);
    header('Content-Length: ' . $filesize);
    header('Content-Disposition: attachment; filename="' . $fileName . '"');
    header('Accept-Ranges: bytes');
    
    // don't forget to send the data too
    print($data);
    

    I may have missed something obvious, and I have most definitely ignored some potential sources of errors, but it should be a start.

    There's a description of partial content here and I found some info on partial content on the documentation page for fread.

提交回复
热议问题