CodeIgniter大文件下载

CodeIgniter为方便开发者提供了下载助手函数force_download('filename', 'data'),但需要使用file_get_contents()函数先将文件内容全部读入一个变量中,这在读取小文件时没什么问题,但读大文件时将会报内存不够的错误,所以我们一般使用readfile()函数读取或者使用fread()依次读取文件片段然后输出的方式下载文件。

CI3虽然还没有最终发布,但在Github中我们看到了将改进force_download()函数的功能,如果第二个参数为NULL,CI将视第一个参数为文件的路径名并使用fread()函数读取文件内容,我们可以将CI3的force_download()函数加入到现有的CI2的项目中,但需要做一些改动,在application/helpers目录下建立MY_download_helper.php文件:

  1 <?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
  2 
  3 if ( ! function_exists('force_download'))
  4 {
  5     /**
  6      * Force Download
  7      *
  8      * Generates headers that force a download to happen
  9      *
 10      * @param    string    filename
 11      * @param    mixed    the data to be downloaded
 12      * @param    bool    whether to try and send the actual file MIME type
 13      * @return    void
 14      */
 15     function force_download($filename = '', $data = '', $set_mime = FALSE)
 16     {
 17         if ($filename === '' OR $data === '')
 18         {
 19             return FALSE;
 20         }
 21         elseif ($data === NULL)
 22         {
 23             if (@is_file($filename) && ($filesize = @filesize($filename)) !== FALSE)
 24             {
 25                 $filepath = $filename;
 26                 $filename = explode('/', str_replace(DIRECTORY_SEPARATOR, '/', $filename));
 27                 $filename = end($filename);
 28             }
 29             else
 30             {
 31                 return FALSE;
 32             }
 33         }
 34         else
 35         {
 36             $filesize = strlen($data);
 37         }
 38 
 39         // Set the default MIME type to send
 40         $mime = 'application/octet-stream';
 41 
 42         $x = explode('.', $filename);
 43         $extension = end($x);
 44 
 45         if ($set_mime === TRUE)
 46         {
 47             if (count($x) === 1 OR $extension === '')
 48             {
 49                 /* If we're going to detect the MIME type,
 50                  * we'll need a file extension.
 51                  */
 52                 return FALSE;
 53             }
 54 
 55             // Load the mime types
 56             if (defined('ENVIRONMENT') AND is_file(APPPATH.'config/'.ENVIRONMENT.'/mimes.php'))
 57             {
 58                 include(APPPATH.'config/'.ENVIRONMENT.'/mimes.php');
 59             }
 60             elseif (is_file(APPPATH.'config/mimes.php'))
 61             {
 62                 include(APPPATH.'config/mimes.php');
 63             }
 64 
 65             // Only change the default MIME if we can find one
 66             if (isset($mimes[$extension]))
 67             {
 68                 $mime = is_array($mimes[$extension]) ? $mimes[$extension][0] : $mimes[$extension];
 69             }
 70         }
 71 
 72         /* It was reported that browsers on Android 2.1 (and possibly older as well)
 73          * need to have the filename extension upper-cased in order to be able to
 74          * download it.
 75          *
 76          * Reference: http://digiblog.de/2011/04/19/android-and-the-download-file-headers/
 77          */
 78         if (count($x) !== 1 && isset($_SERVER['HTTP_USER_AGENT']) && preg_match('/Android\s(1|2\.[01])/', $_SERVER['HTTP_USER_AGENT']))
 79         {
 80             $x[count($x) - 1] = strtoupper($extension);
 81             $filename = implode('.', $x);
 82         }
 83 
 84         if ($data === NULL && ($fp = @fopen($filepath, 'rb')) === FALSE)
 85         {
 86             return FALSE;
 87         }
 88 
 89         // Clean output buffer
 90         if (ob_get_level() !== 0 && @ob_end_clean() === FALSE)
 91         {
 92             ob_clean();
 93         }
 94 
 95         // Generate the server headers
 96         header('Content-Type: '.$mime);
 97         header('Content-Disposition: attachment; filename="'.$filename.'"');
 98         header('Expires: 0');
 99         header('Content-Transfer-Encoding: binary');
100         header('Content-Length: '.$filesize);
101 
102         // Internet Explorer-specific headers
103         if (isset($_SERVER['HTTP_USER_AGENT']) && strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE') !== FALSE)
104         {
105             header('Cache-Control: no-cache, no-store, must-revalidate');
106         }
107 
108         header('Pragma: no-cache');
109 
110         // If we have raw data - just dump it
111         if ($data !== NULL)
112         {
113             exit($data);
114         }
115 
116         // Flush 1MB chunks of data
117         while ( ! feof($fp) && ($data = fread($fp, 1048576)) !== FALSE)
118         {
119             echo $data;
120         }
121 
122         fclose($fp);
123         exit;
124     }
125 }

在程序中使用以下方法下载文件:

1 $this->load->helper('download');
2 $file = APPPATH.'download/file.zip';
3 force_download($file, NULL);

参考链接:

1. The “right way” to handle file downloads in PHP

2. PHP Download Script with Resume option

3. PHP File Download Script

4. codeigniter - Download helper for large files

5. codeigniter - Using Download Helper With Extremely Large Files

6. Advanced File Downloading Library

 

posted @ 2013-03-06 14:20  陈小飞  阅读(960)  评论(0编辑  收藏  举报