File.php 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. <?php
  2. // +----------------------------------------------------------------------
  3. // | ThinkPHP [ WE CAN DO IT JUST THINK ]
  4. // +----------------------------------------------------------------------
  5. // | Copyright (c) 2006~2019 http://thinkphp.cn All rights reserved.
  6. // +----------------------------------------------------------------------
  7. // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
  8. // +----------------------------------------------------------------------
  9. // | Author: liu21st <liu21st@gmail.com>
  10. // +----------------------------------------------------------------------
  11. declare (strict_types = 1);
  12. namespace think;
  13. use SplFileInfo;
  14. use think\exception\FileException;
  15. /**
  16. * 文件上传类
  17. * @package think
  18. */
  19. class File extends SplFileInfo
  20. {
  21. /**
  22. * 文件hash规则
  23. * @var array
  24. */
  25. protected $hash = [];
  26. protected $hashName;
  27. public function __construct(string $path, bool $checkPath = true)
  28. {
  29. if ($checkPath && !is_file($path)) {
  30. throw new FileException(sprintf('The file "%s" does not exist', $path));
  31. }
  32. parent::__construct($path);
  33. }
  34. /**
  35. * 获取文件的哈希散列值
  36. * @access public
  37. * @param string $type
  38. * @return string
  39. */
  40. public function hash(string $type = 'sha1'): string
  41. {
  42. if (!isset($this->hash[$type])) {
  43. $this->hash[$type] = hash_file($type, $this->getPathname());
  44. }
  45. return $this->hash[$type];
  46. }
  47. /**
  48. * 获取文件的MD5值
  49. * @access public
  50. * @return string
  51. */
  52. public function md5(): string
  53. {
  54. return $this->hash('md5');
  55. }
  56. /**
  57. * 获取文件的SHA1值
  58. * @access public
  59. * @return string
  60. */
  61. public function sha1(): string
  62. {
  63. return $this->hash('sha1');
  64. }
  65. /**
  66. * 获取文件类型信息
  67. * @access public
  68. * @return string
  69. */
  70. public function getMime(): string
  71. {
  72. $finfo = finfo_open(FILEINFO_MIME_TYPE);
  73. return finfo_file($finfo, $this->getPathname());
  74. }
  75. /**
  76. * 移动文件
  77. * @access public
  78. * @param string $directory 保存路径
  79. * @param string|null $name 保存的文件名
  80. * @return File
  81. */
  82. public function move(string $directory, string $name = null): File
  83. {
  84. $target = $this->getTargetFile($directory, $name);
  85. set_error_handler(function ($type, $msg) use (&$error) {
  86. $error = $msg;
  87. });
  88. $renamed = rename($this->getPathname(), $target);
  89. restore_error_handler();
  90. if (!$renamed) {
  91. throw new FileException(sprintf('Could not move the file "%s" to "%s" (%s)', $this->getPathname(), $target, strip_tags($error)));
  92. }
  93. @chmod($target, 0666 & ~umask());
  94. return $target;
  95. }
  96. /**
  97. * 实例化一个新文件
  98. * @param string $directory
  99. * @param null|string $name
  100. * @return File
  101. */
  102. protected function getTargetFile(string $directory, string $name = null): File
  103. {
  104. if (!is_dir($directory)) {
  105. if (false === @mkdir($directory, 0777, true) && !is_dir($directory)) {
  106. throw new FileException(sprintf('Unable to create the "%s" directory', $directory));
  107. }
  108. } elseif (!is_writable($directory)) {
  109. throw new FileException(sprintf('Unable to write in the "%s" directory', $directory));
  110. }
  111. $target = rtrim($directory, '/\\') . \DIRECTORY_SEPARATOR . (null === $name ? $this->getBasename() : $this->getName($name));
  112. return new self($target, false);
  113. }
  114. /**
  115. * 获取文件名
  116. * @param string $name
  117. * @return string
  118. */
  119. protected function getName(string $name): string
  120. {
  121. $originalName = str_replace('\\', '/', $name);
  122. $pos = strrpos($originalName, '/');
  123. $originalName = false === $pos ? $originalName : substr($originalName, $pos + 1);
  124. return $originalName;
  125. }
  126. /**
  127. * 文件扩展名
  128. * @return string
  129. */
  130. public function extension(): string
  131. {
  132. return $this->getExtension();
  133. }
  134. /**
  135. * 自动生成文件名
  136. * @access protected
  137. * @param string|\Closure $rule
  138. * @return string
  139. */
  140. public function hashName($rule = 'date'): string
  141. {
  142. if (!$this->hashName) {
  143. if ($rule instanceof \Closure) {
  144. $this->hashName = call_user_func_array($rule, [$this]);
  145. } else {
  146. switch (true) {
  147. case in_array($rule, hash_algos()):
  148. $hash = $this->hash($rule);
  149. $this->hashName = substr($hash, 0, 2) . DIRECTORY_SEPARATOR . substr($hash, 2);
  150. break;
  151. case is_callable($rule):
  152. $this->hashName = call_user_func($rule);
  153. break;
  154. default:
  155. $this->hashName = date('Ymd') . DIRECTORY_SEPARATOR . md5((string) microtime(true));
  156. break;
  157. }
  158. }
  159. }
  160. return $this->hashName . '.' . $this->extension();
  161. }
  162. }