PageRenderTime 47ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/system/classes/helpers/file.php

https://github.com/shnhrrsn/EightPHP
PHP | 365 lines | 289 code | 21 blank | 55 comment | 9 complexity | ce42282948eb1b6477aae2f36f7f0dad MD5 | raw file
Possible License(s): BSD-3-Clause
  1. <?php
  2. /**
  3. * File helper class.
  4. *
  5. * @package System
  6. * @subpackage Helpers
  7. * @author EightPHP Development Team
  8. * @copyright (c) 2009-2010 EightPHP
  9. * @license http://license.eightphp.com
  10. */
  11. class file_Core {
  12. // Location of Mime Magic DB
  13. const MAGIC_DB = '/usr/share/misc/magic';
  14. // Dir push/pop stack
  15. static $dir_stack = array();
  16. /**
  17. * Moves into a new directory
  18. *
  19. * @param string directory to move into
  20. */
  21. public static function push_dir($dir) {
  22. array_push(self::$dir_stack, getcwd());
  23. chdir($dir);
  24. }
  25. /**
  26. * Pops back to previous directory
  27. */
  28. public static function pop_dir() {
  29. if(!arr::e(self::$dir_stack)) {
  30. $dir = array_pop(self::$dir_stack);
  31. chdir($dir);
  32. }
  33. }
  34. /**
  35. * Recursive version of php's native glob() method
  36. *
  37. * @param int the pattern passed to glob()
  38. * @param int the flags passed to glob()
  39. * @param string the path to scan
  40. * @return mixed an array of files in the given path matching the pattern.
  41. */
  42. public static function rglob($pattern='*', $flags = 0, $path='') {
  43. $paths = glob($path.'*', GLOB_MARK|GLOB_ONLYDIR|GLOB_NOSORT);
  44. $files = glob($path.$pattern, $flags);
  45. foreach ($paths as $path) {
  46. $files = array_merge($files, file::rglob($pattern, $flags, $path));
  47. }
  48. return $files;
  49. }
  50. /**
  51. * Attempt to get the mime type from a file. This method is horribly
  52. * unreliable, due to PHP being horribly unreliable when it comes to
  53. * determining the mime-type of a file.
  54. *
  55. * @param string filename
  56. * @return string|boolean mime-type: if found, false: if not found
  57. */
  58. public static function mime($filename) {
  59. // Make sure the file is readable
  60. if(!(is_file($filename) and is_readable($filename)))
  61. return NO;
  62. // Get the extension from the filename
  63. $extension = strtolower(substr(strrchr($filename, '.'), 1));
  64. if(preg_match('/^(?:jpe?g|png|[gt]if|bmp|swf)$/', $extension)) {
  65. // Disable error reporting
  66. $ER = error_reporting(0);
  67. // Use getimagesize() to find the mime type on images
  68. $mime = getimagesize($filename);
  69. // Turn error reporting back on
  70. error_reporting($ER);
  71. // Return the mime type
  72. if(isset($mime['mime']))
  73. return $mime['mime'];
  74. }
  75. if(function_exists('finfo_open')) {
  76. // Use the fileinfo extension
  77. $finfo = finfo_open(FILEINFO_MIME, self::MAGIC_DB);
  78. $mime = finfo_file($finfo, $filename);
  79. finfo_close($finfo);
  80. // Return the mime type
  81. return $mime;
  82. }
  83. if(ini_get('mime_magic.magicfile') and function_exists('mime_content_type')) {
  84. // Return the mime type using mime_content_type
  85. return mime_content_type($filename);
  86. }
  87. if(!empty($extension) and is_array($mime = Eight::config('mimes.'.$extension))) {
  88. // Return the mime-type guess, based on the extension
  89. return $mime[0];
  90. }
  91. // Unable to find the mime-type
  92. return NO;
  93. }
  94. /**
  95. * Force a download of a file to the user's browser. This function is
  96. * binary-safe and will work with any MIME type that Eight is aware of.
  97. *
  98. * @param string a file path or file name
  99. * @param mixed data to be sent if the filename does not exist
  100. * @param string suggested filename to display in the download
  101. */
  102. public static function download($filename = nil, $data = nil, $nicename = nil) {
  103. if(empty($filename))
  104. return NO;
  105. if(is_file($filename)) {
  106. // Get the real path
  107. $filepath = str_replace('\\', '/', realpath($filename));
  108. // Set filesize
  109. $filesize = filesize($filepath);
  110. // Get filename
  111. $filename = substr(strrchr('/'.$filepath, '/'), 1);
  112. // Get extension
  113. $extension = strtolower(substr(strrchr($filepath, '.'), 1));
  114. } else {
  115. // Get filesize
  116. $filesize = strlen($data);
  117. // Make sure the filename does not have directory info
  118. $filename = substr(strrchr('/'.$filename, '/'), 1);
  119. // Get extension
  120. $extension = strtolower(substr(strrchr($filename, '.'), 1));
  121. }
  122. // Get the mime type of the file
  123. $mime = Eight::config('mimes.'.$extension);
  124. if(empty($mime)) {
  125. // Set a default mime if none was found
  126. $mime = array('application/octet-stream');
  127. }
  128. // Generate the server headers
  129. header('Content-Type: '.$mime[0]);
  130. header('Content-Disposition: attachment; filename="'.(empty($nicename) ? $filename : $nicename).'"');
  131. header('Content-Transfer-Encoding: binary');
  132. header('Content-Length: '.sprintf('%d', $filesize));
  133. // More caching prevention
  134. header('Expires: 0');
  135. if(Eight::user_agent('browser') === 'Internet Explorer') {
  136. // Send IE headers
  137. header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
  138. header('Pragma: public');
  139. } else {
  140. // Send normal headers
  141. header('Pragma: no-cache');
  142. }
  143. // Clear the output buffer
  144. Eight::close_buffers(NO);
  145. if(isset($filepath)) {
  146. // Open the file
  147. $handle = fopen($filepath, 'rb');
  148. // Send the file data
  149. fpassthru($handle);
  150. // Close the file
  151. fclose($handle);
  152. } else {
  153. // Send the file data
  154. echo $data;
  155. }
  156. }
  157. /**
  158. * Split a file into pieces matching a specific size.
  159. *
  160. * @param string file to be split
  161. * @param string directory to output to, defaults to the same directory as the file
  162. * @param integer size, in MB, for each chunk to be
  163. * @return integer The number of pieces that were created.
  164. */
  165. public static function split($filename, $output_dir = NO, $piece_size = 10) {
  166. // Find output dir
  167. $output_dir = ($output_dir == NO) ? pathinfo(str_replace('\\', '/', realpath($filename)), PATHINFO_DIRNAME) : str_replace('\\', '/', realpath($output_dir));
  168. $output_dir = rtrim($output_dir, '/').'/';
  169. // Open files for writing
  170. $input_file = fopen($filename, 'rb');
  171. // Change the piece size to bytes
  172. $piece_size = 1024 * 1024 * (int) $piece_size; // Size in bytes
  173. // Set up reading variables
  174. $read = 0; // Number of bytes read
  175. $piece = 1; // Current piece
  176. $chunk = 1024 * 8; // Chunk size to read
  177. // Split the file
  178. while(!feof($input_file)) {
  179. // Open a new piece
  180. $piece_name = $filename.'.'.str_pad($piece, 3, '0', STR_PAD_LEFT);
  181. $piece_open = @fopen($piece_name, 'wb+') or die('Could not write piece '.$piece_name);
  182. // Fill the current piece
  183. while($read < $piece_size and $data = fread($input_file, $chunk)) {
  184. fwrite($piece_open, $data) or die('Could not write to open piece '.$piece_name);
  185. $read += $chunk;
  186. }
  187. // Close the current piece
  188. fclose($piece_open);
  189. // Prepare to open a new piece
  190. $read = 0;
  191. $piece++;
  192. // Make sure that piece is valid
  193. ($piece < 999) or die('Maximum of 999 pieces exceeded, try a larger piece size');
  194. }
  195. // Close input file
  196. fclose($input_file);
  197. // Returns the number of pieces that were created
  198. return ($piece - 1);
  199. }
  200. /**
  201. * Join a split file into a whole file.
  202. *
  203. * @param string split filename, without .000 extension
  204. * @param string output filename, if different then an the filename
  205. * @return integer The number of pieces that were joined.
  206. */
  207. public static function join($filename, $output = NO) {
  208. if($output == NO)
  209. $output = $filename;
  210. // Set up reading variables
  211. $piece = 1; // Current piece
  212. $chunk = 1024 * 8; // Chunk size to read
  213. // Open output file
  214. $output_file = @fopen($output, 'wb+') or die('Could not open output file '.$output);
  215. // Read each piece
  216. while($piece_open = @fopen(($piece_name = $filename.'.'.str_pad($piece, 3, '0', STR_PAD_LEFT)), 'rb')) {
  217. // Write the piece into the output file
  218. while(!feof($piece_open)) {
  219. fwrite($output_file, fread($piece_open, $chunk));
  220. }
  221. // Close the current piece
  222. fclose($piece_open);
  223. // Prepare for a new piece
  224. $piece++;
  225. // Make sure piece is valid
  226. ($piece < 999) or die('Maximum of 999 pieces exceeded');
  227. }
  228. // Close the output file
  229. fclose($output_file);
  230. // Return the number of pieces joined
  231. return ($piece - 1);
  232. }
  233. /**
  234. * Loops through the mimes config array and finds the extension for a given mime type.
  235. * Might be able to speed this one up a bit...not sure.
  236. *
  237. * @param string mime type
  238. * @return string extension for given mime type
  239. */
  240. public static function mime_to_ext($mime) {
  241. $mimes = Eight::config('mimes');
  242. foreach($mimes as $k=>$m) {
  243. foreach($m as $v) {
  244. if($mime == $v) {
  245. return $k;
  246. }
  247. }
  248. }
  249. }
  250. public static function ext($file) {
  251. if(substr_count($file, ".") > 0) {
  252. return substr(strrchr($file, "."), 1);
  253. } else {
  254. return NULL;
  255. }
  256. }
  257. public static function without_ext($file) {
  258. if(substr_count($file, ".") > 0) {
  259. return substr($file, 0, strrpos($file, "."));
  260. } else {
  261. return $file;
  262. }
  263. }
  264. public static function ext_replace($file, $new) {
  265. $old = self::ext($file);
  266. return substr_replace($file, $new, strlen($old)*-1);
  267. }
  268. /**
  269. * Delete Files
  270. *
  271. * Deletes all files contained in the supplied directory path.
  272. * Files must be writable or owned by the system in order to be deleted.
  273. * If the second parameter is set to true, any directories contained
  274. * within the supplied base directory will be nuked as well.
  275. *
  276. * @access public
  277. * @param string path to file
  278. * @param bool whether to delete any directories found in the path
  279. * @return bool
  280. */
  281. public static function delete_files($path, $del_dir = false, $level = 0) {
  282. // Trim the trailing slash
  283. $path = preg_replace("|^(.+?)/*$|", "\\1", $path);
  284. if ( ! $current_dir = @opendir($path))
  285. return;
  286. while(false !== ($filename = @readdir($current_dir))) {
  287. if ($filename != "." and $filename != "..") {
  288. if (is_dir($path.'/'.$filename)) {
  289. $level++;
  290. self::delete_files($path.'/'.$filename, $del_dir, $level);
  291. } else {
  292. unlink($path.'/'.$filename);
  293. }
  294. }
  295. }
  296. @closedir($current_dir);
  297. if ($del_dir == true and $level > 0) {
  298. @rmdir($path);
  299. }
  300. }
  301. } // End file