首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

PHP 精確檢測文件 MIME 類型:多層級回退策略(finfo、mime_content_type、file 命令、擴展名映射)

     編輯:PHP 相關知識

PHP 精確檢測文件 MIME 類型:多層級回退策略(finfo、mime_content_type、file 命令、擴展名映射)

單靠擴展名判斷 MIME 不可靠,單靠 mime_content_type 可能缺失。本文實現一個四層回退的 _getMimeType() 函數,確保在各種 PHP 環境下都能獲得最準確的 MIME 類型。

四層檢測策略(優先級遞減)

層級方法可用條件準確度
1finfo_open(FILEINFO_MIME)PHP 5.3+ Fileinfo 擴展⭐⭐⭐⭐⭐ 魔術位元組檢測
2mime_content_type()PHP 內建(舊版)⭐⭐⭐⭐ 同層級 1
3exec('file -ib') / file -IbLinux/BSD 有 file 命令⭐⭐⭐⭐ 系統級檢測
4擴展名映射表兜底方案⭐⭐ 僅參考副檔名

完整實現

<?php
$mimeMap = [
    // applications
    'ai'=>'application/postscript', 'eps'=>'application/postscript', 'exe'=>'application/octet-stream',
    'doc'=>'application/vnd.ms-word', 'xls'=>'application/vnd.ms-excel', 'ppt'=>'application/vnd.ms-powerpoint',
    'pdf'=>'application/pdf', 'xml'=>'application/xml', 'odt'=>'application/vnd.oasis.opendocument.text',
    'swf'=>'application/x-shockwave-flash',
    // archives
    'gz'=>'application/x-gzip', 'tgz'=>'application/x-gzip', 'bz'=>'application/x-bzip2',
    'zip'=>'application/zip', 'rar'=>'application/x-rar', 'tar'=>'application/x-tar',
    // texts
    'txt'=>'text/plain', 'php'=>'text/x-php', 'html'=>'text/html', 'js'=>'text/javascript',
    'css'=>'text/css', 'rtf'=>'text/rtf', 'py'=>'text/x-python', 'java'=>'text/x-java-source',
    // images
    'bmp'=>'image/x-ms-bmp', 'jpg'=>'image/jpeg', 'png'=>'image/png', 'gif'=>'image/gif',
    'tif'=>'image/tiff', 'psd'=>'image/vnd.adobe.photoshop',
    // audio/video ...
];

function _getMimeDetect() {
    if (class_exists('finfo')) return 'finfo';
    if (function_exists('mime_content_type')) return 'mime_content_type';
    if (function_exists('exec')) {
        $r = exec('file -ib ' . escapeshellarg(__FILE__));
        if (strpos($r, 'text/x-php') === 0 || strpos($r, 'text/x-c++') === 0) return 'linux';
        $r = exec('file -Ib ' . escapeshellarg(__FILE__));
        if (strpos($r, 'text/x-php') === 0 || strpos($r, 'text/x-c++') === 0) return 'bsd';
    }
    return 'internal';
}

function _getMimeType($path) {
    global $mimeMap;
    $detect = _getMimeDetect();
    $type = 'unknown';

    switch ($detect) {
        case 'finfo':
            $finfo = finfo_open(FILEINFO_MIME);
            if ($finfo) $type = @finfo_file($finfo, $path);
            break;
        case 'mime_content_type':
            $type = @mime_content_type($path);
            break;
        case 'linux':
            $type = exec('file -ib ' . escapeshellarg($path));
            break;
        case 'bsd':
            $type = exec('file -Ib ' . escapeshellarg($path));
            break;
        default:
            $ext = strtolower(pathinfo($path, PATHINFO_EXTENSION));
            $type = $mimeMap[$ext] ?? 'unknown';
    }

    // 修正:若系統檢測返回 application/octet-stream,嘗試用擴展名修正
    if ($detect !== 'internal' && $type === 'application/octet-stream') {
        $ext = strtolower(pathinfo($path, PATHINFO_EXTENSION));
        if ($ext && isset($mimeMap[$ext])) $type = $mimeMap[$ext];
    }

    return explode(';', $type)[0]; // 去除 charset 等參數
}

// 測試(文件不存在時走擴展名兜底)
var_dump(_getMimeType('1.txt')); // string(10) "text/plain"
?>

關鍵細節

  • escapeshellarg() 防止命令注入。
  • explode(';', $type)[0] 移除 charset=binary 等後綴。
  • 針對 application/octet-stream 這類通用類型,二次嘗試擴展名映射修正。
  • 映射表涵蓋常見 60+ 格式,可按需擴展。

現代最佳實踐

PHP 5.3+ 環境請確保安裝 php-fileinfo 擴展(通常預設開啟),直接使用 finfo 即可獲得最高準確度,無需複雜回退邏輯。

$finfo = new finfo(FILEINFO_MIME_TYPE);
echo $finfo->file('/path/to/file'); // 如 image/png

此多層回退函數適合「需相容未知 PHP 環境」的通用庫開發場景。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved