验证失败:上传的文件扩展名与其内容不匹配。

14

我正在使用paperclip gem上传文件,我的paperclip gem版本是paperclip-4.1.1。在上传文件时出现问题:

Validation failed: Upload file has an extension that does not match its contents.
我正在尝试上传一个xlsx文件,并且我已经在模型content_type中提到了它。
 validates_attachment_content_type :upload_file, :content_type => %w(application/msword application/vnd.ms-office application/vnd.ms-excel application/vnd.openxmlformats-officedocument.spreadsheetml.sheet),
                                               :message => ', Only XML,EXCEL files are allowed. '

我不知道为什么会出现这个错误。如果您对此错误有任何想法,请分享。

摘录日志以显示验证失败:

Command :: file -b --mime-type '/tmp/5249540099071db4e41e119388e9dd6220140513-24023-1jlg4zy' [paperclip] Content Type Spoof: Filename file_for_bulk_upload1.xlsx (["application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"]), content type discovered from file command: . See documentation to allow this combination. 
Command :: file -b --mime-type '/tmp/6f19a4f96154ef7ce65db1d585abdb2820140513-24023-tt4u1e' [paperclip] Content Type Spoof: Filename file_for_bulk_upload1.xlsx (["application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"]), content type discovered from file command:

请问您能否提供日志文件中的错误信息?另外,虽然这不是失败的原因,但从错误信息来看,您似乎只想允许加载xml或excel文件。为什么要允许加载word文件呢?xml文件的MIME类型是application/xml - user740584
命令::file -b --mime-type '/tmp/5249540099071db4e41e119388e9dd6220140513-24023-1jlg4zy' [paperclip]内容类型欺骗:文件名 file_for_bulk_upload1.xlsx(["application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"]),从文件命令发现的内容类型:。请参阅文档以允许此组合。 命令::file -b --mime-type '/tmp/6f19a4f96154ef7ce65db1d585abdb2820140513-24023-tt4u1e' [paperclip]内容类型欺骗:文件名 file_for_bulk_upload1.xlsx(["application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"]),从文件命令发现的内容类型:。 - Can Can
请您手动检查此文件。在Unix提示符下输入以下几个命令:file --mime-type <filename.xlsx>mimetype <filename.xlsx> - user740584
file_for_bulk_upload1.xlsx:application/zip - Can Can
file_for_bulk_upload1.xlsx: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet - Can Can
@GraemeMcLean,我的本地机器可以运行,但测试服务器出现了错误。可能是什么问题? - Can Can
3个回答

17

由于file命令无法准确确定文件类型,因此Paperclip欺骗验证检查失败。

在您的日志中,content type discovered from file command: . - 句点前面的空格是输出结果 - 即为空白。但是比较的另一侧仅使用文件扩展名,正确地选择为Excel文件。因此,验证失败。

Paperclip的当前版本使用file -b --mime-type来确定文件,但并非所有实现都支持--mime-type。有一个更改使用--mime的选项,但它尚未达到里程碑。

我认为您有一些选择。您的选择取决于您对上传可疑文件并将其称为Excel文件的担忧程度。如果您担心这个问题,请尝试选项1;如果您不担心,请选择选项2或3。

1)覆盖欺骗检查,使用--mime而不是--mime-type

在初始化程序中覆盖type_from_file_command

module Paperclip
  class MediaTypeSpoofDetector
    private

    def type_from_file_command
      # -- original code removed --
      # begin
      #   Paperclip.run("file", "-b --mime-type :file", :file => @file.path)
      # rescue Cocaine::CommandLineError
      #   ""
      # end

      # -- new code follows --
      begin
         Paperclip.run("file", "-b --mime :file", :file => @file.path)
      rescue Cocaine::CommandLineError
        ""
      end
    end
  end
end

2) 通过从其文件扩展名完全设置文件类型来绕过file检查。

将此Paperclip选项设置在应用程序初始化期间的某个位置,例如(例如config/application.rbconfig/environments/<environment>.rbconfig/initializers/paperclip.rb):

Paperclip.options[:content_type_mappings] = { xlsx: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' }

3) 完全禁用欺骗。

通过在初始化器中创建以下内容来覆盖欺骗检查:

module Paperclip
  class MediaTypeSpoofDetector
    def spoofed?
      false
    end
  end
end

更新:

您在模型中进行的验证并不是这个问题的原因。它验证了您可以加载哪些类型的文件;而您看到的是Paperclip计算出文件类型是有效的,但其内容与文件类型不匹配。

假设您可以使欺骗验证起作用,那么您的内容验证存在一个异常。您输出的错误消息说“只允许使用XML、EXCEL文件”,但实际验证检查的是MS Word和Excel文件,而不是XML。

如果您的消息是正确的,并且确实只想允许使用XML和Excel文件,则应将content_type验证更改为:

validates_attachment_content_type :upload_file, :content_type => %w(application/xml application/vnd.ms-excel application/vnd.openxmlformats-officedocument.spreadsheetml.sheet),
                                                :message => ', Only XML,EXCEL files are allowed. '

抱歉,我以为你在测试服务器上运行了mimetype命令。无论如何,如果您无法安装mimetype,则可以使用我提供的其他选项之一,或者使用sudo apt-get install libfile-mimeinfo-perl进行安装。实际上,您能否在测试服务器上执行file --mime-type?这可能只是权限问题吗? - user740584
它给出了文件:未识别选项“--mime-type”。 - Can Can
它正在提供file_for_bulk_upload1.xlsx:application/x-zip文件。 - Can Can
我已经更改了我的答案中的选项1,因为似乎你的file实现不支持--mime-type。这应该可以解决问题,但是,如果你坚持认为.xlsx文件是一个zip文件,那么它实际上可能是一个真正的欺骗检测。你的文件是否被压缩?如果没有,那么你将不得不选择选项2或3,因为在这个服务器上似乎无法可靠地进行欺骗检测。 - user740584
选项1和2对我都没用,所以我从content_type切换到了只使用file_name验证。validates_attachment:file,presence:true,file_name:{matches:[/ xlsx \ Z /]}。这样可以防止欺骗,但仅限于该位置-其他图像/视频上传仍然会被检查。顺便说一句,现在是时候从Paperclip迁移到ActiveStorage了。 - shooma
显示剩余2条评论

0
今晚在从4.2升级到5.3时遇到了类似的问题。 接受的答案中的选项1和2对我没有用,所以我改为使用file_name验证而不是content_type
validates_attachment :file, presence: true, file_name: {matches: [/xlsx\Z/]}

欺骗可用,但仅限于具体附件 - 其他图片/视频上传仍会被检查。

PS:无论如何,纸片夹已弃用,现在是迁移到ActiveStorage的时候了。


-1

试试这个方法

validates_attachment_content_type :upload_file, :content_type => ["application/msword", "application/vnd.ms-office application/vnd.ms-excel", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"], :message => ', Only XML,EXCEL files are allowed. '

除了在%w()中引入双引号和逗号之外,您的代码片段还有其他更改吗?顺便说一下,%w()的整个目的是在构建数组时摆脱引号和逗号。尝试使用您的代码片段查看带有转义引号的结果数组! - Kostas Rousis
%w("a,b") 不是有效的。它是错误的。%w(a b) 是有效的。 - Pavan
3
您编辑后的答案现在提供了一个正确的数组,与原帖没有区别。 - Kostas Rousis
1
%w(a b) = ["a,b"]。您的答案与原帖相同。 - Pavan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接