ChunkUploadService.php 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. <?php
  2. namespace plugin\saiadmin\service\storage;
  3. use plugin\saiadmin\app\logic\system\SystemConfigLogic;
  4. use plugin\saiadmin\app\model\system\SystemAttachment;
  5. use plugin\saiadmin\exception\ApiException;
  6. use plugin\saiadmin\utils\Arr;
  7. /**
  8. * 切片上传服务
  9. */
  10. class ChunkUploadService
  11. {
  12. /**
  13. * 基础配置
  14. */
  15. protected $config;
  16. protected $path;
  17. protected $folder = "chunk";
  18. /**
  19. * 初始化切片上传服务
  20. */
  21. public function __construct($folder = "chunk")
  22. {
  23. $logic = new SystemConfigLogic();
  24. $this->folder = $folder;
  25. $this->config = $logic->getGroup('upload_config');
  26. $this->path = $this->checkPath();
  27. }
  28. /**
  29. * 检查并创建上传路径
  30. * @return string
  31. */
  32. public function checkPath(): string
  33. {
  34. $root = Arr::getConfigValue($this->config, 'local_root');
  35. $path = base_path() . DIRECTORY_SEPARATOR . $root . $this->folder . DIRECTORY_SEPARATOR;
  36. if (!is_dir($path)) {
  37. mkdir($path, 0777, true);
  38. }
  39. return $path;
  40. }
  41. /**
  42. * 检查切片文件上传状态
  43. * @param $data
  44. * @return array
  45. */
  46. public function checkChunk($data): array
  47. {
  48. $allow_file = Arr::getConfigValue($this->config, 'upload_allow_file');
  49. if (!in_array($data['ext'], explode(',', $allow_file))) {
  50. throw new ApiException('不支持该格式的文件上传');
  51. }
  52. // 检查已经上传的分片文件
  53. for ($i = 0; $i < $data['total']; ++$i) {
  54. $chunkFile = $this->path . "{$data['hash']}_{$data['total']}_{$i}.chunk";
  55. if (!file_exists($chunkFile)) {
  56. if ($i == 0) {
  57. return $this->uploadChunk($data);
  58. } else {
  59. return ['chunk' => $i, 'status' => 'resume'];
  60. }
  61. }
  62. }
  63. // 分片文件已经全部上传
  64. return ['chunk' => $i, 'status' => 'success'];
  65. }
  66. /**
  67. * 上传切片
  68. * @param $data
  69. * @return array
  70. */
  71. public function uploadChunk($data): array
  72. {
  73. $allow_file = Arr::getConfigValue($this->config, 'upload_allow_file');
  74. if (!in_array($data['ext'], explode(',', $allow_file))) {
  75. throw new ApiException('不支持该格式的文件上传');
  76. }
  77. $request = request();
  78. if (!$request) {
  79. throw new ApiException('切片上传服务必须在 HTTP 请求环境下调用');
  80. }
  81. $uploadFile = current($request->file());
  82. $chunkName = $this->path . "{$data['hash']}_{$data['total']}_{$data['index']}.chunk";
  83. $uploadFile->move($chunkName);
  84. if (($data['index'] + 1) == $data['total']) {
  85. return $this->mergeChunk($data);
  86. }
  87. return ['chunk' => $data['index'], 'status' => 'success'];
  88. }
  89. /**
  90. * 合并切片文件
  91. * @param $data
  92. * @return array
  93. */
  94. public function mergeChunk($data): array
  95. {
  96. $filePath = $this->path . $data['hash'] . '.' . $data['ext'];
  97. $fileHandle = fopen($filePath, 'w');
  98. for ($i = 0; $i < $data['total']; ++$i) {
  99. $chunkFile = $this->path . "{$data['hash']}_{$data['total']}_{$i}.chunk";
  100. if (!file_exists($chunkFile)) {
  101. throw new ApiException('切片文件查找失败,请重新上传');
  102. }
  103. fwrite($fileHandle, file_get_contents($chunkFile));
  104. unlink($chunkFile);
  105. }
  106. $domain = Arr::getConfigValue($this->config, 'local_domain');
  107. $uri = Arr::getConfigValue($this->config, 'local_uri');
  108. $baseUrl = $domain . $uri . $this->folder . '/';
  109. $save_path = Arr::getConfigValue($this->config, 'local_root') . $this->folder . '/';
  110. $object_name = $data['hash'] . '.' . $data['ext'];
  111. $info['storage_mode'] = 1;
  112. $info['category_id'] = 1;
  113. $info['origin_name'] = $data['name'];
  114. $info['object_name'] = $object_name;
  115. $info['hash'] = $data['hash'];
  116. $info['mime_type'] = $data['type'];
  117. $info['storage_path'] = $save_path . $object_name;
  118. $info['suffix'] = $data['ext'];
  119. $info['size_byte'] = $data['size'];
  120. $info['size_info'] = formatBytes($data['size']);
  121. $info['url'] = $baseUrl . $object_name;
  122. SystemAttachment::create($info);
  123. return $info;
  124. }
  125. }