Detect MIME type of uploaded file in Ruby

Ruby on-RailsRubyFile UploadSwfupload

Ruby on-Rails Problem Overview


Is there a bullet proof way to detect MIME type of uploaded file in Ruby or Ruby on Rails? I'm uploading JPEGs and PNGs using SWFupload and content_type is always "application/octet-stream"

Ruby on-Rails Solutions


Solution 1 - Ruby on-Rails

The ruby-filemagic gem will do it:

require 'filemagic'

puts FileMagic.new(FileMagic::MAGIC_MIME).file(__FILE__)
# => text/x-ruby; charset=us-ascii

This gem does not look at the file extension at all. It reads a bit of the file contents and uses that to guess the file's type.

Solution 2 - Ruby on-Rails

In Ruby on Rails you can do:

MIME::Types.type_for("filename.gif").first.content_type # => "image/gif"

Solution 3 - Ruby on-Rails

You can use this reliable method base on the magic header of the file :

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

Solution 4 - Ruby on-Rails

The ruby-filemagic gem is good solution, but requires additional dependencies on libmagic (recently removed from CarrierWave as part of CarrierWave::MagicMimeTypes removal).

If you're interested in a pure ruby implementation, consider the MimeMagic gem! It works well for file types listed in the freedesktop.org mime database:

require 'mimemagic'

MimeMagic.by_magic(File.open('Table-Flip-Guy.jpg')).type # => "image/jpeg" 

For Microsoft Office 2007+ formats (xlsx, docx, and pptx), require the overlay (unless you're okay with the generic "application/zip" MIME type for these files)

require 'mimemagic'    
require 'mimemagic/overlay'

MimeMagic.by_magic(File.open('big_spreadsheet.xlsx')).type # => "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" 

Solution 5 - Ruby on-Rails

filemagic gem is good solution but depends lots of unnecessary gems. (rails, aws-sdk-core, ...)

If your app is small and only runs in Linux or OSX, consider to use file program:

require 'shellwords'
mimetype = `file --brief --mime-type - < #{Shellwords.shellescape(__FILE__)}`.strip

Note: Replace __FILE__ with any expr contains the filepath.

Solution 6 - Ruby on-Rails

mimemagic gem will also do it

https://github.com/minad/mimemagic

from the oficial documentation

> MimeMagic is a library to detect the mime type of a file by extension > or by content. It uses the mime database provided by freedesktop.org > (see http://freedesktop.org/wiki/Software/shared-mime-info/). > > require 'mimemagic' > MimeMagic.by_extension('html').text? > MimeMagic.by_extension('.html').child_of? 'text/plain' > MimeMagic.by_path('filename.txt') > MimeMagic.by_magic(File.open('test.html')) > # etc...

Solution 7 - Ruby on-Rails

As of 2021, I would claim that the best tool to compute mime types based on all the available hints (magic number, file name when the magic number does not suffice, user hints) is Marcel.

To shamelessly quote the documentation itself:

Marcel::MimeType.for Pathname.new("example.gif")
#  => "image/gif"

File.open "example.gif" do |file|
  Marcel::MimeType.for file
end
#  => "image/gif"

Marcel::MimeType.for Pathname.new("unrecognisable-data"), name: "example.pdf"
#  => "application/pdf"

Marcel::MimeType.for extension: ".pdf"
#  => "application/pdf"

Marcel::MimeType.for Pathname.new("unrecognisable-data"), name: "example", declared_type: "image/png"
#  => "image/png"

Marcel::MimeType.for StringIO.new(File.read "unrecognisable-data")
#  => "application/octet-stream"

Solution 8 - Ruby on-Rails

in case you are doing this from scratch, install mimemagic gem

gem 'mimemagic'

open stream(bytes of target image)

url="https://i.ebayimg.com/images/g/rbIAAOSwojpgyQz1/s-l500.jpg"
result = URI.parse(url).open

then check data-stream's file type for example:

MimeMagic.by_magic(result).type == "image/jpeg"

even though as mentioned above

%w(JPEG GIF TIFF PNG).include?(MimeMagic.by_magic(result).type)

this might be more elegant

Solution 9 - Ruby on-Rails

You can use

Mime::Type.lookup_by_extension(extention_name)

Thanks

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionVincentView Question on Stackoverflow
Solution 1 - Ruby on-RailsWayne ConradView Answer on Stackoverflow
Solution 2 - Ruby on-RailsNARKOZView Answer on Stackoverflow
Solution 3 - Ruby on-RailsAlain BeauvoisView Answer on Stackoverflow
Solution 4 - Ruby on-RailsMarcView Answer on Stackoverflow
Solution 5 - Ruby on-RailskaorukoboView Answer on Stackoverflow
Solution 6 - Ruby on-RailsprikiView Answer on Stackoverflow
Solution 7 - Ruby on-RailsakimView Answer on Stackoverflow
Solution 8 - Ruby on-Railsd1jhoni1bView Answer on Stackoverflow
Solution 9 - Ruby on-RailsSivaView Answer on Stackoverflow