本文由網友投稿。
作者:江湖人士
原文標題:2022年底C# 解壓zip文件遇到的一個bug
原文鏈接:https://jhrs.com/2022/46060.html
最近在排查一個上傳功能時,客戶端上傳的是zip文件,到服務器端后使用C# 解壓zip文件的代碼將上傳文件解壓后驗證是否是允許上傳的文件類型,并且要驗證亂改文件后綴啊,文件頭什么的都要走一遭,結果解壓zip文件時就出妖蛾子了。
C# 解壓zip文件
先說一下前文(或者上下文),在IIS上部署了一個文件服務站點,用于上傳各類文件,流程上是先上傳到站點根目錄里面隨機創建的一個臨時目錄(這里采用偷懶方案,直接使用guid做為目錄名創建),先通過文件驗證后再將其通過代碼剪切或者復制到正式存檔目錄,C# 復制或者移動文件[1]的代碼可以參考江湖人士[2]網的這篇文章。昨天快下班時發現上傳zip文件時報錯,在文件服務根站點創建了很多很多的guid開頭的目錄,我的妹呀,這下玩犢子了,事出反常必有妖啊,肯定代碼出錯了。

有bug的解壓代碼
這都馬上2022年底了,出了這bug后,趕緊搭建個模擬環境跑一下,發現如下原來的代碼確實有問題,原始代碼如下:
///?<summary>
///?解壓文件
///?</summary>
///?<param?name="saveDir">保存目錄</param>
///?<param?name="stream"></param>
public?static?void?UnZipFiles(string?saveDir,?Stream?stream)
{using?(ZipInputStream?s?=?new?ZipInputStream(stream)){ZipEntry?theEntry;while?((theEntry?=?s.GetNextEntry())?!=?null){string?directoryName?=?$"{saveDir}{Path.GetDirectoryName(theEntry.Name)}\\";string?fileName?=?Path.GetFileName(theEntry.Name);Directory.CreateDirectory(directoryName);using?(FileStream?streamWriter?=?File.Create(directoryName?+?fileName)){byte[]?data?=?new?byte[2048];while?(true){int?size?=?s.Read(data,?0,?data.Length);if?(size?>?0){streamWriter.Write(data,?0,?size);}else{break;}}}}}
}
對了,這里需要說明一下,這是以前的老項目,因此壓縮,解壓使用了 ICSharpCode.SharpZipLib.Zip
這個組件。
當打開源碼來看,一眼就發現了問題所在,邏輯不嚴謹導致,解壓文件保存目錄直接拼接。
如何修復此bug?
知道了問題所在,修復自然簡單,調用Path.Combine[3]方法即可,解壓時再判斷一下是目錄還是文件即可,最終修復后的代碼如下:
///?<summary>
///?解壓文件
///?</summary>
///?<param?name="saveDir">保存目錄</param>
///?<param?name="stream"></param>
public?static?void?UnZipFiles(string?saveDir,?Stream?stream)
{using?(ZipInputStream?s?=?new?ZipInputStream(stream)){ZipEntry?theEntry;string?directoryName,?file,?fileName;while?((theEntry?=?s.GetNextEntry())?!=?null){directoryName?=?Path.Combine(saveDir,?Path.GetDirectoryName(theEntry.Name));fileName?=?Path.GetFileName(theEntry.Name);Directory.CreateDirectory(directoryName);file?=?Path.Combine(directoryName,?fileName);if?(theEntry.IsFile){using?(FileStream?streamWriter?=?File.Create(file)){byte[]?data?=?new?byte[2048];while?(true){int?size?=?s.Read(data,?0,?data.Length);if?(size?>?0){streamWriter.Write(data,?0,?size);}else{break;}}}}}}
}
參考資料
[1]
C# 復制或者移動文件: https://jhrs.com/2022/45307.html
[2]江湖人士: https://jhrs.com/
[3]Path.Combine: https://learn.microsoft.com/zh-cn/dotnet/api/system.io.path.combine?view=net-7.0