Posted By

Almorca on 01/04/10


Tagged

php file download


Versions (?)

Who likes this?

3 people have marked this snippet as a favorite

Almorca
mgerdt
wattsupnow


Download any file from a server.


 / Published in: PHP
 

URL: http://www.almorca.es

Class has simple interface to download any file from a server without displaying the location of the file.

  1. <?php
  2. /*
  3.  * LICENCE: This program is free software: you can redistribute it and/or modify
  4.  * it under the terms of the GNU Affero General Public License as published by
  5.  * the Free Software Foundation, either version 3 of the License, or
  6.  * (at your option) any later version.
  7.  *
  8.  * This program is distributed in the hope that it will be useful,
  9.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11.  * GNU Affero General Public License for more details.
  12.  *
  13.  * You should have received a copy of the GNU Affero General Public License
  14.  * along with this program. If not, see <http://www.gnu.org/licenses/>.
  15.  */
  16.  
  17. /**
  18.  * Signals that an attempt to open the file denoted by a specified pathname has failed.
  19.  *
  20.  * @author Alejandro Moreno Calvo <[email protected]>
  21.  * @copyright &copy; 2009 Alejandro Moreno Calvo
  22.  * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
  23.  * @version @package_version@
  24.  * @since 0.1
  25. */
  26. class FileNotFoundException extends Exception
  27. {
  28. /**
  29. * Constructs a <code>FileNotFoundException</code> with the specified detail message.
  30. *
  31. * @param s the detail message.
  32. */
  33. public function __construct($s) {
  34. parent::__construct($s);
  35. }
  36. }
  37.  
  38.  
  39. /**
  40.  * Download any file from a server.
  41.  *
  42.  * Class has simple interface to download any file from a server without displaying the location of the file.
  43.  *
  44.  * @author Alejandro Moreno Calvo <[email protected]>
  45.  * @copyright &copy; 2009 Alejandro Moreno Calvo
  46.  * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
  47.  * @version @package_version@
  48.  * @since 0.1
  49.  */
  50. class Download
  51. {
  52. /** Size of buffers in which the file will be sent. */
  53. const BUFFER_SIZE = 8192; // 8*1024
  54.  
  55. /**
  56. * List of all mimetypes
  57. *
  58. * @access protected
  59. * @var array
  60. */
  61. protected $_mediatypes;
  62.  
  63. /**
  64. * File name
  65. *
  66. * @access private
  67. * @var string
  68. */
  69. private $_filename;
  70.  
  71. /**
  72. * File path whit the file name. E.g. /etc/file
  73. *
  74. * @access private
  75. * @var string
  76. */
  77. private $_filepath;
  78.  
  79. /**
  80. * Mimetype
  81. *
  82. *
  83. * @access private
  84. * @var string
  85. */
  86. private $_mimetype;
  87.  
  88.  
  89. /**
  90. * Constructs a <code>Download</code> with the specified file.
  91. *
  92. * @param name File name
  93. * @param path File path
  94. * @since 0.1
  95. */
  96. public function __construct($name, $path = '/')
  97. {
  98. $this->_mediatypes = array (
  99. 'epub' => 'application/epub+zip',
  100. 'fb2' => 'text/xml',
  101. 'pdf' => 'application/pdf',
  102. 'rtf' => 'application/rtf',
  103. 'txt' => 'text/plain');
  104. $this->_filename = $name;
  105. $this->findFilepath($path, $name);
  106. $this->findMimetype($name);
  107. }
  108.  
  109. /**
  110. * Returns the file path
  111. *
  112. * @return string
  113. */
  114. public function getFilepath() {
  115. return $this->_filepath;
  116. }
  117.  
  118. /**
  119. * Returns the mime type
  120. *
  121. * @return string
  122. */
  123. public function getMimetype() {
  124. return $this->_mimetype;
  125. }
  126.  
  127. /**
  128. * This method determines the file path and if the file path is good.
  129. *
  130. * @param path folder where you keep the file for download
  131. * @return None
  132. * @exception FileNotFoundException if the file does not exist.
  133. * @exception Exception if the file name starts with '.'
  134. * @since 0.1
  135. */
  136. protected function findFilepath($path)
  137. {
  138. if ( $this->_filename[0] == '.' ) {
  139. throw new Exception("The file name can not start with '.' Current file name: " . $name);
  140. }
  141.  
  142. $filepath = $path . $this->_filename;
  143.  
  144. if ( file_exists($filepath) === true && is_file($filepath) === true && is_readable($filepath) === true ) {
  145. $this->_filepath = $filepath;
  146. } else {
  147. throw new FileNotFoundException("The system can not find the file specified: " . $filepath);
  148. }
  149. }
  150.  
  151. /**
  152. * Get the mime type
  153. *
  154. * @return String with mime type
  155. * @exception FileNotFoundException if the file does not exist.
  156. * @exception Exception if the file name starts with '.'
  157. * @since 0.1
  158. */
  159. protected function findMimetype()
  160. {
  161. $pathInfo = pathinfo($this->_filepath);
  162. $extension = $pathInfo['extension'];
  163. if ( array_key_exists($extension, $this->_mediatypes) ) {
  164. /* NOTE: This method have a security risk because the file may have been misslabled intentionally.
  165. * E.g. .exe rename to .jpg
  166. */
  167. $this->_mimetype = $this->_mediatypes[$extension];
  168. } else { // mime type is not set, get from server settings
  169. $mediatype = '';
  170.  
  171. if ( class_exists('finfo', false) ) { // PHP >= 5.3.0 or PECL fileinfo >= 0.1.0
  172. $constant = defined('FILEINFO_MIME_TYPE') ? FILEINFO_MIME_TYPE : FILEINFO_MIME;
  173. $fileInfo = finfo_open($constant);
  174. $mediatype = finfo_file($fileInfo, $this->_filepath);
  175. finfo_close($fileInfo);
  176. } else if ( function_exists("mime_content_type") ) {
  177. /* NOTE: this function is available since PHP 4.3.0, but only if
  178. * PHP was compiled with --with-mime-magic or, before 4.3.2, with --enable-mime-magic.
  179. *
  180. * On Windows, you must set mime_magic.magicfile in php.ini to point to the mime.magic
  181. * file bundeled with PHP; sometimes, this may even be needed under linux/unix.
  182. *
  183. * Also note that this has been DEPRECATED in favor of the fileinfo extension
  184. */
  185. $tempMime = mime_content_type($this->_filepath);
  186. list($mediatype, $charset) = explode('; ', $tempMime); // get the mime type and delete the charset
  187. } else if ( strstr($_SERVER[HTTP_USER_AGENT], "Macintosh") ) { // correct output on macs
  188. $mediatype = trim(exec('file -b --mime ' . escapeshellarg($this->_filepath)));
  189. } else { // regular unix systems
  190. $mediatype = trim(exec('file -bi '. escapeshellarg($this->_filepath)));
  191. }
  192.  
  193. if ($mediatype == '') { // mediatype is unknow
  194. $mediatype = "application/force-download";
  195. }
  196.  
  197. $this->_mimetype = $mediatype;
  198. }
  199. }
  200.  
  201. /**
  202. * Send the file via http
  203. *
  204. * @param $downloadName Name of the file the user will see.
  205. * @return None
  206. * @exception Exception if can not open the file.
  207. */
  208. public function sendFile($downloadName = NULL)
  209. {
  210. /* Make sure program execution doesn't time out.
  211. * Set maximum script execution time in seconds (0 means no limit)
  212. */
  213.  
  214. // file size in bytes
  215. $fsize = filesize($this->_filepath);
  216.  
  217. // set headers
  218. header("Last-Modified: " . gmdate("D, d M Y H:i:s", filemtime($this->_filepath)) . " GMT");
  219. header("Content-Description: File Transfer"); // Will help force a download for the user.
  220. if ( is_null($downloadName) ) { // change the file name
  221. header("Content-Disposition: attachment; filename=\"$this->_filename\"");
  222. } else {
  223. header("Content-Disposition: attachment; filename=\"$downloadName\"");
  224. }
  225. header("Content-Length: $fsize");
  226. header("Content-Type: $this->_mimetype");
  227.  
  228. // download
  229. $file = @fopen($this->_filepath,"rb");
  230. if ($file) {
  231. while( !feof($file) && connection_status() == CONNECTION_NORMAL ) {
  232. echo fread($file, self::BUFFER_SIZE);
  233. flush();
  234. }
  235. @fclose($file);
  236. } else {
  237. throw new Exception("Can not open file $this->_filepath");
  238. }
  239. }
  240. }

Report this snippet  

You need to login to post a comment.