8

Using ICSharpCode.SharpZipLib for C#, how can I validate that the file being passed is actually a valid zip file (not something that has been right clicked and renamed as .zip)?

[HttpPost]
        public ActionResult Upload(HttpPostedFileBase fileData)
        {
                if (fileData != null && fileData.ContentLength > 0)
                {
                    if (Path.GetExtension(fileData.FileName) == ".zip")
                    {
                        var zipFile = Server.MapPath("~/Content/uploads/" + Path.GetFileName(fileData.FileName));
                        fileData.SaveAs(zipFile);

                        FileStream fs = System.IO.File.OpenRead(zipFile);
                        ZipFile zf = new ZipFile(fs);

                        foreach (ZipEntry zipEntry in zf)
                        {
                            if (zipEntry.Name.EndsWith(".htm") || zipEntry.Name.EndsWith(".html"))
                            {
                                 return Json(new { success = true });                             
                            }
                        }
                        fs.Close();
                        fs.Dispose();
                        System.IO.File.Delete(zipFile);
                    }
                    else
                    {
                        var fileName = Server.MapPath("~/Content/uploads/" + Path.GetFileName(fileData.FileName));
                        fileData.SaveAs(fileName);                           
                        return Json(new { success = true });
                    }
                }                    
                return Json(new { success = false });

    }
McNeight
  • 21
  • 3
GoldenUser
  • 365
  • 3
  • 6
  • 21

2 Answers2

17

You can use the ZipFile.TestArchive method. Here is how it is declared in SharpZipLib:

/// <summary>
/// Test an archive for integrity/validity
/// </summary>
/// <param name="testData">Perform low level data Crc check</param>
/// <returns>true if all tests pass, false otherwise</returns>
/// <remarks>Testing will terminate on the first error found.</remarks>
public bool TestArchive(bool testData)
{
    return TestArchive(testData, TestStrategy.FindFirstError, null);
}

Usage example:

ZipFile zipFile = new ZipFile("archive.zip");
Console.WriteLine("Archive validation result: {0}", zipFile.TestArchive(true));
Yuriy Guts
  • 2,180
  • 1
  • 14
  • 18
  • Thanks, that's really clean and helpful answer! – Roee Gavirel Jun 16 '14 at 14:27
  • does this verify the entire archive? I have a ~1GB password protected zip file that I am able to enumerate through its entries but when I perform the extraction it crashes at ~56%. Can I just test it before beginning to extract it? – Adi Jan 20 '17 at 20:05
  • Does this also check for Zip Bombs. Means the reported size of the packed file is not the same size when you unzip the file. – rudimenter Jan 31 '20 at 15:58
  • Sorry to revive this, but the example you gave fails at the `new ZipFile()` call if the file isn't a valid archive (for example a .txt file renamed to .zip, similar to what OP specified). It throws an exception with the message `Cannot find central directory`. – Oscar Anthony Apr 09 '21 at 17:13
0

Be careful with this one. It created an IOAccess error on the file for me when I immediately attempted to rename, I had to add a using statement:

public static bool ValidateZipFile(string fileToTest)
{
    bool result;
    //Added using statement to fix IOAccess Blocking
    using (ICSharpCode.SharpZipLib.Zip.ZipFile zip = new ICSharpCode.SharpZipLib.Zip.ZipFile(fileToTest))
    {
        result = zip.TestArchive(true, TestStrategy.FindFirstError, null);
    }
    return result;
}
MikeP.
  • 31
  • 3
  • 1
    If I use the code exactly like this in SharpZipLib 0.86.0, I get a ````ZipException```` ("Cannot find central directory") thrown in the ZipFile constructor, because the constructor already tries to access the ZIP file. However, you can not use TestArchive without creating an instance. – Niklas Peter Sep 09 '16 at 08:36