使用Python Flask建置影像圖檔上傳網站服務(四):使用filetype檢測上傳檔類型

延續上一篇貼文透過檢查副檔名過濾上傳檔案,本文採用Python的filetype程式庫,實際讀取檔案內容來鑑別檔案的真實類型。

透過文件的標頭數據判斷其類型

影音媒體文件的開頭都包含檔案資訊,以JPEG影像檔為例,檔頭前20個位元組包含解析度單位、水平解析度、垂直解析度、水平像素數量、垂直像素數量…等資訊。

JPEG檔頭

在.jpg影像檔上按滑鼠右鍵,查看它的內容,即可檢視影像資訊。

影像的詳細資料

右上圖的.jpg檔沒有任何數據,因為它不是真的影像檔,而是把副檔名.exe改成.jpg的假圖檔。所以,驗證檔案是否為影像,只需要讀取、解析檔案開頭的一小部分資訊,不必讀取整個檔案。

使用下列Hex Editor(16進位碼編輯器)開啟JPEG圖檔,可觀察到JPEG影像檔的前兩個位元組一定是FF D8。

使用filetype模組檢測檔案類型

Python 3的標準程式庫有內建檢查文件檔頭是否包含影像資料的imghdr模組,可辨識常見的JPEG, PNG, GIF, TIFF,…等影像檔,使用也很簡單,假設“cookies.jpg”是真實的JPEG影像,底下what()函式將傳回“jpeg”,否則傳回None。

import imghdr
imghdr.what('cookies.jpg')  # 讀取目前路徑裡的cookies.jpg檔 

但imghdr模組只能鑑別圖檔。本文範例程式採用filetype模組檢測檔案類型,它可辨識多種影像、視訊、聲音和壓縮檔案格式。以影像圖檔為例,filetype能分辨下列類型:

  • dwg – image/vnd.dwg
  • xcf – image/x-xcf
  • jpg – image/jpeg
  • jpx – image/jpx
  • png – image/png
  • gif – image/gif
  • webp – image/webp
  • cr2 – image/x-canon-cr2
  • tif – image/tiff
  • bmp – image/bmp
  • jxr – image/vnd.ms-photo
  • psd – image/vnd.adobe.photoshop
  • ico – image/x-icon
  • heic – image/heic

請先在本專案的Python Flask虛擬環境執行底下pip install命令安裝filetype模組,根據此模組的專案網頁說明,filetype目前最高支援Python 3.9版,我在Ubuntu系統用Python 3.10.2版測試執行沒問題。

pip install filetype

底下列舉filetype模組裡的3個函式,它們都接收一個「檔案路徑」參數。

  • guess(檔案路徑):傳回已知類型檔案的物件,透過extension(副檔名)和mime屬性,可分別取得副檔名和MIME類型名稱字串;傳回None代表未知檔案。
  • guess_extension(檔案路徑):傳回已知的副檔名字串,例如,”jpg”, “png”, “mp4”, “mp3″,或者None代表未知。
  • guess_mime (檔案路徑):傳回已知的MIME類型名稱字串,例如,”image/jpeg”, “video/mpeg”,或者None代表未知。

包含驗證圖檔的Flask上傳檔案服務程式

修改上一篇貼文的app.py程式碼,加入使用filetype模組檢測上傳檔是否為允許的影像檔。包含requirements.txt和index.html樣版檔的原始碼,可按此連結下載

包含驗證圖檔的Flask上傳檔案服務程式

補充說明「令讀取檔案的游標回到開頭」的 file.stream.seek(0) 敘述。每當執行filetype模組的guess_extension()或其他驗證檔案內容的函式,filetype程式都會讀取檔案開頭的一部分位元組,假設程式讀取了前20個位元組(實際讀取將近200位元組),下次讀取檔案,將從第21個位元組開始:

JPEG檔頭

如果不執行 file.stream.seek(0) 把游標移到檔案開頭,後面的file.save()函式儲存的檔案將是缺少前20個位元組的殘缺檔案,而上傳、存檔完畢後,你將看到如下的網頁畫面:

殘缺影像

為了讓後面的file程式物件能從頭讀取完整的檔案,必須執行 file.stream.seek(0) 敘述。

Posts created 470

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *

Related Posts

Begin typing your search term above and press enter to search. Press ESC to cancel.

Back To Top