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
4. codeigniter - Download helper for large files
5. codeigniter - Using Download Helper With Extremely Large Files
6. Advanced File Downloading Library