You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Ruby on Rails中检测PDF、DOC/DOCX文件是否受密码保护?

刚好我之前在Rails项目里处理过类似的文件上传校验需求,给你整理几种靠谱的纯Ruby实现方案,针对PDF、DOC、DOCX分别说明:

检测PDF文件是否受密码保护

最常用的是ruby-pdf-reader这个库,它能直接读取PDF的元数据并检测加密状态。

首先在Gemfile里添加:

gem 'pdf-reader'

然后执行bundle install。

接下来写检测方法:

def password_protected_pdf?(file_path)
  reader = PDF::Reader.new(file_path)
  !reader.decrypt.nil? # 如果需要解密,说明文件是加密的
rescue PDF::Reader::EncryptedPDFError
  true # 直接抛出加密异常,肯定是受密码保护的
rescue StandardError => e
  # 处理文件损坏或其他异常,这里可以根据需求返回false或者抛出错误
  false
end

解释一下:这个方法会先尝试初始化PDF读取器,要是遇到加密的PDF,要么会抛出EncryptedPDFError,要么reader.decrypt会返回非nil值(表示需要密码才能解密)。两种情况都可以判定为受密码保护。

检测DOC文件是否受密码保护

DOC是旧版的OLE格式文件,我们可以用ruby-ole库来检查它的加密属性。

先添加Gem:

gem 'ruby-ole'

检测方法示例:

require 'ole/storage'

def password_protected_doc?(file_path)
  ole = Ole::Storage.open(file_path)
  # 加密的DOC会有一个名为"\x05Password"的OLE流
  ole.entries.any? { |entry| entry.name == "\x05Password" }
rescue Ole::Storage::FormatError => e
  # 文件不是合法的DOC或者损坏
  false
rescue StandardError => e
  false
ensure
  ole.close if ole
end

这个方法是通过检查OLE存储里是否存在特定的加密标记流来判断的,这是旧版DOC加密的典型特征。

检测DOCX文件是否受密码保护

DOCX本质是ZIP压缩包,加密的DOCX会在压缩包内包含加密相关的配置文件,比如EncryptionInfo.xml。我们可以用rubyzip库来读取ZIP内容进行判断。

添加Gem:

gem 'rubyzip'

检测方法:

require 'zip'

def password_protected_docx?(file_path)
  Zip::File.open(file_path) do |zip_file|
    # 加密的DOCX必然包含EncryptionInfo.xml文件
    zip_file.find_entry('EncryptionInfo.xml').present?
  end
rescue Zip::Error => e
  # 文件不是合法的DOCX或者损坏
  false
rescue StandardError => e
  false
end

另外,如果你想更严谨,还可以尝试读取ZIP里的XML内容,不过只要存在EncryptionInfo.xml基本就能确定是受密码保护的DOCX了。

在Rails上传流程中集成

比如你用Active Storage的话,可以在模型里添加自定义验证:

class Attachment < ApplicationRecord
  has_one_attached :file

  validate :file_not_password_protected

  private

  def file_not_password_protected
    return unless file.attached?

    temp_file = Tempfile.new(['upload', file.filename.extension_with_delimiter])
    temp_file.binmode
    temp_file.write(file.download)
    temp_file.close

    case file.filename.extension.downcase
    when 'pdf'
      if password_protected_pdf?(temp_file.path)
        errors.add(:file, '不能上传受密码保护的PDF文件')
      end
    when 'doc'
      if password_protected_doc?(temp_file.path)
        errors.add(:file, '不能上传受密码保护的DOC文件')
      end
    when 'docx'
      if password_protected_docx?(temp_file.path)
        errors.add(:file, '不能上传受密码保护的DOCX文件')
      end
    end
  ensure
    temp_file.unlink if temp_file
  end
end

注意这里要把前面写的三个检测方法放到模型里或者一个工具类里,方便调用。

另外要提醒的是:这些方法只能检测是否存在密码保护,不能破解密码,完全符合你的需求。如果遇到异常文件(比如损坏的文件),要做好异常处理,避免误判。

内容的提问来源于stack exchange,提问作者nurav

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 04:09:56