欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  后端开发

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

程序员文章站 2022-04-08 15:09:17
...
  1. /**
  2. * 一般文件安全下载
  3. * edit bbs.it-home.org
  4. */
  5. $durl = 'file/phpcms2008_o2abf32efj883c91a.iso';
  6. $filename = 'phpcms2008_o2abf32efj883c91a.iso';
  7. $file = @fopen($durl, 'r');
  8. header("Content-Type: application/octet-stream");
  9. header("Accept-Ranges: bytes");
  10. header("Accept-Length: ".filesize($durl));
  11. header("Content-Disposition: attachment; filename=".$filename);
  12. echo fread($file,filesize($durl));
  13. fclose($file);
  14. ?>
复制代码

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

  1. /**
  2. * 大文件安全下载的实现代码
  3. * edit bbs.it-home.org
  4. */
  5. function download($url, $filename) {
  6. // 获得文件大小, 防止超过2G的文件, 用sprintf来读
  7. $filesize = sprintf ( "%u", filesize ( $url ) );
  8. if (! $filesize) {
  9. return;
  10. }
  11. header ( "Content-type:application/octet-stream\n" ); //application/octet-stream
  12. header ( "Content-type:unknown/unknown;" );
  13. header ( "Content-disposition: attachment; filename=\"" . $filename . "\"" );
  14. header ( 'Content-transfer-encoding: binary' );
  15. if ($range = getenv ( 'HTTP_RANGE' )) { // 当有偏移量的时候,采用206的断点续传头
  16. $range = explode ( '=', $range );
  17. $range = $range [1];
  18. header ( "HTTP/1.1 206 Partial Content" );
  19. header ( "Date: " . gmdate ( "D, d M Y H:i:s" ) . " GMT" );
  20. header ( "Last-Modified: " . gmdate ( "D, d M Y H:i:s", filemtime ( $url ) ) . " GMT" );
  21. header ( "Accept-Ranges: bytes" );
  22. header ( "Content-Length:" . ($filesize - $range) );
  23. header ( "Content-Range: bytes " . $range . ($filesize - 1) . "/" . $filesize );
  24. header ( "Connection: close" . "\n\n" );
  25. } else {
  26. header ( "Content-Length:" . $filesize . "\n\n" );
  27. $range = 0;
  28. }
  29. loadFile ( $url );
  30. }
  31. function loadFile($filename, $retbytes = true) {
  32. $buffer = '';
  33. $cnt = 0;
  34. $handle = fopen ( $filename, 'rb' );
  35. if ($handle === false) {
  36. return false;
  37. }
  38. while ( ! feof ( $handle ) ) {
  39. $buffer = fread ( $handle, 1024 * 1024 );
  40. echo $buffer;
  41. ob_flush ();
  42. flush ();
  43. if ($retbytes) {
  44. $cnt += strlen ( $buffer );
  45. }
  46. }
  47. $status = fclose ( $handle );
  48. if ($retbytes && $status) {
  49. return $cnt; // return num. bytes delivered like readfile() does.
  50. }
  51. return $status;
  52. }
  53. ?>
复制代码

调用示例:

  1. //大文件的安全下载
  2. download($url, $filename);
复制代码