0

我有一个项目可以加密上传的文件并保存它们。这些文件对用户隐藏,但仍然可以看到它们(通过使用 php)。

下面的代码完美适用于大小为 0-2MB 的图像和所有其他文件。问题是用于以请求的字节范围发送到浏览器的较大文件(> 2MB)。像带有 HTML5 视频的视频。

有很多类似的问题可用,但我仍然无法处理加密的大文件。

如何让这个代码在大文件和解密中正常工作,以便用户浏览器理解它并显示内容?是否有一些标题是我遗漏的或我做错了什么?

这是当前代码:

<?php
function printFileChunksRange($file, $key){

    //$_SERVER["HTTP_RANGE"]="bytes=0-"; // For testing

    $fp = fopen($file['url'], 'rb');
    $size   = $file['size'];       // File size
    $length = $size;               // Content length
    $start  = 0;                   // Start byte
    $end    = $size - 1;           // End byte
    $chunkSize = 1024*100;         // Chunk size used to crypt files
    $readChunkSize = $chunkSize+8; // Chunk size + IV size

    // parse the range of bytes
    if(!empty($_SERVER['HTTP_RANGE'])){
        if(preg_match('/bytes=\h*(\d+)-(\d*)[\D.*]?/i', $_SERVER['HTTP_RANGE'], $matches)){
            $start = intval($matches[1]); // Start byte
            if(!empty($matches[2])){
                $end = intval($matches[2]); // End byte
            }
        }
    }

    if($start > $end) $end = $file['size']-1;
    $length = $end-$start;

    if(isset($_SERVER['HTTP_RANGE'])) header('HTTP/1.1 206 Partial Content'); // Send the header code 206 if range is requested...
    else header('HTTP/1.1 200 OK'); // ...otherwise send 200

    // Set the rest of headers
    header("Content-type: {$file['type']}");                      // File type
    header('Cache-Control: public, must-revalidate, max-age=0');  // ...
    header('Accept-Ranges: bytes');                               // Say that ranges is accepted
    if(isset($_SERVER['HTTP_RANGE'])) header("Content-Range: bytes {$start}-{$end}/{$file['size']}"); // Tell that what bytes we'll send
    header("Content-Length: ".(($end-$begin)+1)); //$length // Content length
    //Header("Connection: close");

    // Count the chunk sizes.. etc. ...for the start of requested range
    $chunk_start = intval(floor($start/$chunkSize));
    $chunk_start_bytes = intval($chunk_start*$readChunkSize);
    $chunk_start_remainder = intval($start % $chunkSize);

    // Count the chunk sizes.. etc. ...for the end of requested range
    $chunk_end = intval(floor($end/$chunkSize));
    $chunk_end_bytes = intval($chunk_end*$readChunkSize);
    $chunk_end_remainder = intval(($end+1) % $chunkSize);

    fseek($fp, $chunk_start_bytes); // Seek the right byte to start reading
    set_time_limit(0);              // Set time limit to 0, for large files
    $current = 0;                   // Current output length

    while(!feof($fp) and $current <= $length and connection_status() == 0) {
        $data = fread($fp, $readChunkSize); // Read encrypted chunk...
        $data = $this->decrypt($data, $key); // ...and decrypt it

        if($start+$end < $chunkSize)                 $data = substr($data, $chunk_start_remainder, $chunk_end_remainder-$chunk_start_remainder);
        elseif($current + strlen($data) > $length+1) $data = substr($data, $chunk_start_remainder, $chunk_end_remainder);
        else                                         $data = substr($data, $chunk_start_remainder);

        $chunk_start_remainder = 0; // Set remainder to 0, because we have already used it and we don't need it anymore;
        $current += strlen($data);  // Add $data length to $current output length

        echo $data; // Print the decrypted chunk
        flush();    // Free up memory to save server's resources
    }
    fclose($fp); // Close the file handle
}
?>

以及上面代码的用法:

<?php
$file = array(
    'type' => 'video/mp4',
    'ext' => 'mp4',
    'name' => '6XjQALY3YG',
    'size' => '15765276',
    'original_name' => '20130908.mp4',
    'key' => 'feab20c63f84788ad7cb90b547946bccb5da8a9d0b4ffb6473c70a732ae8df99',
    'url' => 'upload/2013/12/17/6XjQALY3YG',
    //'url' => 'bigfile.mp4',
);

printFileChunksRange($file, $file['key']);
?>

http://mobiforge.com/design-development/content-delivery-mobile-devices
使用 PHP 发送文件时可恢复下载?
http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html

4

0 回答 0