UploadHelper.php 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305
  1. <?php
  2. namespace common\helpers;
  3. use Yii;
  4. use yii\imagine\Image;
  5. use yii\web\UploadedFile;
  6. use yii\web\NotFoundHttpException;
  7. use common\forms\UploadForm;
  8. use common\enums\AttachmentUploadTypeEnum;
  9. use common\enums\AttachmentDriveEnum;
  10. /**
  11. * 上传辅助类
  12. *
  13. * Class UploadHelper
  14. * @package common\helpers
  15. * @author jianyan74 <751393839@qq.com>
  16. */
  17. class UploadHelper
  18. {
  19. /**
  20. * 切片合并缓存前缀
  21. */
  22. const PREFIX_MERGE_CACHE = 'upload-file-guid:';
  23. /**
  24. * @var
  25. */
  26. protected $form;
  27. /**
  28. * 写入
  29. *
  30. * @param bool $data
  31. * @throws NotFoundHttpException
  32. * @throws \League\Flysystem\FileExistsException
  33. * @throws \League\Flysystem\FileNotFoundException
  34. */
  35. public static function save(UploadForm $form)
  36. {
  37. // 拦截 如果是切片上传就接管
  38. if ($form->isCut == true) {
  39. return self::cut($form);
  40. }
  41. // 判断如果文件存在就重命名文件名
  42. if ($form->fileSystem->has($form->fileRelativePath)) {
  43. $name = explode('_', $form->name);
  44. $form->name = $name[0] . '_' . time() . '_' . StringHelper::random(8);
  45. $form->fileRelativePath = $form->paths['relativePath'] . $form->name . '.' . $form->extension;
  46. }
  47. // 判断是否直接写入
  48. if (empty($form->fileData)) {
  49. $file = UploadedFile::getInstanceByName($form->fileName);
  50. if (!$file->getHasError()) {
  51. $stream = fopen($file->tempName, 'r+');
  52. $result = $form->fileSystem->writeStream($form->fileRelativePath, $stream);
  53. if (!$result) {
  54. throw new NotFoundHttpException('文件写入失败');
  55. }
  56. if (is_resource($stream)) {
  57. fclose($stream);
  58. }
  59. } else {
  60. throw new NotFoundHttpException('上传失败,可能文件太大了');
  61. }
  62. } else {
  63. $result = $form->fileSystem->write($form->fileRelativePath, $form->fileData);
  64. if (!$result) {
  65. throw new NotFoundHttpException('文件写入失败');
  66. }
  67. }
  68. // 本地的图片才可执行
  69. if ($form->upload_type == AttachmentUploadTypeEnum::IMAGES && $form->drive == AttachmentDriveEnum::LOCAL) {
  70. // 图片水印
  71. self::watermark($form);
  72. // 图片压缩
  73. // self::compress($form);
  74. // 创建缩略图
  75. // self::thumb($form);
  76. // 获取图片信息
  77. if (empty($form->width) && empty($form->height) && $form->fileSystem->has($form->fileRelativePath)) {
  78. $imgInfo = getimagesize(Yii::getAlias('@attachment') . '/' . $form->fileRelativePath);
  79. $form->width = $imgInfo[0] ?? 0;
  80. $form->height = $imgInfo[1] ?? 0;
  81. }
  82. }
  83. return $form;
  84. }
  85. /**
  86. * 获取视频封面图
  87. *
  88. * @param UploadForm $form
  89. * @return UploadForm|false
  90. * @throws NotFoundHttpException
  91. * @throws \League\Flysystem\FileExistsException
  92. */
  93. public static function videoPoster(UploadForm $form)
  94. {
  95. // use `ffmpeg` get first frame as video poster
  96. // save poster local and upload to cloud, return the cloud url
  97. $file = UploadedFile::getInstanceByName($form->fileName);
  98. if ($file->error === UPLOAD_ERR_OK) {
  99. $form->upload_type = AttachmentUploadTypeEnum::IMAGES;
  100. $form->name = $form->name . '_poster';
  101. $form->extension = 'jpg';
  102. $form->fileRelativePath = $form->paths['relativePath'] . $form->name . '.' . $form->extension;
  103. $tmpPosterFilePath = sys_get_temp_dir() . DIRECTORY_SEPARATOR . $form->name . '.' . $form->extension;
  104. FfmpegHelper::imageResize($file->tempName, $tmpPosterFilePath, 0);
  105. if (file_exists($tmpPosterFilePath)) {
  106. $stream = fopen($tmpPosterFilePath, 'r+');
  107. $result = $form->fileSystem->writeStream($form->fileRelativePath, $stream);
  108. if (!$result) {
  109. throw new NotFoundHttpException('文件写入失败');
  110. }
  111. if (is_resource($stream)) {
  112. fclose($stream);
  113. }
  114. $imgInfo = getimagesize($tmpPosterFilePath);
  115. $form->width = $imgInfo[0] ?? 0;
  116. $form->height = $imgInfo[1] ?? 0;
  117. unlink($tmpPosterFilePath); // delete tmp file
  118. return $form;
  119. }
  120. }
  121. return false;
  122. }
  123. /**
  124. * 水印
  125. *
  126. * @param $fullPathName
  127. * @return bool
  128. */
  129. protected static function watermark(UploadForm $form)
  130. {
  131. if (Yii::$app->services->config->backendConfig('sys_image_watermark_status') != true) {
  132. return true;
  133. }
  134. // 原图路径
  135. $absolutePath = Yii::getAlias("@attachment/") . $form->fileRelativePath;
  136. $local = Yii::$app->services->config->backendConfig('sys_image_watermark_location');
  137. $watermarkImg = StringHelper::getLocalFilePath(Yii::$app->services->config->backendConfig('sys_image_watermark_img'));
  138. if ($coordinate = DebrisHelper::getWatermarkLocation($absolutePath, $watermarkImg, $local)) {
  139. // $aliasName = StringHelper::getAliasUrl($fullPathName, 'watermark');
  140. Image::watermark($absolutePath, $watermarkImg, $coordinate)->save($absolutePath, ['quality' => 100]);
  141. }
  142. return true;
  143. }
  144. /**
  145. * 压缩
  146. *
  147. * @param $fullPathName
  148. * @return bool
  149. */
  150. protected static function compress(UploadForm $form)
  151. {
  152. if ($form->driveConfig['compress'] != true) {
  153. return true;
  154. }
  155. // 原图路径
  156. $absolutePath = Yii::getAlias("@attachment/") . $form->fileRelativePath;
  157. $imgInfo = getimagesize($absolutePath);
  158. $compressibility = $form->driveConfig['compressibility'];
  159. $tmpMinSize = 0;
  160. foreach ($compressibility as $key => $item) {
  161. if ($form->size >= $tmpMinSize && $form->size < $key && $item < 100) {
  162. // $aliasName = StringHelper::getAliasUrl($fullPathName, 'compress');
  163. Image::thumbnail($absolutePath, $imgInfo[0], $imgInfo[1])->save($absolutePath, ['quality' => $item]);
  164. break;
  165. }
  166. $tmpMinSize = $key;
  167. }
  168. return true;
  169. }
  170. /**
  171. * 缩略图
  172. *
  173. * @return bool
  174. */
  175. protected static function thumb(UploadForm $form)
  176. {
  177. if (empty($form->thumb)) {
  178. return true;
  179. }
  180. // 原图路径
  181. $absolutePath = Yii::getAlias("@attachment/") . $form->fileRelativePath;
  182. // 缩略图路径
  183. $path = Yii::getAlias("@attachment/") . $form->paths['thumbRelativePath'];
  184. FileHelper::mkdirs($path);
  185. $thumbPath = $path . $form->name . '.' . $form->extension;
  186. foreach ($form->thumb as $value) {
  187. $thumbFullPath = StringHelper::createThumbUrl($thumbPath, $value['width'], $value['height']);
  188. // 裁剪从坐标0,60 裁剪一张300 x 20 的图片,并保存 不设置坐标则从坐标0,0开始
  189. // Image::crop($originalPath, $thumbWidth , $thumbHeight, [0, 60])->save($thumbOriginalPath), ['quality' => 100]);
  190. Image::thumbnail($absolutePath, $value['width'], $value['height'])->save($thumbFullPath);
  191. }
  192. return true;
  193. }
  194. /**
  195. * 切片
  196. *
  197. * @throws \League\Flysystem\FileExistsException
  198. * @throws \League\Flysystem\FileNotFoundException
  199. */
  200. public static function cut(UploadForm $form): UploadForm
  201. {
  202. // 切片参数
  203. $chunk = $form->chunk + 1;
  204. $guid = $form->guid;
  205. // 临时文件夹路径
  206. $url = $form->paths['tmpRelativePath'] . $chunk . '.' . $form->extension;
  207. // 上传
  208. $file = UploadedFile::getInstanceByName($form->fileName);
  209. if ($file->error === UPLOAD_ERR_OK) {
  210. $stream = fopen($file->tempName, 'r+');
  211. $result = $form->fileSystem->writeStream($url, $stream);
  212. fclose($stream);
  213. // 判断如果上传成功就去合并文件
  214. if (($form->chunks - 1) <= $chunk) {
  215. // 缓存上传信息等待回调
  216. $form->uploadDrive = '';
  217. $form->fileSystem = '';
  218. Yii::$app->cache->set(self::PREFIX_MERGE_CACHE . $guid, $form, 3600);
  219. }
  220. $form->merge = true;
  221. }
  222. return $form;
  223. }
  224. /**
  225. * 切片合并
  226. *
  227. * @param int $name
  228. * @throws \League\Flysystem\FileExistsException
  229. * @throws \League\Flysystem\FileNotFoundException
  230. */
  231. public static function merge(UploadForm $form, $name = 1)
  232. {
  233. // 由于合并会附带上一次切片的信息,取消切片判断
  234. $form->isCut = false;
  235. $filePath = $form->paths['tmpRelativePath'] . $name . '.' . $form->extension;
  236. if ($form->fileSystem->has($filePath) && ($content = $form->fileSystem->read($filePath))) {
  237. if ($form->fileSystem->has($form->fileRelativePath)) {
  238. $form->fileSystem->update($form->fileRelativePath, $content);
  239. } else {
  240. $form->fileSystem->write($form->fileRelativePath, $content);
  241. }
  242. unset($content);
  243. $form->fileSystem->delete($filePath);
  244. $name += 1;
  245. self::merge($form, $name);
  246. } else {
  247. // 删除文件夹,如果删除失败重新去合并
  248. $form->fileSystem->deleteDir($form->paths['tmpRelativePath']);
  249. return $form;
  250. }
  251. }
  252. /**
  253. * @param $specific_type
  254. * @param $extension
  255. * @return string
  256. */
  257. public static function formattingFileType($specific_type, $extension, $upload_type)
  258. {
  259. if (preg_match("/^image/", $specific_type) && $extension != 'psd') {
  260. return AttachmentUploadTypeEnum::IMAGES;
  261. }
  262. return $upload_type;
  263. }
  264. }
粤ICP备19079148号