Local.php 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. <?php
  2. namespace app\common\library\upload\driver;
  3. use ba\Filesystem;
  4. use think\facade\Config;
  5. use think\file\UploadedFile;
  6. use think\exception\FileException;
  7. use app\common\library\upload\Driver;
  8. /**
  9. * 上传到本地磁盘的驱动
  10. * @see Driver
  11. */
  12. class Local extends Driver
  13. {
  14. protected array $options = [];
  15. public function __construct(array $options = [])
  16. {
  17. $this->options = Config::get('filesystem.disks.public');
  18. if (!empty($options)) {
  19. $this->options = array_merge($this->options, $options);
  20. }
  21. }
  22. /**
  23. * 保存文件
  24. * @param UploadedFile $file
  25. * @param string $saveName
  26. * @return bool
  27. */
  28. public function save(UploadedFile $file, string $saveName): bool
  29. {
  30. $savePathInfo = pathinfo($saveName);
  31. $saveFullPath = $this->getFullPath($saveName);
  32. // cgi 直接 move
  33. if (request()->isCgi()) {
  34. $file->move($saveFullPath, $savePathInfo['basename']);
  35. return true;
  36. }
  37. set_error_handler(function ($type, $msg) use (&$error) {
  38. $error = $msg;
  39. });
  40. // 建立文件夹
  41. if (!is_dir($saveFullPath) && !mkdir($saveFullPath, 0755, true)) {
  42. restore_error_handler();
  43. throw new FileException(sprintf('Unable to create the "%s" directory (%s)', $saveFullPath, strip_tags($error)));
  44. }
  45. // cli 使用 rename
  46. $saveName = $this->getFullPath($saveName, true);
  47. if (!rename($file->getPathname(), $saveName)) {
  48. restore_error_handler();
  49. throw new FileException(sprintf('Could not move the file "%s" to "%s" (%s)', $file->getPathname(), $saveName, strip_tags($error)));
  50. }
  51. restore_error_handler();
  52. @chmod($saveName, 0666 & ~umask());
  53. return true;
  54. }
  55. /**
  56. * 删除文件
  57. * @param string $saveName
  58. * @return bool
  59. */
  60. public function delete(string $saveName): bool
  61. {
  62. $saveFullName = $this->getFullPath($saveName, true);
  63. if ($this->exists($saveFullName)) {
  64. @unlink($saveFullName);
  65. }
  66. Filesystem::delEmptyDir(dirname($saveFullName));
  67. return true;
  68. }
  69. /**
  70. * 获取资源 URL 地址
  71. * @param string $saveName 资源保存名称
  72. * @param string|bool $domain 是否携带域名 或者直接传入域名
  73. * @param string $default 默认值
  74. * @return string
  75. */
  76. public function url(string $saveName, string|bool $domain = true, string $default = ''): string
  77. {
  78. $saveName = $this->clearRootPath($saveName);
  79. if ($domain === true) {
  80. $domain = '//' . request()->host();
  81. } elseif ($domain === false) {
  82. $domain = '';
  83. }
  84. $saveName = $saveName ?: $default;
  85. if (!$saveName) return $domain;
  86. $regex = "/^((?:[a-z]+:)?\/\/|data:image\/)(.*)/i";
  87. if (preg_match('/^http(s)?:\/\//', $saveName) || preg_match($regex, $saveName) || $domain === false) {
  88. return $saveName;
  89. }
  90. return str_replace('\\', '/', $domain . $saveName);
  91. }
  92. /**
  93. * 文件是否存在
  94. * @param string $saveName
  95. * @return bool
  96. */
  97. public function exists(string $saveName): bool
  98. {
  99. $saveFullName = $this->getFullPath($saveName, true);
  100. return file_exists($saveFullName);
  101. }
  102. /**
  103. * 获取文件的完整存储路径
  104. * @param string $saveName
  105. * @param bool $baseName 是否包含文件名
  106. * @return string
  107. */
  108. public function getFullPath(string $saveName, bool $baseName = false): string
  109. {
  110. $savePathInfo = pathinfo($saveName);
  111. $root = $this->getRootPath();
  112. $dirName = $savePathInfo['dirname'] . '/';
  113. // 以 root 路径开始时单独返回,避免重复调用此方法时造成 $dirName 的错误拼接
  114. if (str_starts_with($saveName, $root)) {
  115. return Filesystem::fsFit($baseName || !isset($savePathInfo['extension']) ? $saveName : $dirName);
  116. }
  117. return Filesystem::fsFit($root . $dirName . ($baseName ? $savePathInfo['basename'] : ''));
  118. }
  119. public function clearRootPath(string $saveName): string
  120. {
  121. return str_replace($this->getRootPath(), '', Filesystem::fsFit($saveName));
  122. }
  123. public function getRootPath(): string
  124. {
  125. return Filesystem::fsFit(str_replace($this->options['url'], '', $this->options['root']));
  126. }
  127. }