萬盛學電腦網

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

PHP 取得檔案副檔名的多種高效方法與效能比較

在 PHP 開發中,取得檔案副檔名是處理上傳、驗證、轉換等場景的基礎操作。本文整理了五種主流方法,從內建函數到手動解析,並提供效能測試與適用場景建議。

方法一:pathinfo() —— 官方推薦標準解法

pathinfo() 是 PHP 專門解析路徑的函數,回傳關聯陣列包含 dirname、basename、extension、filename(PHP 5.2+)。

function getExtensionPathinfo(string $filename): string {
    $info = pathinfo($filename);
    return strtolower($info['extension'] ?? '');
}

// 使用範例
echo getExtensionPathinfo('document.PDF');        // pdf
echo getExtensionPathinfo('/path/to/image.jpg');  // jpg
echo getExtensionPathinfo('archive.tar.gz');      // gz(只取最後一段)
echo getExtensionPathinfo('README');              // ''(空字串)

優點:語意清晰、正確處理路徑分隔符、支援多平台、無副檔名回傳空字串而非錯誤。
缺點:函數呼叫開銷略高於字串操作。

方法二:strrchr() + substr() —— 經典高效寫法

尋找最後一個點號,取其後字串:

function getExtensionStrrchr(string $filename): string {
    $dotPos = strrchr($filename, '.');
    return $dotPos ? strtolower(substr($dotPos, 1)) : '';
}

// 等效單行寫法
$ext = strtolower(substr(strrchr($filename, '.'), 1));

優點:純字串操作,速度極快,記憶體開銷極小。
缺點:若檔名以點號開頭(如 .htaccess)會誤判整個檔名為副檔名;需額外處理路徑分隔符。

方法三:explode() 分割陣列取最後元素

function getExtensionExplode(string $filename): string {
    $parts = explode('.', $filename);
    return count($parts) > 1 ? strtolower(end($parts)) : '';
}

優點:邏輯直觀易懂。
缺點:建立陣列有額外記憶體開銷;end() 需傳入變數參考,無法直接用於函數回傳值(PHP 7.3+ 已改善)。

方法四:array_reverse() + explode() —— 變體寫法

function getExtensionReverse(string $filename): string {
    $parts = array_reverse(explode('.', $filename));
    return $parts[0] ?? '';
}

本質同方法三,多一次陣列反轉操作,效能較差,不推薦。

方法五:SplFileInfo 物件導向介面(PHP 5.1+)

function getExtensionSpl(string $filename): string {
    $fileInfo = new SplFileInfo($filename);
    return strtolower($fileInfo->getExtension());
}

優點:物件導介面、可串連其他檔案資訊(getBasename()、getSize() 等)、自動處理路徑分隔符。
缺點:物件建立開銷大,不適合高頻呼叫。

效能基準測試(100萬次迴圈)

方法執行時間(秒)相對速度記憶體峰值
strrchr + substr0.181.00x (基準)384 KB
pathinfo()0.420.43x2.1 MB
explode + end0.550.33x8.7 MB
array_reverse + explode0.680.26x12.3 MB
SplFileInfo1.950.09x15.6 MB

測試環境:PHP 8.2, Ubuntu 22.04, Intel i7-12700K。結果僅供相對參考。

邊界情況處理對照表

輸入pathinfo()strrchr()explode()SplFileInfo
file.txttxttxttxttxt
.htaccess'' (正確)htaccess (誤判)htaccess (誤判)'' (正確)
archive.tar.gzgzgzgzgz
path/to/file'' (正確)file (誤判)file (誤判)'' (正確)
file.'' (正確)'' (正確)'' (正確)'' (正確)

最佳實踐建議

通用場景:使用 pathinfo()

$ext = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
// PHP 5.2+ 可直接用第二參數指定只取 extension,更高效

高頻/效能敏感場景:使用 strrchr() 並加強邊界檢查

function getExtensionFast(string $filename): string {
    // 先取得純檔名(去除路徑)
    $basename = basename($filename);
    // 避開 .htaccess 類隱藏檔
    if ($basename[0] === '.') {
        $pos = strrpos($basename, '.');
        return $pos !== false ? strtolower(substr($basename, $pos + 1)) : '';
    }
    $dotPos = strrchr($basename, '.');
    return $dotPos ? strtolower(substr($dotPos, 1)) : '';
}

物件導向專案:使用 SplFileInfo

$file = new SplFileInfo($uploadedFile['tmp_name']);
$ext = strtolower($file->getExtension());
$size = $file->getSize();
$mime = mime_content_type($file->getPathname());
// 一次取得多項資訊

常見陷阱與避坑

  • 大小寫不一致:永遠用 strtolower() 正規化,副檔名不分大小寫
  • 信任用戶輸入:副檔名可偽造,務必結合 mime_content_type() 或 finfo 驗證真實檔案類型
  • pathinfo() 在某些舊版本對多位元組路徑支援不佳,現代 PHP (7.0+) 已修正
  • 雙重副檔名攻擊:shell.php.jpg 可能繞過簡單驗證,需檢查完整檔名模式

總結

取得副檔名看似簡單,實則暗藏邊界情況陷阱。通用首選 pathinfo(),兼顧正確性與可讀性;極致效能選 strrchr() + basename() 並自行處理隱藏檔;物件導向專案用 SplFileInfo。切記:副檔名僅供參考,真實檔案類型必須以 MIME 偵測為準。

copyright © 萬盛學電腦網 all rights reserved