DefaultFileStorage.cs 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
  1. using FileStorage.Extensions;
  2. using Microsoft.AspNetCore.StaticFiles;
  3. using Microsoft.Extensions.Logging;
  4. using Microsoft.Extensions.Options;
  5. using XF.Domain.Dependency;
  6. using XF.Domain.Exceptions;
  7. namespace FileStorage;
  8. public class DefaultFileStorage : IFileStorage, IScopeDependency
  9. {
  10. private readonly IFileMetadataRepository _fileMetadataRepository;
  11. private readonly IOptionsSnapshot<StorageConfiguration> _fileUploadOptions;
  12. private readonly ILogger<DefaultFileStorage> _logger;
  13. public DefaultFileStorage(IFileMetadataRepository fileMetadataRepository, IOptionsSnapshot<StorageConfiguration> optionsSnapshot, ILogger<DefaultFileStorage> logger)
  14. {
  15. _fileMetadataRepository = fileMetadataRepository;
  16. _fileUploadOptions = optionsSnapshot;
  17. _logger = logger;
  18. }
  19. /// <summary>
  20. /// 本地上传
  21. /// </summary>
  22. /// <param name="fileName"></param>
  23. /// <param name="length"></param>
  24. /// <param name="extraInfo"></param>
  25. /// <param name="fileData"></param>
  26. /// <param name="client"></param>
  27. /// <param name="isVerification">是否验证文件格式</param>
  28. /// <returns></returns>
  29. public async Task<FileMetadata> UploadAsync(string fileName, long length, string extraInfo, Stream fileData, string client, bool? isVerification)
  30. {
  31. if (fileName == null)
  32. {
  33. fileName = "unkown";
  34. }
  35. fileName = fileName.Replace("<", "").Replace(">", "").Replace(" ", "");
  36. var rv = UploadLoca(fileName, length, extraInfo, fileData, client, isVerification);
  37. if (!string.IsNullOrEmpty(rv))
  38. {
  39. FileMetadata fileModel = new FileMetadata();
  40. fileModel.Client = client;
  41. fileModel.FileName = fileName;
  42. var ext = string.Empty;
  43. if (string.IsNullOrEmpty(fileName) == false)
  44. {
  45. var dotPos = fileName.LastIndexOf('.');
  46. ext = fileName[(dotPos + 1)..];
  47. }
  48. fileModel.FileExt = ext;
  49. fileModel.Path = rv;
  50. fileModel.Length = length;
  51. fileModel.SaveMode = _fileUploadOptions.Value.Impt;
  52. fileModel.ExtraInfo = extraInfo;
  53. fileModel.UploadTime = DateTime.Now;
  54. await _fileMetadataRepository.AddAsync(fileModel);
  55. return fileModel;
  56. }
  57. return null;
  58. }
  59. public async Task<Uri> GetFileUrlAsync(string id, string clientId)
  60. {
  61. var fileMetadata = await _fileMetadataRepository.GetAsync(x => x.Id == id && x.Client == clientId);
  62. if (fileMetadata != null)
  63. {
  64. long sTime = (long)(DateTime.Now.AddHours(1).ToUniversalTime() - new DateTime(1970, 1, 1, 0, 0, 0)).TotalSeconds;
  65. string encryptText = clientId + "|" + sTime + "|" + id;
  66. var signatureText = DESExtensions.Encrypt(encryptText);
  67. return new Uri("/file/files?id=" + id + "&expires=" + sTime + "&clientid=" + clientId + "&signature=" + signatureText);
  68. //return new Uri(_fileUploadOptions.Value.Local.VisDomain+fileMetadata.Path);
  69. }
  70. throw new UserFriendlyException("无权限访问");
  71. }
  72. public async Task<Uri> GetFileUrlIndefinitelyAsync(string id, string clientId)
  73. {
  74. var fileMetadata = await _fileMetadataRepository.GetAsync(x => x.Id == id && x.Client == clientId);
  75. if (fileMetadata != null)
  76. {
  77. long sTime = (long)(DateTime.Now.AddHours(1).ToUniversalTime() - new DateTime(1970, 1, 1, 0, 0, 0)).TotalSeconds;
  78. string encryptText = clientId + "|" + sTime + "|" + id;
  79. var signatureText = DESExtensions.Encrypt(encryptText);
  80. return new Uri("/file/files_indefinitely?id=" + id + "&expires=" + sTime + "&clientid=" + clientId + "&signature=" + signatureText);
  81. }
  82. throw new UserFriendlyException("无权限访问");
  83. }
  84. public (Stream stream, string contentType, string fileName) DownLoadFile(string id, string clientId)
  85. {
  86. var fileMetadata = _fileMetadataRepository.Get(x => x.Id == id && x.Client == clientId);
  87. if (fileMetadata != null)
  88. {
  89. string filePath = Path.Combine(Directory.GetCurrentDirectory(), fileMetadata.Path);
  90. var contentType = TaskGetFileContentTypeAsync(fileMetadata.Path);
  91. var stream = File.OpenRead(filePath);
  92. return (stream, contentType, fileMetadata.FileName);
  93. }
  94. throw new UserFriendlyException("无权限访问");
  95. }
  96. public async Task<bool> DelFileAsync(string id, string clientId)
  97. {
  98. var fileMetadata = await _fileMetadataRepository.GetAsync(x => x.Id == id && x.Client == clientId);
  99. if (fileMetadata != null)
  100. {
  101. string filePath = Path.Combine(Directory.GetCurrentDirectory(), fileMetadata.Path);
  102. await _fileMetadataRepository.RemoveAsync(id);
  103. File.Delete(filePath);
  104. return true;
  105. }
  106. return false;
  107. }
  108. public async Task<string> GetFilePathAsync(string id, string clientId)
  109. {
  110. var fileMetadata = await _fileMetadataRepository.GetAsync(x => x.Id == id && x.Client == clientId);
  111. return fileMetadata?.Path!;
  112. }
  113. public async Task<string> GetFilePath(string id, string expires, string clientId, string signature)
  114. {
  115. string decryptText = DESExtensions.Decrypt(signature);
  116. if (!string.IsNullOrEmpty(decryptText))
  117. {
  118. string[] paramData = decryptText.Split('|');
  119. if (id != paramData[2] || clientId != paramData[0] || expires != paramData[1])
  120. throw UserFriendlyException.SameMessage("参数不合法");
  121. if (long.Parse(paramData[1]) < ((long)(DateTime.Now.ToUniversalTime() - new DateTime(1970, 1, 1, 0, 0, 0)).TotalSeconds))
  122. throw UserFriendlyException.SameMessage("链接已过期");
  123. var fileMetadata = await _fileMetadataRepository.GetAsync(x => x.Id == id && x.Client == clientId);
  124. if (fileMetadata == null)
  125. throw UserFriendlyException.SameMessage("无权限访问");
  126. return GetFullPath(fileMetadata.Path);
  127. }
  128. throw UserFriendlyException.SameMessage("无权限访问");
  129. }
  130. public async Task<string> GetFilePathIndefinitely(string id, string expires, string clientId, string signature)
  131. {
  132. string decryptText = DESExtensions.Decrypt(signature);
  133. if (!string.IsNullOrEmpty(decryptText))
  134. {
  135. string[] paramData = decryptText.Split('|');
  136. if (id != paramData[2] || clientId != paramData[0] || expires != paramData[1])
  137. throw UserFriendlyException.SameMessage("参数不合法");
  138. var fileMetadata = await _fileMetadataRepository.GetAsync(x => x.Id == id && x.Client == clientId);
  139. if (fileMetadata == null)
  140. throw UserFriendlyException.SameMessage("无权限访问");
  141. return GetFullPath(fileMetadata.Path);
  142. }
  143. throw UserFriendlyException.SameMessage("无权限访问");
  144. }
  145. private string TaskGetFileContentTypeAsync(string fileName)
  146. {
  147. string suffix = Path.GetExtension(fileName);
  148. var provider = new FileExtensionContentTypeProvider();
  149. var contentType = provider.Mappings[suffix];
  150. return contentType;
  151. }
  152. private string UploadLoca(string fileName, long length, string extraInfo, Stream fileData, string client, bool? isVerification)
  153. {
  154. var settings = _fileUploadOptions.Value.Local;
  155. string groupDir = "";
  156. if (settings != null)
  157. {
  158. groupDir = settings.Path;
  159. }
  160. if (string.IsNullOrEmpty(groupDir))
  161. {
  162. groupDir = "uploads";
  163. }
  164. string sub = DateTime.Now.ToString("yyyyMMdd");
  165. groupDir = Path.Combine(groupDir, client, sub);
  166. string pathHeader = groupDir;
  167. string fulldir = GetFullPath(pathHeader);
  168. _logger.LogInformation("路径:"+fulldir);
  169. if (!Directory.Exists(fulldir))
  170. {
  171. Directory.CreateDirectory(fulldir);
  172. }
  173. _logger.LogInformation("已执行");
  174. var ext = string.Empty;
  175. if (!string.IsNullOrEmpty(fileName))
  176. {
  177. var dotPos = fileName.LastIndexOf('.');
  178. if (dotPos == 0)
  179. {
  180. throw UserFriendlyException.SameMessage("文件没有格式,请重新上传文件");
  181. }
  182. ext = fileName.Substring(dotPos + 1);
  183. }
  184. if (isVerification.HasValue && isVerification == true)
  185. {
  186. //TODO验证文件格式
  187. var extList = new List<string>();
  188. extList.Add("txt");
  189. extList.Add("xls");
  190. extList.Add("xlsx");
  191. extList.Add("jpg");
  192. extList.Add("jpeg");
  193. extList.Add("png");
  194. extList.Add("doc");
  195. extList.Add("docx");
  196. extList.Add("rar");
  197. extList.Add("pdf");
  198. extList.Add("mp3");
  199. extList.Add("zip");
  200. extList.Add("wmv");
  201. extList.Add("mp4");
  202. extList.Add("svg");
  203. extList.Add("avi");
  204. //extList.Add("m4a");
  205. if (!extList.Contains(ext))
  206. {
  207. // throw UserFriendlyException.SameMessage("文件格式不正确,只能上传【doc,rar,jpg,pdf,mp3,xls,xlsx,zip,docx,wmv,mp4.png,svg,avijpeg.m4a.txt】格式文件");
  208. throw UserFriendlyException.SameMessage("文件格式不正确,只能上传【doc,rar,jpg,pdf,mp3,xls,xlsx,zip,docx,wmv,mp4.png,svg,avi,jpeg,txt】格式文件");
  209. }
  210. }
  211. var filename = $"{Guid.NewGuid().ToString().Replace("-", string.Empty)}.{ext}";
  212. var fullPath = Path.Combine(fulldir, filename);
  213. using (var fileStream = File.Create(fullPath))
  214. {
  215. fileData.CopyTo(fileStream);
  216. }
  217. fileData.Dispose();
  218. return (Path.Combine(pathHeader, filename));
  219. }
  220. private string GetFullPath(string path)
  221. {
  222. string rv = "";
  223. if (path.StartsWith("."))
  224. {
  225. rv = Path.Combine(Directory.GetCurrentDirectory(), path);
  226. }
  227. else
  228. {
  229. rv = path;
  230. }
  231. rv = Path.GetFullPath(rv);
  232. return rv;
  233. }
  234. }