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

PHP rtrim() 陷阱:刪除後綴時誤刪文件名主體的 Bug 分析與修正

     編輯:PHP 相關知識

現象重現

<?php
echo rtrim('article_list.html', '.html')."\n";    // 預期 article_list  實際 article_list ✓
echo rtrim('article_index.html', '.html')."\n";   // 預期 article_index 實際 article_ind ✗
echo rtrim('articleABCT.html', '.html')."\n";     // 預期 articleABCT   實際 articleABCT ✓

輸出:

article_list
article_ind
articleABCT

根因分析

rtrim($str, $charlist) 的第二個參數是 字符集合 而非 字符串後綴。函數會從字符串末尾開始,逐個字符檢查是否在字符集合中,若在則刪除,直到遇到不在集合中的字符停止。

  • 'article_index.html' 末尾字符序列:l → m → x → . → l → m → t → h
  • 字符集合 '.html' 包含字符:. h t m l
  • 從右向左:h∈ → 刪,t∈ → 刪,m∈ → 刄,l∈ → 刪,.∈ → 刪,x∉ → 停止。
  • 結果保留 article_ind,ex 被誤刪。

正確解決方案

方案一:basename + pathinfo (推薦,語義清晰)

function removeExt(string $filename, string $ext): string {
    // 確保極性帶點
    $ext = $ext[0] === '.' ? $ext : '.' . $ext;
    $info = pathinfo($filename);
    if (isset($info['extension']) && $info['extension'] === ltrim($ext, '.')) {
        return $info['filename']; // 不含擴展名的文件名
    }
    return $filename; // 擴展名不匹配,原樣返回
}
// 測試
echo removeExt('article_index.html', '.html'); // article_index ✓
echo removeExt('article_index.htm', '.html');  // article_index.htm (不匹配) ✓

方案二:str_ends_with + substr (PHP 8.0+)

function removeSuffix(string $str, string $suffix): string {
    if (str_ends_with($str, $suffix)) {
        return substr($str, 0, -strlen($suffix));
    }
    return $str;
}

方案三:正則精準替換

function removeExtRegex(string $filename, string $ext): string {
    $ext = preg_quote($ext, '/');
    return preg_replace("/{$ext}$/", '', $filename);
}

對比速查

方法優點缺點適用版本
pathinfo內建、處理路徑分隔符、語義明確需額外判斷擴展名是否匹配所有版本
str_ends_with + substr直觀、性能高、嚴格匹配後綴PHP 8.0+PHP 8.0+
正則靈活、可處理複雜模式較慢、易寫錯所有版本
rtrim代碼短語義錯誤,極易產生 Bug—

最佳實踐建議

  1. 永不使用 rtrim/ltrim 去除固定後綴/前綴,除非你確定字符集合不會出現在主體中。
  2. 文件名處理優先用 pathinfo()、basename()、SplFileInfo。
  3. PHP 8.0+ 專案統一遷移至 str_starts_with/str_ends_with。
  4. 代碼審查時重點檢查字符串修剪邏輯。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved