File.php 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  1. <?php
  2. /**
  3. * File helper class.
  4. *
  5. * @package KO7
  6. * @category Helpers
  7. *
  8. * @copyright (c) 2007-2016 Kohana Team
  9. * @copyright (c) since 2016 Koseven Team
  10. * @license https://koseven.dev/LICENSE
  11. */
  12. class KO7_File {
  13. /**
  14. * Attempt to get the mime type from a file. This method is horribly
  15. * unreliable, due to PHP being horribly unreliable when it comes to
  16. * determining the mime type of a file.
  17. *
  18. * $mime = File::mime($file);
  19. *
  20. * @param string $filename file name or path
  21. * @return string mime type on success
  22. * @return FALSE on failure
  23. */
  24. public static function mime($filename)
  25. {
  26. // Get the complete path to the file
  27. $filename = realpath($filename);
  28. // Get the extension from the filename
  29. $extension = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
  30. if (preg_match('/^(?:jpe?g|png|[gt]if|bmp|swf)$/', $extension))
  31. {
  32. // Use getimagesize() to find the mime type on images
  33. $file = getimagesize($filename);
  34. if (isset($file['mime']))
  35. return $file['mime'];
  36. }
  37. if (class_exists('finfo', FALSE))
  38. {
  39. if ($info = new finfo(defined('FILEINFO_MIME_TYPE') ? FILEINFO_MIME_TYPE : FILEINFO_MIME))
  40. {
  41. return $info->file($filename);
  42. }
  43. }
  44. if (ini_get('mime_magic.magicfile') AND function_exists('mime_content_type'))
  45. {
  46. // The mime_content_type function is only useful with a magic file
  47. return mime_content_type($filename);
  48. }
  49. if ( ! empty($extension))
  50. {
  51. return File::mime_by_ext($extension);
  52. }
  53. // Unable to find the mime-type
  54. return FALSE;
  55. }
  56. /**
  57. * Return the mime type of an extension.
  58. *
  59. * $mime = File::mime_by_ext('png'); // "image/png"
  60. *
  61. * @param string $extension php, pdf, txt, etc
  62. * @return string mime type on success
  63. * @return FALSE on failure
  64. */
  65. public static function mime_by_ext($extension)
  66. {
  67. // Extension has to be lowercase
  68. $extension = strtolower($extension);
  69. // Load all of the mime types
  70. $mimes = KO7::$config->load('mimes');
  71. return isset($mimes[$extension]) ? $mimes[$extension][0] : FALSE;
  72. }
  73. /**
  74. * Lookup MIME types for a file
  75. *
  76. * @see KO7_File::mime_by_ext()
  77. * @param string $extension Extension to lookup
  78. * @return array Array of MIMEs associated with the specified extension
  79. */
  80. public static function mimes_by_ext($extension)
  81. {
  82. // Load all of the mime types
  83. $mimes = KO7::$config->load('mimes');
  84. return isset($mimes[$extension]) ? ( (array) $mimes[$extension]) : [];
  85. }
  86. /**
  87. * Lookup file extensions by MIME type
  88. *
  89. * @param string $type File MIME type
  90. * @return array|false File extensions matching MIME type or false if none
  91. */
  92. public static function exts_by_mime($type)
  93. {
  94. static $types = [];
  95. // Fill the static array
  96. if (empty($types))
  97. {
  98. foreach (KO7::$config->load('mimes') as $ext => $mimes)
  99. {
  100. foreach ($mimes as $mime)
  101. {
  102. if ($mime == 'application/octet-stream')
  103. {
  104. // octet-stream is a generic binary
  105. continue;
  106. }
  107. if ( ! isset($types[$mime]))
  108. {
  109. $types[$mime] = [ (string) $ext];
  110. }
  111. elseif ( ! in_array($ext, $types[$mime]))
  112. {
  113. $types[$mime][] = (string) $ext;
  114. }
  115. }
  116. }
  117. }
  118. return isset($types[$type]) ? $types[$type] : FALSE;
  119. }
  120. /**
  121. * Lookup a single file extension by MIME type.
  122. *
  123. * @param string $type MIME type to lookup
  124. * @return string|false First file extension matching or false
  125. */
  126. public static function ext_by_mime($type)
  127. {
  128. $exts = File::exts_by_mime($type);
  129. if ($exts === FALSE)
  130. {
  131. return FALSE;
  132. }
  133. return current($exts);
  134. }
  135. /**
  136. * Split a file into pieces matching a specific size. Used when you need to
  137. * split large files into smaller pieces for easy transmission.
  138. *
  139. * $count = File::split($file);
  140. *
  141. * @param string $filename file to be split
  142. * @param integer $piece_size size, in MB, for each piece to be
  143. * @return integer The number of pieces that were created
  144. */
  145. public static function split($filename, $piece_size = 10)
  146. {
  147. // Open the input file
  148. $file = fopen($filename, 'rb');
  149. // Change the piece size to bytes
  150. $piece_size = floor($piece_size * 1024 * 1024);
  151. // Write files in 8k blocks
  152. $block_size = 1024 * 8;
  153. // Total number of pieces
  154. $pieces = 0;
  155. while ( ! feof($file))
  156. {
  157. // Create another piece
  158. $pieces += 1;
  159. // Create a new file piece
  160. $piece = str_pad($pieces, 3, '0', STR_PAD_LEFT);
  161. $piece = fopen($filename.'.'.$piece, 'wb+');
  162. // Number of bytes read
  163. $read = 0;
  164. do
  165. {
  166. // Transfer the data in blocks
  167. fwrite($piece, fread($file, $block_size));
  168. // Another block has been read
  169. $read += $block_size;
  170. }
  171. while ($read < $piece_size);
  172. // Close the piece
  173. fclose($piece);
  174. }
  175. // Close the file
  176. fclose($file);
  177. return $pieces;
  178. }
  179. /**
  180. * Join a split file into a whole file. Does the reverse of [File::split].
  181. *
  182. * $count = File::join($file);
  183. *
  184. * @param string $filename split filename, without .000 extension
  185. * @return integer The number of pieces that were joined.
  186. */
  187. public static function join($filename)
  188. {
  189. // Open the file
  190. $file = fopen($filename, 'wb+');
  191. // Read files in 8k blocks
  192. $block_size = 1024 * 8;
  193. // Total number of pieces
  194. $pieces = 0;
  195. while (is_file($piece = $filename.'.'.str_pad($pieces + 1, 3, '0', STR_PAD_LEFT)))
  196. {
  197. // Read another piece
  198. $pieces += 1;
  199. // Open the piece for reading
  200. $piece = fopen($piece, 'rb');
  201. while ( ! feof($piece))
  202. {
  203. // Transfer the data in blocks
  204. fwrite($file, fread($piece, $block_size));
  205. }
  206. // Close the piece
  207. fclose($piece);
  208. }
  209. return $pieces;
  210. }
  211. }