python-magic:最實用的「以內容判斷文件類型」方法

當伺服器具備圖片上傳功能時,往往會遇到以下需求。

  • .png 這個檔案真的 PNG 嗎?」
  • 「先判斷這個檔案是圖片還是文件,再決定處理方式。」
  • 「在使用 Pillow/OpenCV 等外部解析器之前,先確認檔案類型。」

此時最堅實的起點不是「副檔名」,而是「檔案內容」。 而「以內容判斷」最簡單的工具就是 python-magic


python-magic 是什麼?



python-magic 是一個將 C 語言函式庫 libmagic 包裝成 Python 可用的工具。libmagic 透過檢查檔案的「頭部(前幾個位元組)」等特徵來辨識檔案類型,這個功能在 Unix 的 file 指令中也能看到。

簡而言之:

  • file(Linux 指令)=「在終端機使用的介面」
  • libmagic = 「核心引擎(判斷邏輯)」
  • python-magic = 「在 Python 中呼叫 libmagic 的薄包裝」

本文將以 python-magic 為核心,結構化說明「這個引擎究竟如何判斷檔案類型」。


libmagic 的工作原理

libmagic 库工作原理图

libmagic 的核心概念很簡單:

「讀取包含檔案類型判斷規則的資料庫,依照規則檢查檔案位元組,並給出最合理的結論。」

這個資料庫即為 magic database(魔法模式資料庫),file/libmagic 共同使用。通常以編譯後的二進位檔(magic.mgc)安裝在系統中。

1) 「魔法檔」是規則集合

這些規則主要包含:

  • 要檢查的位置(offset:檔案的哪個位元組)
  • 讀取方式(type:位元組/字串/整數等)
  • 比較目標(expected value/pattern)
  • 判斷結論(message/MIME 等)

file 的手冊也說明它在檢查「magic patterns」。規則逐行測試(offset/type/value/message),若符合則進一步進入更具體的子測試,形成「層級結構」。

想了解 Linux file 指令的詳細資訊,請點擊以下連結。

了解 Linux file 指令

2) 規則資料庫有「文字原始」與「編譯結果」

魔法資料庫原本是人類可讀的文字片段,為了效能,通常也提供編譯後的二進位資料庫(.mgc)。

3) 目的:以內容判斷檔案類型

file 之所以被視為「以內容判斷檔案類型」的工具,已是長久以來的哲學。python-magic 就是把這個哲學「以一行 Python 代碼」帶進來的工具。


如何使用 python-magic



常見的使用模式有兩種。

1) 取得 MIME 類型(最實用)

適用於上傳處理、路由、日誌/指標。

import magic

mime = magic.from_file("upload.bin", mime=True)
print(mime)  # 例如: image/png

python-magic 以 libmagic 為基礎提供檔案類型辨識,功能與 file 指令相同,官方說明亦如此。

2) 直接以位元組判斷(上傳流時更方便)

在將檔案寫入磁碟前,只需檢查上傳的前幾個位元組即可快速判斷。

import magic

with open("upload.bin", "rb") as f:
    head = f.read(4096)

mime = magic.from_buffer(head, mime=True)
print(mime)

(基於緩衝區的判斷特別適合作為「檔案寫入前的第一道過濾器」)


從開發者角度看其實用性

1) 上傳驗證的第一道防線

  • 不僅依賴副檔名
  • 先確認「這個檔案能否被當作圖片處理」

2) 處理流程的分流點

  • 若是圖片 → 進入縮放/縮圖流程
  • 若是 PDF/ZIP → 交給其他工作者
  • 若是未知類型 → 隔離/拒絕/進一步驗證

3) 在呼叫「重量級解碼器」前降低成本

Pillow 等解碼器雖強大,但呼叫本身會消耗記憶體/CPU,甚至擴大攻擊面。python-magic 可先判斷「是否值得進一步處理」。

重要實務提醒:libmagic 只是一個推測/辨識工具。若安全性是首要目標,仍需額外驗證(白名單、大小限制、沙盒解碼等)。


小結:python-magic 是「以程式碼輕鬆取得檔案類型」的最佳選擇

  • 不是用來處理圖片,而是告訴你「這個檔案應該怎麼對待」
  • 引擎:file/libmagic
  • 判斷方式:規則資料庫 + 位元組檢查
  • 在實務中,特別適合上傳驗證、路由決策、成本節省

掌握後,即使在缺乏其他庫的環境,也能構建「判斷 → 分流 → 安全防護」的流程。


下一篇預告

  • 解析 Pillow(PIL)的 open()load()verify() 各自保證什麼,何時使用,如何運作。

相關文章