萬盛學電腦網

您现在的位置: 萬盛學電腦網 >> 程式設計 >  >> 網路程式設計 >> PHP 程式設計

PHP 獲取上傳文件類型三大法:副檔名白名單、MIME 偵測、檔頭魔數讀取

方法一:副檔名白名單(最簡單、最不可靠)

function getTypeByExt(string $filename): string {
    $ext = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
    $allowed = ['jpg','jpeg','png','gif','bmp','webp','pdf','doc','docx'];
    return in_array($ext, $allowed, true) ? $ext : 'invalid';
}

方法二:MIME 類型偵測 (finfo / Fileinfo 擴展)

function getMimeType(string $tmpPath): string {
    $finfo = new finfo(FILEINFO_MIME_TYPE);
    return $finfo->file($tmpPath); // 例: image/jpeg, application/pdf
}

// 對照表驗證
$mimeMap = [
    'jpg'  => 'image/jpeg',
    'png'  => 'image/png',
    'gif'  => 'image/gif',
    'pdf'  => 'application/pdf',
];
if (($mimeMap[$ext] ?? null) !== $mime) {
    throw new Exception('檔案類型不符');
}

方法三:讀取檔頭魔數 (Bytes Signature) - 最底層驗證

function getTypeByMagic(string $path): string {
    $fp = fopen($path, 'rb');
    $header = fread($fp, 8); // 讀前 8 位元組足夠大多數格式
    fclose($fp);
    
    $signatures = [
        "\xFF\xD8\xFF"        => 'jpg',
        "\x89\x50\x4E\x47"    => 'png', // PNG
        "\x47\x49\x46\x38"    => 'gif', // GIF87a/89a
        "\x42\x4D"            => 'bmp',
        "\x25\x50\x44\x46"    => 'pdf', // %PDF
        "\x50\x4B\x03\x04"    => 'zip', // ZIP 基礎 (docx/xlsx/epub 等)
        "\x7F\x45\x4C\x46"    => 'elf', // Linux 執行檔
    ];
    
    foreach ($signatures as $sig => $type) {
        if (str_starts_with($header, $sig)) return $type;
    }
    return 'unknown';
}

綜合驗證策略(推薦)

  1. 副檔名白名單:快速攔截明顯非法副檔名。
  2. finode MIME 驗證:核心防禦,確認檔案內容與副檔名一致。
  3. 圖片重繪:imagecreatefromstring() → imagejpeg() 覆寫暫存檔,徹底剝離夾帶腳本/EXIF。
  4. 儲存重命名:bin2hex(random_bytes(16)) . '.' . $ext,防路徑遍歷、覆蓋、執行。
  5. 儲存目錄禁用腳本執行:Nginx location ~ \.php$ { deny all; }。

常見檔頭魔數速查

格式Hex 簽名ASCII
JPEGFF D8 FFÿØÿ
PNG89 50 4E 47 0D 0A 1A 0A‰PNG...
GIF47 49 46 38 37/39 61GIF87a/89a
PDF25 50 44 46%PDF
ZIP/DOCX/XLSX50 4B 03 04PK..
RAR52 61 72 21 1A 07Rar!..
BMP42 4DBM
EXE/DLL4D 5AMZ
copyright © 萬盛學電腦網 all rights reserved