upload_tencent_cos.go 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  1. /*
  2. * @desc:腾讯oss
  3. * @company:云南省奇讯科技有限公司
  4. * @Author: yixiaohu
  5. * @Date: 2021/7/7 15:51
  6. */
  7. package adapter
  8. import (
  9. "context"
  10. "gfast/app/common/model"
  11. "gfast/app/common/service"
  12. "github.com/gogf/gf/errors/gerror"
  13. "github.com/gogf/gf/net/ghttp"
  14. "github.com/gogf/gf/os/gfile"
  15. "github.com/gogf/gf/os/gtime"
  16. "github.com/gogf/gf/text/gregex"
  17. "github.com/gogf/gf/text/gstr"
  18. "github.com/gogf/gf/util/gconv"
  19. "github.com/gogf/gf/util/grand"
  20. "github.com/tencentyun/cos-go-sdk-v5"
  21. "github.com/tencentyun/cos-go-sdk-v5/debug"
  22. "io"
  23. "net/http"
  24. "net/url"
  25. "strconv"
  26. "strings"
  27. )
  28. type UploadTencentCOSAdapter struct {
  29. UpPath string
  30. SecretID string
  31. SecretKey string
  32. RawUrl string
  33. }
  34. func (u UploadTencentCOSAdapter) UpImg(file *ghttp.UploadFile) (fileInfo *FileInfo, err error) {
  35. return u.upByType(file, "img")
  36. }
  37. func (u UploadTencentCOSAdapter) UpFile(file *ghttp.UploadFile) (fileInfo *FileInfo, err error) {
  38. return u.upByType(file, "file")
  39. }
  40. func (u UploadTencentCOSAdapter) UpImgs(files []*ghttp.UploadFile) (fileInfos []*FileInfo, err error) {
  41. return u.upBathByType(files, "img")
  42. }
  43. func (u UploadTencentCOSAdapter) UpFiles(files []*ghttp.UploadFile) (fileInfos []*FileInfo, err error) {
  44. return u.upBathByType(files, "file")
  45. }
  46. //文件上传 img|file
  47. func (u UploadTencentCOSAdapter) upByType(file *ghttp.UploadFile, fType string) (fileInfo *FileInfo, err error) {
  48. if file == nil {
  49. err = gerror.New("未上传任何文件")
  50. return
  51. }
  52. var (
  53. typeKey string
  54. sizeKey string
  55. )
  56. if fType == "img" {
  57. typeKey = "sys.uploadFile.imageType"
  58. sizeKey = "sys.uploadFile.imageSize"
  59. } else if fType == "file" {
  60. typeKey = "sys.uploadFile.fileType"
  61. sizeKey = "sys.uploadFile.fileSize"
  62. }
  63. //获取上传类型配置
  64. config, err := u.getUpConfig(typeKey)
  65. if err != nil {
  66. return
  67. }
  68. //检测文件类型
  69. rightType := u.checkFileType(file.Filename, config.ConfigValue)
  70. if !rightType {
  71. err = gerror.New("上传文件类型错误,只能包含后缀为:" + config.ConfigValue + "的文件。")
  72. return
  73. }
  74. //获取上传大小配置
  75. config, err = u.getUpConfig(sizeKey)
  76. if err != nil {
  77. return
  78. }
  79. rightSize, err := u.checkSize(config.ConfigValue, file.Size)
  80. if err != nil {
  81. return
  82. }
  83. if !rightSize {
  84. err = gerror.New("上传文件超过最大尺寸:" + config.ConfigValue)
  85. return
  86. }
  87. var path string
  88. path, err = u.upAction(file)
  89. if err != nil {
  90. return
  91. }
  92. fileInfo = &FileInfo{
  93. FileName: file.Filename,
  94. FileSize: file.Size,
  95. FileUrl: u.getUrl(path),
  96. FileType: file.Header.Get("Content-type"),
  97. }
  98. return
  99. }
  100. //批量上传 img|file
  101. func (u UploadTencentCOSAdapter) upBathByType(files []*ghttp.UploadFile, fType string) (fileInfos []*FileInfo, err error) {
  102. if len(files) == 0 {
  103. err = gerror.New("未上传任何文件")
  104. return
  105. }
  106. var (
  107. typeKey string
  108. sizeKey string
  109. )
  110. if fType == "img" {
  111. typeKey = "sys.uploadFile.imageType"
  112. sizeKey = "sys.uploadFile.imageSize"
  113. } else if fType == "file" {
  114. typeKey = "sys.uploadFile.fileType"
  115. sizeKey = "sys.uploadFile.fileSize"
  116. }
  117. //获取上传类型配置
  118. configType, err := u.getUpConfig(typeKey)
  119. if err != nil {
  120. return
  121. }
  122. //获取上传大小配置
  123. configSize, err := u.getUpConfig(sizeKey)
  124. if err != nil {
  125. return
  126. }
  127. for _, file := range files {
  128. //检测文件类型
  129. rightType := u.checkFileType(file.Filename, configType.ConfigValue)
  130. if !rightType {
  131. err = gerror.New("上传文件类型错误,只能包含后缀为:" + configType.ConfigValue + "的文件。")
  132. return
  133. }
  134. var rightSize bool
  135. rightSize, err = u.checkSize(configSize.ConfigValue, file.Size)
  136. if err != nil {
  137. return
  138. }
  139. if !rightSize {
  140. err = gerror.New("上传文件超过最大尺寸:" + configSize.ConfigValue)
  141. return
  142. }
  143. }
  144. for _, file := range files {
  145. var path string
  146. path, err = u.upAction(file)
  147. if err != nil {
  148. return
  149. }
  150. fileInfo := &FileInfo{
  151. FileName: file.Filename,
  152. FileSize: file.Size,
  153. FileUrl: u.getUrl(path),
  154. FileType: file.Header.Get("Content-type"),
  155. }
  156. fileInfos = append(fileInfos, fileInfo)
  157. }
  158. return
  159. }
  160. // 上传到腾讯cos操作
  161. func (u UploadTencentCOSAdapter) upAction(file *ghttp.UploadFile) (path string, err error) {
  162. name := gfile.Basename(file.Filename)
  163. name = strings.ToLower(strconv.FormatInt(gtime.TimestampNano(), 36) + grand.S(6))
  164. name = name + gfile.Ext(file.Filename)
  165. path = u.getUpPath() + name
  166. url, _ := url.Parse(u.RawUrl)
  167. b := &cos.BaseURL{BucketURL: url}
  168. c := cos.NewClient(b, &http.Client{
  169. Transport: &cos.AuthorizationTransport{
  170. SecretID: u.SecretID,
  171. SecretKey: u.SecretKey,
  172. Transport: &debug.DebugRequestTransport{
  173. RequestHeader: false,
  174. RequestBody: false,
  175. ResponseHeader: false,
  176. ResponseBody: false,
  177. },
  178. },
  179. })
  180. opt := &cos.ObjectPutOptions{
  181. ObjectPutHeaderOptions: &cos.ObjectPutHeaderOptions{
  182. ContentLength: int64(file.Size),
  183. },
  184. }
  185. var f io.ReadCloser
  186. f, err = file.Open()
  187. if err != nil {
  188. return
  189. }
  190. defer f.Close()
  191. _, err = c.Object.Put(context.Background(), path, f, opt)
  192. return
  193. }
  194. //获取上传配置
  195. func (u UploadTencentCOSAdapter) getUpConfig(key string) (config *model.SysConfig, err error) {
  196. config, err = service.SysConfig.GetConfigByKey(key)
  197. if err != nil {
  198. return
  199. }
  200. if config == nil {
  201. err = gerror.New("上传文件类型未设置,请在后台配置")
  202. return
  203. }
  204. return
  205. }
  206. //判断上传文件类型是否合法
  207. func (u UploadTencentCOSAdapter) checkFileType(fileName, typeString string) bool {
  208. suffix := gstr.SubStrRune(fileName, gstr.PosRRune(fileName, ".")+1, gstr.LenRune(fileName)-1)
  209. imageType := gstr.Split(typeString, ",")
  210. rightType := false
  211. for _, v := range imageType {
  212. if gstr.Equal(suffix, v) {
  213. rightType = true
  214. break
  215. }
  216. }
  217. return rightType
  218. }
  219. //检查文件大小是否合法
  220. func (u UploadTencentCOSAdapter) checkSize(configSize string, fileSize int64) (bool, error) {
  221. match, err := gregex.MatchString(`^([0-9]+)(?i:([a-z]*))$`, configSize)
  222. if err != nil {
  223. return false, err
  224. }
  225. if len(match) == 0 {
  226. err = gerror.New("上传文件大小未设置,请在后台配置,格式为(30M,30k,30MB)")
  227. return false, err
  228. }
  229. var cfSize int64
  230. switch gstr.ToUpper(match[2]) {
  231. case "MB", "M":
  232. cfSize = gconv.Int64(match[1]) * 1024 * 1024
  233. case "KB", "K":
  234. cfSize = gconv.Int64(match[1]) * 1024
  235. case "":
  236. cfSize = gconv.Int64(match[1])
  237. }
  238. if cfSize == 0 {
  239. err = gerror.New("上传文件大小未设置,请在后台配置,格式为(30M,30k,30MB),最大单位为MB")
  240. return false, err
  241. }
  242. return cfSize >= fileSize, nil
  243. }
  244. func (u UploadTencentCOSAdapter) getUpPath() (upPath string) {
  245. upPath = u.UpPath + gtime.Date() + "/"
  246. return
  247. }
  248. func (u UploadTencentCOSAdapter) getUrl(path string) string {
  249. url := u.RawUrl + path
  250. return url
  251. }