douyingmou1389 2013-12-18 00:22
浏览 19

使用PHP具有可恢复的下载和加密文件

I have a project that encrypts uploaded files and saves them. Those files are hidden from the users while still able to see them (by using php).

The code below works perfectly with images and all other files with sizes 0-2MB. The problem is larger files (> 2MB) that is used to send to a browser in requested range of bytes. Like videos with HTML5 video.

There is lots of similar questions available but I still haven't got that to work with encrypted large files.

How to get this code to work properly with large files and decryption so that the users browser will understand it and show the contents? Is there some headers what I'm missing or what I have done wrong?

Here's the current code:

<?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
}
?>

And the usage for the code above:

<?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
Resumable downloads when using PHP to send the file?
http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html

  • 写回答

0条回答 默认 最新

    报告相同问题?

    悬赏问题

    • ¥15 树莓派与pix飞控通信
    • ¥15 自动转发微信群信息到另外一个微信群
    • ¥15 outlook无法配置成功
    • ¥30 这是哪个作者做的宝宝起名网站
    • ¥60 版本过低apk如何修改可以兼容新的安卓系统
    • ¥25 由IPR导致的DRIVER_POWER_STATE_FAILURE蓝屏
    • ¥50 有数据,怎么建立模型求影响全要素生产率的因素
    • ¥50 有数据,怎么用matlab求全要素生产率
    • ¥15 TI的insta-spin例程
    • ¥15 完成下列问题完成下列问题