【问题标题】:Detect MIME type of uploaded file in Ruby在 Ruby 中检测上传文件的 MIME 类型
【发布时间】:2011-06-03 19:04:31
【问题描述】:

在 Ruby 或 Ruby on Rails 中检测上传文件的 MIME 类型是否有防弹方法?我正在使用 SWFupload 上传 JPEG 和 PNG,content_type 始终是 "application/octet-stream"

【问题讨论】:

    标签: ruby-on-rails ruby file-upload swfupload


    【解决方案1】:

    ruby-filemagic gem 可以做到:

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

    这个 gem 根本不看文件扩展名。它读取一些文件内容并使用它来猜测文件的类型。

    【讨论】:

    • 在 OS X 上,我只需要brew install libmagicgem install ruby-filemagic 就可以工作。但是 gem 就像 image/png、image/jpg、application/x-shockwave-flash、video/mp4、application/ogg、image/vnd.adobe.photoshop、application/pdf、video/x-ms- 的魅力asf等
    • 只是为了澄清(并与@NARKOZ 的答案对比),与 rails MIME::types 选项不同,此 gem 不会查看扩展名来查找 mime 类型。
    • 我遇到 filemagic 无法识别简单图像/jpeg 的情况: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"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 所以我在检查@alain-beauvois 头文件后使用它
    • 遗憾的是,这个 gem 似乎还不能在 Rails 5 上运行 :(
    • 在 Rails 5 上为我工作,但在 Fedora/RHEL/CentOS 上为我工作,还需要 dnf install file-devel 才能编译 gem "ruby-filemagic"
    【解决方案2】:

    在 Ruby on Rails 中,您可以:

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

    【讨论】:

    • 不是一个有效的答案,它只是根据其扩展检测文件类型。如果你命名一个带有 FLV 扩展名的 PNG 文件,它会检测到它是一个 => "video/x-flv"
    • 如果您强制执行一致的文件扩展名可能就足够了。
    • 投反对票,因为扩展名与实际文件类型无关。可能根本没有扩展名。
    • Rails 4.0.1: NameError: uninitialized constant MIME, 你的 rails 版本是多少?
    • @IvanBlack 这是来自 Ruby gem,mime-types
    【解决方案3】:

    您可以根据文件的魔术头使用这种可靠的方法:

    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 可以设置为 ;rm -rf .。在这种特殊情况下,该方法会在不擦除当前目录的情况下安全地以Errno::ENOENT 失败,但当文件名由用户提供时,您最好不要依赖它。
    • file 不能保证安装在每个 Linux 发行版上。例如,它不在 docker://ubuntu:latest 中。跳之前先看看。
    【解决方案4】:

    你可以使用

    Mime::Type.lookup_by_extension(extention_name)

    谢谢

    【讨论】:

    • 否决,因为扩展名与实际文件类型无关。可能没有扩展名。
    • 如果您强制执行一致的文件扩展名可能就足够了。
    • -1 因为这使人们相信文件扩展名与文件类型相关(Windows 是唯一准确的地方)。
    【解决方案5】:

    ruby-filemagic gem 是一个很好的解决方案,但需要对 libmagic 的额外依赖(最近作为 CarrierWave::MagicMimeTypes 删除的一部分从 CarrierWave 中删除)。

    如果您对纯 ruby​​ 实现感兴趣,请考虑使用 MimeMagic gem!它适用于 freedesktop.org mime 数据库中列出的文件类型:

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

    对于 Microsoft Office 2007+ 格式(xlsx、docx 和 pptx),需要覆盖(除非您可以使用这些文件的通用“应用程序/zip”MIME 类型)

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

    【讨论】:

    • 它不适用于 docx 扩展,它将返回 docx 文件的 zip 内容类型。
    【解决方案6】:

    mimemagic gem 也会这样做

    https://github.com/minad/mimemagic

    来自官方文档

    MimeMagic 是一个通过扩展名检测文件的 mime 类型的库 或按内容。它使用 freedesktop.org 提供的 mime 数据库 (见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...
    

    【讨论】:

      【解决方案7】:

      filemagic gem 是很好的解决方案,但依赖于许多不必要的 gem。 (rails, aws-sdk-core, ...)

      如果您的应用程序很小并且只能在 Linux 或 OSX 中运行,请考虑使用file 程序:

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

      注意:将 __FILE__ 替换为任何包含文件路径的 expr。

      【讨论】:

        【解决方案8】:

        如果您是从头开始执行此操作,请安装 mimemagic gem

        gem 'mimemagic'

        打开流(目标图像的字节数)

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

        然后检查数据流的文件类型,例如:

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

        尽管如上所述

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

        这可能更优雅

        【讨论】:

          【解决方案9】:

          截至 2021 年,我认为根据所有可用提示(幻数、幻数不足时的文件名、用户提示)计算 mime 类型的最佳工具是 Marcel

          无耻地引用文档本身:

          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"
          

          【讨论】:

            猜你喜欢
            • 2014-02-20
            • 2010-09-10
            • 2011-06-15
            • 2011-06-09
            • 2018-11-07
            • 2019-07-14
            • 2011-08-06
            • 2012-02-05
            • 2010-10-13
            相关资源
            最近更新 更多