Ответ 1
Я бы использовал ruby-filemagic gem, который является привязкой Ruby для libmagic.
Как вы можете проверить, является ли файл изображением? Я думаю, вы можете использовать такой метод:
def image?(file)
file.to_s.include?(".gif") or file.to_s.include?(".png") or file.to_s.include?(".jpg")
end
Но это может быть немного неэффективным и неправильным. Любые идеи?
(Я использую плагин paperclip, кстати, но я не вижу никаких способов определить, является ли файл изображением в папке)
Я бы использовал ruby-filemagic gem, который является привязкой Ruby для libmagic.
Один из подходов - использовать соглашение "магическое число" для чтения первых бит файла.
http://www.astro.keele.ac.uk/oldusers/rno/Computing/File_magic.html
Примеры:
"BM" is a Bitmap image "GIF8" is a GIF image "\xff\xd8\xff\xe0" is a JPEG image
Пример в Ruby:
def bitmap?(data) return data[0,2]=="MB" end def gif?(data) return data[0,4]=="GIF8" end def jpeg?(data) return data[0,4]=="\xff\xd8\xff\xe0" end def file_is_image?(filename) f = File.open(filename,'rb') # rb means to read using binary data = f.read(9) # magic numbers are up to 9 bytes f.close return bitmap?(data) or gif?(data) or jpeg?(data) end
Зачем использовать это вместо расширения имени файла или модуля filemagic?
Чтобы определить тип данных перед записью любых данных на диск. Например, мы можем прочитать поток данных для загрузки, прежде чем писать какие-либо данные на диск. Если магическое число не соответствует типу содержимого веб-формы, мы можем немедленно сообщить об ошибке.
Мы реализуем наш код реального мира несколько иначе. Мы создаем хэш: каждый ключ представляет собой строку магического числа, каждое значение представляет собой символ: bitmap,: gif,: jpeg и т.д. Если кто-то хочет увидеть наш код реального мира, не стесняйтесь связаться со мной здесь.
Поскольку вы используете Paperclip, вы можете использовать встроенный метод validates_attachment_content_type в модели, где используется "has_attached_file", и указать, какие типы файлов вы хотите разрешить.
Вот пример из приложения, в котором пользователи загружают аватар для своего профиля:
has_attached_file :avatar,
:styles => { :thumb => "48x48#" },
:default_url => "/images/avatars/missing_avatar.png",
:default_style => :thumb
validates_attachment_content_type :avatar, :content_type => ["image/jpeg", "image/pjpeg", "image/png", "image/x-png", "image/gif"]
Документация находится здесь http://dev.thoughtbot.com/paperclip/classes/Paperclip/ClassMethods.html
Пожалуйста, проверьте его один раз
MIME::Types.type_for('tmp/img1.jpg').first.try(:media_type)
=> "image"
MIME::Types.type_for('tmp/img1.jpeg').first.try(:media_type)
=> "image"
MIME::Types.type_for('tmp/img1.gif').first.try(:media_type)
=> "image"
MIME::Types.type_for('tmp/ima1.png').first.try(:media_type)
=> "image"
У imagemagick есть команда под названием identity, которая обрабатывает это: check w/paperclip documentation - возможно, это способ справиться с этим из вашего RoR-приложения.
Как дополнение к ответу Джоэля, в Rails 5 мне пришлось преобразовать строку сравнения в байт-код. Например:
def jpeg?(data)
return data[0,4]=="\xff\xd8\xff\xe0".b
end