我有一个项目可以加密上传的文件并保存它们。这些文件对用户隐藏,但仍然可以看到它们(通过使用 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