php安全下载大文件的实现代码

发布时间:2019-07-21编辑:脚本学堂
本文介绍下,在php中实现文件下载的方法,以及大文件安全下载的实现代码,供大家学习参考。

先来看下一般文件的安全下载方法:
 

复制代码 代码示例:
<?php
/**
* 一般文件安全下载
* edit www.jb200.com
*/
    $durl = 'file/phpcms2008_o2abf32efj883c91a.iso';  
    $filename = 'phpcms2008_o2abf32efj883c91a.iso';  
    $file = @fopen($durl, 'r');  
    header("Content-Type: application/octet-stream");     
    header("Accept-Ranges:    bytes");  
    header("Accept-Length:    ".filesize($durl));  
    header("Content-Disposition:    attachment;    filename=".$filename);  
    echo   fread($file,filesize($durl));  
    fclose($file);  
?>  

以上的代码,在遇到大文件时,超过php.ini配置的内存最大值的文件时,服务器会非常占用CPU资源,文件不能正常下载,只能下载几十Kb的文件。
可以用下面的代码来解决:
 

复制代码 代码示例:
<?php
/**
* 大文件安全下载的实现代码
* edit www.jb200.com
*/
function download($url, $filename) {  
// 获得文件大小, 防止超过2G的文件, 用sprintf来读  
$filesize = sprintf ( "%u", filesize ( $url ) );  
if (! $filesize) {  
    return;  
 }  
 header ( "Content-type:application/octet-streamn" ); //application/octet-stream  
 header ( "Content-type:unknown/unknown;" );  
 header ( "Content-disposition: attachment; filename="" . $filename . """ );  
 header ( 'Content-transfer-encoding: binary' );  
if ($range = getenv ( 'HTTP_RANGE' )) { // 当有偏移量的时候,采用206的断点续传头  
    $range = explode ( '=', $range );  
    $range = $range [1];  
      
     header ( "HTTP/1.1 206 Partial Content" );  
     header ( "Date: " . gmdate ( "D, d M Y H:i:s" ) . " GMT" );  
     header ( "Last-Modified: " . gmdate ( "D, d M Y H:i:s", filemtime ( $url ) ) . " GMT" );  
     header ( "Accept-Ranges: bytes" );  
     header ( "Content-Length:" . ($filesize - $range) );  
     header ( "Content-Range: bytes " . $range . ($filesize - 1) . "/" . $filesize );  
     header ( "Connection: close" . "nn" );  
 } else {  
     header ( "Content-Length:" . $filesize . "nn" );  
    $range = 0;  
 }  
 loadFile ( $url );  
}  
     
function loadFile($filename, $retbytes = true) {  
$buffer = '';  
$cnt = 0;  
$handle = fopen ( $filename, 'rb' );  
if ($handle === false) {  
    return false;  
 }  
while ( ! feof ( $handle ) ) {  
    $buffer = fread ( $handle, 1024 * 1024 );  
    echo $buffer;  
     ob_flush ();  
    flush ();  
    if ($retbytes) {  
$cnt += strlen ( $buffer );  
     }  
 }  
$status = fclose ( $handle );  
if ($retbytes && $status) {  
    return $cnt; // return num. bytes delivered like readfile() does.  
 }  
return $status;  
}
?>

调用示例:
 

复制代码 代码示例:
//大文件的安全下载
download($url, $filename);