Bestimmen Sie den Dateityp in Ruby

74

Wie bestimmt man zuverlässig den Dateityp? Eine Analyse der Dateierweiterung ist nicht akzeptabel. Es muss ein rubyeskes Tool geben, das dem Befehl UNIX file (1) ähnelt.

Dies betrifft MIME oder den Inhaltstyp, nicht Dateisystemklassifizierungen wie Verzeichnis, Datei oder Socket.


quelle

Antworten:

58

Es gibt eine Rubinbindung, die genau libmagicdas tut, was Sie brauchen. Es ist als Edelstein namens Ruby-Filemagic erhältlich :

gem install ruby-filemagic

Benötigen libmagic-dev.

Die Dokumentation scheint etwas dünn zu sein, aber dies sollte Ihnen den Einstieg erleichtern:

$ irb 
irb(main):001:0> require 'filemagic' 
=> true
irb(main):002:0> fm = FileMagic.new
=> #<FileMagic:0x7fd4afb0>
irb(main):003:0> fm.file('foo.zip') 
=> "Zip archive data, at least v2.0 to extract"
irb(main):004:0> 
Martin Carpenter
quelle
Laut grub.ath.cx/filemagic/CHANGELOG scheint dieses Juwel nicht aktiv gepflegt zu werden.
Lars Haugseth
23
Ich freue mich, berichten zu können, dass dieses Juwel wieder aktiv gepflegt wird. Github.com/blackwinter/ruby-filemagic
Martin Carpenter
Funktioniert auch unter Windows.
Chris Finne
3
Auch dieses Juwel scheint nicht aktiv gepflegt zu werden. Es ist auf Github mit "nicht gepflegt" und "adoptiere mich" markiert .
Tanius
35

Wenn Sie sich auf einem Unix-Computer befinden, versuchen Sie Folgendes:

mimetype = `file -Ib #{path}`.gsub(/\n/,"")

Mir sind keine reinen Ruby-Lösungen bekannt, die so zuverlässig funktionieren wie "Datei".

Bearbeitet, um hinzuzufügen: Je nachdem, welches Betriebssystem Sie ausführen, müssen Sie möglicherweise 'i' anstelle von 'I' verwenden, damit die Datei einen MIME-Typ zurückgibt.

Patrick Ritchie
quelle
18
Versuchen Sie, popen zu verwenden, um böse Hackery zu verhindern:IO.popen(["file", "--brief", "--mime-type", path], in: :close, err: :close).read.chomp
sj26
Ja, das oder das cocaineJuwel.
Maletor
8
@ sj26 Jedes Mal popen, wenn ich anrufe , erhalte ich einen Zombie-Prozess, da das E / A-Objekt nicht geschlossen ist. Um das zu beheben, verwenden Sie einen Block:IO.popen(["file", "--brief", "--mime-type", path], in: :close, err: :close) { |io| io.read.chomp }
Andrew
1
@Pete Das Interpolieren potenziell vom Benutzer bereitgestellter Inhalte in eine Befehlszeichenfolge wie Backticks ist eine potenzielle Sicherheitslücke. Die Verwendung von popen mit einer Reihe von Argumenten verhindert diese Exploit-Kategorie. :-)
sj26
1
Hervorragender Punkt über Zombies! IO.popen(["file", "--brief", "--mime-type", path], &:read).chompfunktioniert auch.
Sj26
14

Ich fand das Beschießen am zuverlässigsten. Aus Gründen der Kompatibilität unter Mac OS X und Ubuntu Linux habe ich Folgendes verwendet:

file --mime -b myvideo.mp4
Video / mp4; Zeichensatz = binär

Ubuntu druckt auch Video-Codec-Informationen, wenn dies möglich ist, was ziemlich cool ist:

file -b myvideo.mp4
ISO Media, MPEG v4-System, Version 2

Jamiew
quelle
6
sollte file -b --mime-type myvideo.mp4für die Webnutzung sein
Yam Marcovic
8

Sie können diese zuverlässige Methode basierend auf dem magischen Header der Datei verwenden:

