/// <summary> /// 保存上传文件到磁盘目录(此方法在http_service_handler的Upload中在文件类型校验合法后被调用) /// </summary> /// <param name="param">上传参数配置</param> /// <param name="fileHash">上传文件的物理路径Hashtable</param> internal static void SaveToDisk(UploadParameter param, System.Collections.Hashtable fileHash) { int cur_build = 0; // 创建文件保存路径次数 string _filePath = string.Empty; if (!Directory.Exists(param.SaveToDir)) { if (!param.AutoMKDir) throw new APIFW_ArgumentException(" 上传目录不存在,请手动创建目录或将AutoMKDir参数设置为True "); fileHash.Add(-1, Directory.CreateDirectory(param.SaveToDir).FullName); } int size = 0; long completed = 0; byte[] buffer = new byte[param.BufferSize]; for (int i = 0; i < param.FileUploads.Length; i++) { cur_build = 0; // 上传文件名称重命名计数 completed = 0; // 当前上传文件已保存大小 AdjustUploadItemFileName(param, ref param.FileUploads[i], ref cur_build, ref _filePath); if (param.FileUploads[i].IsValid && param.FileUploads[i].FileName != null && param.FileUploads[i].ContentLength > 0 && param.FileUploads[i].FileName.Length > 0) { try { // 开始上传 param.ExcuteOnUploadItemStart(param.FileUploads[i]); // request.Files.Get(param.FileUploads[i].ClientKey).SaveAs(_filePath); using (FileStream fs = new FileStream(_filePath, FileMode.Create, FileAccess.ReadWrite)) { using (BinaryWriter bw = new BinaryWriter(fs)) { using (BinaryReader br = new BinaryReader(param.FileUploads[i].InputStream)) { while ((size = br.Read(buffer, 0, buffer.Length)) > 0) { completed += size; bw.Write(buffer, 0, size); // 进度变化 param.ExcuteOnUploadItemProgressChange(param.FileUploads[i], completed); } } } } // 上传完成 param.ExcuteOnUploadItemCompleted(param.FileUploads[i]); } catch (Exception ex) { // 上传出错 if (!param.ExcuteOnUploadItemFailedHandler(param.FileUploads[i], ex)) { throw ex; } } } } }
protected override void Upload(UploadParameter arg) { arg.UnBindEvent(); // 添加 或者 // 删除自定义允许上传文件类型 //arg.UnOrAllowTypes.Add("chm"); //arg.UnOrAllowTypes.Add("ini"); //arg.UnOrAllowTypes.Add("css"); // 重命名上传文件保存名称 //foreach (UploadItem item in arg.FileUploads) //{ // item.FileName = Guid.NewGuid() + "." + item.FileSuffix; //} // 上传文件类型 arg.FileTypes.Clear(); arg.FileTypes.Add("exe"); // 禁止上传 exe arg.TypeValidMode = FileUploadTypeValidMode.UnAllowType; // 上传事件订阅 arg.OnUploadItemStart += Arg_OnUploadItemStart; arg.OnUploadItemCompleted += Arg_OnUploadItemCompleted; arg.OnUploadItemValidFailed += Arg_OnUploadItemValidFailed; arg.OnUploadItemFailedHandler += Arg_OnUploadItemFailedHandler; arg.OnUploadItemProgressChange += Arg_OnUploadItemProgressChange; // 解除绑定事件委托函数列表 // arg.UnBindEvent(); base.Upload(arg); }
/// <summary> /// 对已经上传的文件进行调整管理(删除。保留),当上传失败,发生异常的时候调用此方法 /// </summary> /// <param name="arg">上传配置参数</param> /// <param name="_fileHash">已经上传的文件名hash表</param> internal static void DoTranstion(UploadParameter arg, Hashtable _fileHash) { if (arg.IsUseTranstion) { // 删除已经上传文件 for (int i = 0; i < _fileHash.Count; i++) { try { File.Delete(_fileHash[i].ToString()); } catch { } } // 删除本次创建的目录 try { if (_fileHash.ContainsKey(-1)) { // 防止误删(因为可能同时有多个用户上传文件,并且上传到同一个 // 目录中,A成功,B失败,目录是B创建的,这里就不能这样删了,尽管会提示不可以删除非空目录) if (Directory.GetFiles(_fileHash[-1].ToString()).Length == 0) { File.Delete(_fileHash[-1].ToString()); } } } catch { } } }
/// <summary> /// 创建上传文件的配置参数对象 /// </summary> /// <param name="request">HttpRequest</param> /// <param name="server">HttpServerUtility</param> /// <returns></returns> internal static UploadParameter BuildUploadParameter(HttpRequest request, HttpServerUtility server) { long totalSize = 0; List<UploadItem> uploadItems = new List<UploadItem>(); for (int i = 0; i < request.Files.Count; i++) { if (request.Files[i].ContentLength > 0) { totalSize += request.Files[i].ContentLength; uploadItems.Add( new UploadItem( request.Files.AllKeys[i], request.Files[i].FileName, request.Files[i].ContentType, request.Files[i].ContentLength, request.Files[i].InputStream )); } } // 参数配置 UploadParameter uploadParam = new UploadParameter(uploadItems.ToArray(), server.MapPath("~/App_Data/Upload/" + DateTime.Now.ToString("yyyyMMddHH") + "/"), totalSize); // 上传事件 uploadParam.OnUploadItemStart += UploadParam_OnUploadItemStart; uploadParam.OnUploadItemCompleted += upload_OnUploadItemCompleted; uploadParam.OnUploadItemFailedHandler += upload_OnUploadItemFailedHandler; uploadParam.OnUploadItemProgressChange += upload_OnUploadItemProgressChange; uploadParam.OnUploadItemValidFailed += UploadParam_OnUploadItemValidFailed; return uploadParam; }
/// <summary> /// 验证文件类型是否无效(当文件类型与参数fileSuffix一样时,表示有效) /// 如果当文件类型与参数fileSuffix不一样时,通过调用 uploadParam.ExcuteOnUploadItemValidFailed来确定文件是否有效 /// </summary> /// <returns></returns> private static bool IsinValidFileTypeWhenNotEqual(UploadParameter uploadParam, UploadItem uploadItem, string fileSuffix) { if (fileSuffix.Equals( uploadItem.FileSuffix, StringComparison.OrdinalIgnoreCase)) { return !(uploadItem.IsValid = true); } uploadItem.IsValid = false; uploadItem.InValidMessages.Add(" 文件 [" + uploadItem.FileName + "] 上传类型验证无效 "); // 调用ExcuteOnUploadItemValidFailed进行(如果返回false,表示不允许忽略错误,禁止继续上传文件) return !(uploadItem.IsValid = uploadParam.ExcuteOnUploadItemValidFailed(uploadItem, FileUploadTypeValidOption.FileType)); }
/// <summary> /// 尝试对长传文件进行保存路径与文件名称调整(该方法可能会递归调用自己,但不会出现死循环 /// 有最大次数限制,如果达到最大调整次数还没有成功,会抛出 APIFW_InvalidOperationException 异常) /// </summary> /// <param name="param">上传配置参数</param> /// <param name="item">当前执行上传文件对象</param> /// <param name="callCount">对路径进行调整的次数</param> /// <param name="fileNewPath">文件的上传保存路径</param> private static void AdjustUploadItemFileName(UploadParameter param, ref UploadItem item, ref int callCount, ref string fileNewPath) { fileNewPath = Path.Combine(param.SaveToDir, item.FileName); if (File.Exists(fileNewPath)) { SFUEDoOption(param.FileExistDoOption, param.SaveToDir, ref item); if (callCount++ > FileUploadDefault.ReUploadItemNameMaxCount) throw new APIFW_InvalidOperationException("上传文件名称冲突,程序尝试了[" + FileUploadDefault.ReUploadItemNameMaxCount + "]次重命名任然失败,请重新尝试"); FileUploadUtility.AdjustUploadItemFileName(param, ref item, ref callCount, ref fileNewPath); } }
/// <summary> /// 判断是否上传文件的文件类型(是否存在不存在与允许上传文件类型配置项中) /// </summary> /// <param name="uploadParam">上传参数对象</param> /// <returns></returns> private static bool IsValidExistUnAllowType(UploadParameter uploadParam) { int okQu = 0; // 文件类型的验证模式为 UnAllowType,如果uploadParam.UnOrAllowTypes为null或者Count为0,表示允许所有文件类型的文件上传 if (uploadParam.TypeValidMode == httpCore.FileUploadTypeValidMode.UnAllowType) { if (uploadParam.FileTypes == null || uploadParam.FileTypes.Count == 0) { return false; } } // // 校验方式为只允许,就遍历所有的文件,只需要找到一个文件的类型不存在于UnOrAllowTypes // 上传的文件类型数组中,就说明本次上传文件中包含非法的文件类型,调用ExcuteOnUploadItemValidFailed // -------------------------------------------------------------------------------------------// if (uploadParam.TypeValidMode == httpCore.FileUploadTypeValidMode.AllowType) { for (int a = 0; a < uploadParam.FileUploads.Length; a++) { for (int b = 0; b < uploadParam.FileTypes.Count; b++) { // 此文件类型存在于UnOrAllowTypes中 // 说明它合法,break 继续下一个文件的文件类型验证 if (IsValidFileTypeWhenEqual(uploadParam, uploadParam.FileUploads[a], uploadParam.FileTypes[b])) { okQu++; break; } // 循环到最后一个了。如果最后一个文件类型都不一样,那就说明这个文件类型非法 if (b == uploadParam.FileTypes.Count - 1) { if (IsinValidFileTypeWhenNotEqual(uploadParam, uploadParam.FileUploads[a], uploadParam.FileTypes[b])) { okQu = -1; break; } } } // 找到了一个非法类型的上传文件,并且 // ExcuteOnUploadItemValidFailed方法返回False,表示不能继续上传了。 if (okQu == -1) { break; } } return uploadParam.FileUploads.Length == okQu; } // // 校验方式为不允许,就遍历所有的文件,只需要找到一个文件的类型存在于UnOrAllowTypes // 上传的文件类型数组中,就说明本次上传文件中包含不允许上传的文件类型,调用ExcuteOnUploadItemValidFailed // -------------------------------------------------------------------------------------------------------// for (int a = 0; a < uploadParam.FileUploads.Length; a++) { for (int b = 0; b < uploadParam.FileTypes.Count; b++) { if (IsinValidFileTypeWhenEqual(uploadParam, uploadParam.FileUploads[a], uploadParam.FileTypes[b])) { okQu = -1; break; } } if (okQu == -1) { return false; } } return true; }
/// <summary> /// 验证上传文件的:基础数据/验证模式与文件类型/所有文件总大小/单个文件大小 是否合法 /// </summary> /// <param name="uploadParam">上传参数对象</param> /// <returns></returns> private static bool IsValidUploadBasicData(UploadParameter uploadParam) { // 基础数据必须正确 if (uploadParam != null && uploadParam.FileUploads != null && uploadParam.FileUploads.Length > 0) { // 验证总文件大小 if (uploadParam.AllowFileSize < uploadParam.FileTotalSize) { throw new APIFW_ArgumentException("上传文件总大小超过了配置参数最大限制!"); } // 验证单个文件大小 foreach (UploadItem item in uploadParam.FileUploads) { if (uploadParam.AllowSingleFileSize < item.ContentLength) { if (!uploadParam.ExcuteOnUploadItemValidFailed(item, FileUploadTypeValidOption.FileSize)) { throw new APIFW_ArgumentException("上传文件[" + item.FileName + "]的大小超过了配置参数最大大小限制!"); } } } // 验证模式为FileUploadTypeValidMode.AllowType,必须指定。UnOrAllowTypes参数 if ((uploadParam.TypeValidMode == FileUploadTypeValidMode.AllowType)) { if (uploadParam.FileTypes == null || uploadParam.FileTypes.Count == 0) { throw new APIFW_ArgumentException("上传允许文件类型验证模式为 FileUploadTypeValidMode.AllowType,最少必须包含一项UnOrAllowTypes!"); } } return true; } throw new APIFW_ArgumentException(" 上传参数[UploadParameter]验证失败,没有任何允许上传的文件或者上传文件大小为零,请确认!"); }
/// <summary> /// 验证是否所有上传文件的文件类型,上传大小都符合 /// 上传配置参数(都满足[即可以上传]返回true,否则返回false) /// </summary> /// <param name="uploadParam">上传参数对象</param> /// <returns></returns> internal static bool IsValid(UploadParameter uploadParam) { // 验证是上传参数数据正确性 --> 验证上传文件类型的正确性 return !(FileUploadUtility.IsValidUploadBasicData(uploadParam)) ? false : FileUploadUtility.IsValidExistUnAllowType(uploadParam); }