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"
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.
FileMagic.new(FileMagic::MAGIC_MIME).file(URI.parse('https://d2qh54gyqi6t5f.cloudfront.net/boat_images/1/1813/1813941/2979796L.jpg').open.path) #=> "application/octet-stream; charset=binary"
but IO.read(URI.parse('https://d2qh54gyqi6t5f.cloudfront.net/boat_images/1/1813/1813941/2979796L.jpg').open.path, 10) =~ /^#{Regexp.new("\xff\xd8\xff\xe0\x00\x10JFIF".force_encoding('binary'))}/ #=> 0
so I use it after @alain-beauvois header file checks –
Whithersoever dnf install file-devel
for gem "ruby-filemagic"
to compile –
Gasket NameError (uninitialized constant Refile::Rails)
. –
Kung In Ruby on Rails you can do:
MIME::Types.type_for("filename.gif").first.content_type # => "image/gif"
mime-types
–
Paean mime-types
gem which is used by RoR, but on itself is a lightweight gem. –
Ostosis 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
local_file_path
could be set to ;rm -rf .
. In this particular case the method would safely fail with Errno::ENOENT
without wiping the current directory, but you better don't rely on that when the file name is provided by a user. –
Euhemerism file
is not guaranteed to be installed on every Linux distribution. For example it is not in docker://ubuntu:latest. Look before you leap. –
Illailladvised 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"
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"
foo.txt
containing ASCII hello world
as being application/octet-stream
. ?!? –
Maser 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.
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...
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
You can use
Mime::Type.lookup_by_extension(extention_name)
Thanks
© 2022 - 2024 — McMap. All rights reserved.
brew install libmagic
beforegem install ruby-filemagic
would work. But the gem works like a charm for image/png, image/jpg, application/x-shockwave-flash, video/mp4, application/ogg, image/vnd.adobe.photoshop, application/pdf, video/x-ms-asf, etc. – Statics