using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.StaticFiles; using System.IO; using System.Text; namespace zero.FileStorage; public class Paths : IPaths { public string WebRoot { get; set; } public string ContentRoot { get; set; } public string SecureRoot { get; set; } public string Media { get; set; } protected IWebHostEnvironment Env { get; set; } public const string MEDIA_FOLDER = "Uploads"; public const char PATH_SEPARATOR = '/'; static char[] InvalidFilenameChars = null; const char REPLACEMENT_CHAR = '-'; FileExtensionContentTypeProvider FileExtensionContentTypeProvider { get; set; } static readonly Dictionary Replacements = new() { { 'ä', "ae" }, { 'ü', "ue" }, { 'ö', "oe" }, { 'ß', "ss" } }; public Paths(IWebHostEnvironment env) { Env = env; WebRoot = env.WebRootPath; ContentRoot = env.ContentRootPath; SecureRoot = Path.Combine(ContentRoot, "wwwroot.secure"); Media = Path.Combine(WebRoot, MEDIA_FOLDER); FileExtensionContentTypeProvider = new(); } /// /// Combine a path /// public string Combine(params string[] paths) { return Path.Combine(paths); } /// /// Map a path /// public string Map(string path) { return Path.Combine(WebRoot, path); } /// /// Map a secure path /// public string MapSecure(string path) { return Path.Combine(SecureRoot, path); } /// /// Map a path /// public string Map(params string[] paths) { return Path.Combine(WebRoot, Path.Combine(paths)); } /// /// Map a secure path /// public string MapSecure(params string[] paths) { return Path.Combine(SecureRoot, Path.Combine(paths)); } /// /// Create a directory if it does not exist yet /// public void Create(string directory) { if (!Directory.Exists(directory)) { Directory.CreateDirectory(directory); } } /// /// Get content type for a filename /// public string GetContentType(string filename, string fallback = "application/octet-stream") { if (filename == null || !FileExtensionContentTypeProvider.TryGetContentType(Path.GetFileName(filename), out string contentType)) { contentType = fallback; } return contentType; } /// /// Normalizes a filename and removes invalid chars /// public string ToFilename(string value) { if (String.IsNullOrWhiteSpace(value)) { return value; } // lowercase for string value = value.ToLower(); StringBuilder sb = new(value.Length); var invalids = InvalidFilenameChars ??= Path.GetInvalidFileNameChars(); bool changed = false; for (int i = 0; i < value.Length; i++) { char c = value[i]; if (Replacements.ContainsKey(c)) { changed = true; sb.Append(Replacements[c]); } else if (invalids.Contains(c)) { changed = true; sb.Append(REPLACEMENT_CHAR); } else { sb.Append(c); } } if (sb.Length == 0) { return "_"; } return changed ? sb.ToString() : value; } } public interface IPaths { string ContentRoot { get; set; } string WebRoot { get; set; } string SecureRoot { get; set; } string Media { get; set; } /// /// Combine a path /// string Combine(params string[] paths); /// /// Map a path /// string Map(string path); /// /// Map a secure path /// string MapSecure(string path); /// /// Map a path /// string Map(params string[] paths); /// /// Map a secure path /// string MapSecure(params string[] paths); /// /// Create a directory if it does not exist yet /// void Create(string directory); /// /// Get content type for a filename /// string GetContentType(string filename, string fallback = "application/octet-stream"); /// /// Normalizes a filename and removes invalid chars /// string ToFilename(string value); }