2009-10-31 11 views

risposta

9

Non sicuro, ma forse dovresti investigare su magic numbers.

Aggiornamento: Leggendo a riguardo, non penso che sia molto affidabile.

+1

'FindMimeData' non rileva nemmeno qualcosa di fondamentale come' audio/mp3', quindi i numeri magici sono l'unica opzione se stai rilevando qualcosa al di fuori di questi 26 tipi. Puoi approfondire perché pensi che sia inaffidabile? – Mrchief

8

Non è possibile conoscerlo dal flusso di byte, ma è possibile memorizzare il tipo MIME quando si popola inizialmente lo byte[].

+3

In generale , non puoi Tuttavia, è possibile utilizzare l'euristica per verificare i numeri magici e indovinare il tipo di contenuto con una buona probabilità (come fa il comando 'file' in UNIX). Puoi controllare la sua fonte. –

+0

come posso farlo, Randolph? – AndreMiranda

+0

Puoi simulare il contenuto con System.Net.Mail's ContentType, convertendo il tuo file caricato in un allegato (non difficile da fare), oppure puoi provare l'hacking URLMON.DLL da questa domanda: http://stackoverflow.com/questions/58510/in-c-how-can-you-find-the-mime-type-of-a-file-based-on-the-file-signature-not-th –

7

Risposta breve: non si può

Più rispondere: Di solito, i programmi di utilizzare l'estensione file per sapere che tipo di file con cui hanno a che fare. Se non hai questa estensione, puoi solo fare supposizioni ... per esempio, puoi guardare i primi pochi byte e controllare se riconosci un'intestazione ben nota (tag di dichiarazione XML per esempio o intestazione bitmap o JPEG). Ma alla fine sarà sempre una supposizione: senza alcuni metadati o informazioni sul contenuto, una serie di byte non ha senso ...

+0

Un buon esempio potrebbe essere costituito da tutti i tipi di file che avvolge i file zip/cab (cioè, .docx). Presumibilmente, se sono in grado di modificare semplicemente l'estensione e aprire il file con un altro programma, i "numeri magici" per i byte del file sottostante sarebbero gli stessi, portando così all'ambiguità. – JoeBrockhaus

1

Non si vuole fare così. Chiama Path.GetExtension quando il file viene caricato e passa l'estensione intorno con il byte [].

+0

come posso farlo? – AndreMiranda

+2

Come verificare che l'estensione sia presente nel file stesso? vale a dire. un PDF memorizzato come JPG – user3308043

2

Mi ricorda di tornare indietro nel giorno in cui, ehm, "alcune persone" erano solite condividere file 50MB rar nei primi siti di hosting gratuito di immagini, aggiungendo semplicemente l'estensione .gif al nome file .rar.

Chiaramente se si è di fronte pubblico e ci si aspetta un determinato tipo di file, e si deve essere sicuri che sia quel tipo di file, allora non ci si può semplicemente fidare dell'estensione.

D'altra parte, se la tua app non avrebbe motivo di diffidare dell'estensione caricata e/o del tipo MIME, basta ottenere quelli quando il file viene caricato come le risposte che hai ricevuto da @rossfabircant e @RandolphPotter. crea un tipo che ha il byte [], così come l'estensione o il mimetype originale e passa in giro.

Se è necessario verificare che il file sia effettivamente un tipo previsto come un file .jpeg o .png valido, provare a interpretare il file come tali e vedere se si apre correttamente. (System.Drawing.Imaging.ImageFormat)

Se si sta tentando di classificare il file solo dai contenuti binari e potrebbe essere qualsiasi formato nell'intero mondo, questo è davvero un problema difficile e aperto e non esiste un modo affidabile al 100% per farlo. Potresti invocare TrID contro di esso, e ci sono probabilmente strumenti forensi simili usati dagli investigatori delle forze dell'ordine se puoi trovarli (e permetterteli).

Se non devi farlo nel modo più difficile, non farlo.

+0

Ottima risposta per casi limite. – user3308043

18

Come accennato, la magia MIME è l'unico modo per farlo. Molte piattaforme forniscono file e codici magici MIME aggiornati e robusti per farlo in modo efficiente. L'unico modo per farlo in .NET senza alcun codice di terze parti è utilizzare da urlmon.dll. Ecco come:

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; 
    } 
} 

Questo utilizza il rilevatore MIME di Internet Explorer. Questo è lo stesso codice utilizzato da IE per inviare un tipo MIME insieme ai file caricati.Puoi vedere lo list of MIME types supported by urlmon.dll. Una cosa a cui fare attenzione è image/pjpeg e image/x-png che non sono standard. Nel mio codice li sostituisco con image/jpeg e image/png.

+0

La dichiarazione del metodo extern sembra essere sbagliata. Qualcuno ha scritto a questo proposito qui: http://webandlife.blogspot.com/2012/11/google-is-your-alcoholic-friend.html – SandRock

+3

Divertente come il suo codice prima del refactoring è esattamente lo stesso di dopo il refactoring. Non promette nulla di buono da parte di qualcuno che fa notare errori agli altri, ma a quanto pare non può gestire la copia/incolla da solo. Ti piace la sua credibilità non è vero? :) – Mrchief

+0

@Mrchielf: Non è la stessa cosa. La prima differenza che ho trovato è stata la modifica di 'uint' in' IntPtr'. Il che ha senso, perché il post era specificamente sull'argomento di corrispondenza tra i tipi di dati C e C#. –

0

Se si dispone di un numero limitato di tipi di file previsti che si desidera supportare, i numeri magici possono essere la soluzione.

Un modo semplice per controllare è aprire solo file di esempio con un editor di testo/hex e studiare i byte iniziali per vedere se c'è qualcosa che è possibile utilizzare per differenziare/eliminare i file dal set supportato.

Se, al contrario, si sta cercando di riconoscere qualsiasi tipo di file arbitrario, sì, come tutti hanno già affermato, difficile.

0

Se sai che è un System.Drawing.Image, si può fare:

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; 
    } 
} 
Problemi correlati