def get_image_extension(local_file_path)
  png = Regexp.new("\x89PNG".force_encoding("binary"))
  jpg = Regexp.new("\xff\xd8\xff\xe0\x00\x10JFIF".force_encoding("binary"))
  jpg2 = Regexp.new("\xff\xd8\xff\xe1(.*){2}Exif".force_encoding("binary"))
  case IO.read(local_file_path, 10)
  when /^GIF8/
    'gif'
  when /^#{png}/
    'png'
  when /^#{jpg}/
    'jpg'
  when /^#{jpg2}/
    'jpg'
  else
    mime_type = `file #{local_file_path} --mime-type`.gsub("\n", '') # Works on linux and mac
    raise UnprocessableEntity, "unknown file type" if !mime_type
    mime_type.split(':')[1].split('/')[1].gsub('x-', '').gsub(/jpeg/, 'jpg').gsub(/text/, 'txt').gsub(/x-/, '')
  end  
end
Alain Beauvois
quelle
1
Sie müssen auch nach "\ xff \ xd8 \ xff \ xdb" als JPEG-Signatur suchen.
Richard Fairhurst
6

Wenn Sie die File-Klasse verwenden, können Sie sie basierend auf der Antwort von @ PatrickRichie mit den folgenden Funktionen erweitern:

class File
    def mime_type
        `file --brief --mime-type #{self.path}`.strip
    end

    def charset
        `file --brief --mime #{self.path}`.split(';').second.split('=').second.strip
    end
end

Wenn Sie Ruby on Rails verwenden, können Sie dies in config / initializers / file.rb ablegen und im gesamten Projekt verfügbar haben.

spyle
quelle
3

Dies wurde als Kommentar zu dieser Antwort hinzugefügt , sollte aber eigentlich eine eigene Antwort sein:

path = # path to your file

IO.popen(
  ["file", "--brief", "--mime-type", path],
  in: :close, err: :close
) { |io| io.read.chomp }

Ich kann bestätigen, dass es bei mir funktioniert hat.

Jason Swett
quelle
1
Dies funktioniert perfekt mit dem zusätzlichen Bonus, dass Sie keinen weiteren Edelstein hinzufügen und pflegen müssen.
Steven Hirlston
2

Sie können Shared-Mime ausprobieren (gem install shared-mime-info). Erfordert die Verwendung der Freedesktop Shared-Mime-Info-Bibliothek, führt jedoch sowohl Dateinamen- / Erweiterungsprüfungen als auch "magische" Prüfungen durch. Ich habe gerade versucht, sie selbst zu testen, aber ich habe keine Freedesktop Shared-Mime-Informationen Datenbank installiert und muss leider "echte Arbeit" leisten, aber es könnte das sein, wonach Sie suchen.

Chris Ingrassia
quelle
2

Für diejenigen, die mit der Suchmaschine hierher gekommen sind, besteht ein moderner Ansatz, um den MimeType in reinem Rubin zu finden, darin, das mimemagische Juwel zu verwenden.

require 'mimemagic'

MimeMagic.by_magic(File.open('tux.jpg')).type # => "image/jpeg" 

Wenn Sie der Meinung sind, dass es sicher ist, nur die Dateierweiterung zu verwenden, können Sie das Juwel mime-types verwenden :

MIME::Types.type_for('tux.jpg') => [#<MIME::Type: image/jpeg>]
Paulo Fidalgo
quelle
1

Ich habe kürzlich mimetype-fu gefunden .

Es scheint die einfachste und zuverlässigste Lösung zu sein, um den MIME-Typ einer Datei zu erhalten.

Die einzige Einschränkung ist, dass auf einem Windows-Computer nur die Dateierweiterung verwendet wird, während es auf * Nix-basierten Systemen hervorragend funktioniert.

Heathderson
quelle
-1

Der Rubin Edelstein ist gut. Pantomimen für Rubin

Qianjigui
quelle
Dieses Juwel verwendet die Dateierweiterung, um den Typ und nicht den Inhalt zu bestimmen.
Lars Haugseth
-2

Sie können MIME :: Types for Ruby ausprobieren .

Diese Bibliothek ermöglicht die Identifizierung des wahrscheinlichen MIME-Inhaltstyps einer Datei. Die Identifizierung des MIME-Inhaltstyps basiert auf den Dateinamenerweiterungen einer Datei.

Bobby Jack
quelle
6
Aus Readme.txt: "Die Identifizierung des MIME-Inhaltstyps basiert auf den Dateinamenerweiterungen einer Datei." OP forderte ausdrücklich eine Methode an, die auf einer Inhaltsanalyse und nicht auf einer Dateinamenerweiterung basiert.
Martin Carpenter