2009-10-31 70 views

回答

9

不確定,但也許你應該調查約magic numbers

更新: 讀了一下,我不認爲它是非常可靠的。

+1

「FindMimeData」甚至沒有檢測到像audio/mp3這樣基本的內容,所以如果您在26種以外的地方檢測到某些東西,幻數是唯一的選擇。你能否詳細說明爲什麼你認爲它不可靠? – Mrchief 2014-08-01 15:28:13

8

您不能從字節流知道,但你可以存儲MIME類型,當你開始填充byte[]

+3

一般,你不能。但是,您可以使用啓發式檢查幻數並以很好的概率猜測內容類型(如UNIX中的'file'命令)。你可以檢查它的來源。 – 2009-10-31 16:35:29

+0

Randolph,我該怎麼做? – AndreMiranda 2009-10-31 16:36:23

+0

你可以用System.Net.Mail的ContentType來僞造它,通過將你上傳的文件轉換成附件(不難做到),或者你可以從這個問題嘗試URLMON.DLL破解:http://stackoverflow.com/questions/58510/in-c-how-can-you-find-the-mime-type-of-the-file-based-on-the-file-signature-not-th – 2009-10-31 22:50:34

7

簡短的回答:你不能

較長的答案:通常情況下,程序使用的文件擴展名來知道他們正在處理的是什麼類型的文件。如果您沒有該擴展名,則只能進行猜測......例如,您可以查看前幾個字節,並檢查是否識別了一個衆所周知的標頭(例如XML聲明標籤,或位圖或JPEG標頭)。但是這將永遠是一個猜測:如果沒有一些元數據或內容信息,字節數組毫無意義...

+0

一個很好的例子可能是所有的文件類型包裹zip/cab文件(即.docx)。據推測,如果我能夠簡單地更改擴展名並用另一個程序打開文件,那麼底層文件字節的「幻數」將是相同的,因此導致含糊不清。 – JoeBrockhaus 2014-12-03 21:49:49

1

你不想這樣做。當文件上傳時調用Path.GetExtension,並將擴展名與byte []一起傳遞。

+0

我該怎麼做? – AndreMiranda 2009-10-31 16:35:28

+2

如何驗證擴展名是文件本身的內容?即。以JPG格式存儲的PDF – user3308043 2014-07-24 22:52:31

2

讓我想起那天我們回來的,呃嗯用來分享早期的免費圖片託管網站上50MB的RAR文件,只需添加.gif擴展名的文件名.rar程序「一些人」。

顯然,如果你是面向公衆的,你的期待某個文件類型,你必須確保它是文件類型,那麼你就不能只信任該擴展程序。另一方面,如果您的應用程序沒有理由不信任上傳的擴展名或MIME類型,那麼只需在上傳文件時像從@rossfabircant和@RandolphPotter收到的答案那樣獲取這些文件。創建一個具有byte []的類型,以及原始擴展名或mimetype,並傳遞該類型。

如果您需要驗證該文件實際上是有一定預期的類型像一個有效的.jpeg或.png你可以嘗試解釋文件爲這些類型,看看它是否成功打開。 (System.Drawing.Imaging.ImageFormat)

如果您試圖僅從二進制內容對文件進行分類,並且它可能是整個世界中的任何格式,那真是一個艱難的開放式問題,而且沒有100%可靠的方法來做到這一點。你可以針對它調用TrID,如果你能找到(並負擔得起),那麼執法調查人員可能會使用類似的取證工具。

如果你不必這麼做,那就不要這麼做。

+0

邊緣情況的好答案。 – user3308043 2014-07-24 22:53:21

18

如前所述,MIME魔術是實現此目的的唯一方法。許多平臺都提供最新且強大的MIME魔術文件和代碼,以便高效地完成此操作。在沒有任何第三方代碼的情況下在.NET中執行此操作的唯一方法是使用urlmon.dll中的。方法如下:

public static int MimeSampleSize = 256; 

public static string DefaultMimeType = "application/octet-stream"; 

[DllImport(@"urlmon.dll", CharSet = CharSet.Auto)] 
private extern static uint FindMimeFromData(
    uint pBC, 
    [MarshalAs(UnmanagedType.LPStr)] string pwzUrl, 
    [MarshalAs(UnmanagedType.LPArray)] byte[] pBuffer, 
    uint cbSize, 
    [MarshalAs(UnmanagedType.LPStr)] string pwzMimeProposed, 
    uint dwMimeFlags, 
    out uint ppwzMimeOut, 
    uint dwReserverd 
); 

public static string GetMimeFromBytes(byte[] data) { 
    try { 
     uint mimeType; 
     FindMimeFromData(0, null, data, (uint)MimeSampleSize, null, 0, out mimeType, 0); 

     var mimePointer = new IntPtr(mimeType); 
     var mime = Marshal.PtrToStringUni(mimePointer); 
     Marshal.FreeCoTaskMem(mimePointer); 

     return mime ?? DefaultMimeType; 
    } 
    catch { 
     return DefaultMimeType; 
    } 
} 

這使用Internet Explorer MIME檢測器。這是IE用來發送MIME類型和上傳文件的相同代碼。你可以看到list of MIME types supported by urlmon.dll。有一點需要注意的是非標準的image/pjpegimage/x-png。在我的代碼中,我將它們替換爲image/jpegimage/png

+0

你extern方法聲明好像是錯的。有人在此處撰寫了這篇文章:http://webandlife.blogspot.com/2012/11/google-is-your-alcoholic-friend.html – SandRock 2013-07-21 22:56:15

+3

有趣的是,他在重構之前的代碼與重構之後的代碼完全相同。對於指出別人錯誤的人來說,這並不好,但顯然不能自己處理複製/粘貼。有點辜負他的信譽不是嗎? :) – Mrchief 2014-08-01 14:59:27

+0

@Mrlflf:這是不一樣的。我發現的第一個區別是將'uint'更改爲'IntPtr'。這是有道理的,因爲這篇文章是專門討論匹配C和C#數據類型的主題。 – 2017-12-08 19:26:22

0

如果您想要支持的預期文件類型數量有限,可以使用幻數。

一個簡單的檢查方法是使用文本/十六進制編輯器打開示例文件,並研究前導字節以查看是否有可用於區分/丟棄支持集中的文件的文件。

另一方面,如果您希望識別任何任意文件類型,是的,正如大家已經說過的那樣,強硬。

0

如果你知道這是一個System.Drawing.Image,你可以這樣做:

public static string GeMimeTypeFromImageByteArray(byte[] byteArray) 
{ 
    using (MemoryStream stream = new MemoryStream(byteArray)) 
    using (Image image = Image.FromStream(stream)) 
    { 
     return ImageCodecInfo.GetImageEncoders().First(codec => codec.FormatID == image.RawFormat.Guid).MimeType; 
    } 
} 
相關問題