PHP 內建的 is_writable() 函數雖然方便,但在某些特殊場景(如權限判斷不準確、掛載點檢測等)下可能無法滿足需求。本文提供一個功能完整的替代實現 isWritable(),並詳細解析其核心邏輯與邊界處理。
function isWritable($filename) {
// 1. 處理目錄路徑:若以 / 結尾,視為目錄,嘗試建立臨時文件測試
if (preg_match('/\/$/', $filename)) {
$tmp_file = sprintf('%s%s.tmp', $filename, uniqid(mt_rand()));
return isWritable($tmp_file); // 遞歸調用檢測目錄可寫性
}
// 2. 文件已存在:嘗試以 "r+" 模式打開(讀寫模式,指針在開頭)
if (file_exists($filename)) {
$fp = @fopen($filename, 'r+');
if ($fp) {
fclose($fp);
return true;
}
return false;
}
// 3. 文件不存在:嘗試以 "w" 模式創建新文件
$fp = @fopen($filename, 'w');
if ($fp) {
fclose($fp);
unlink($filename); // 測試成功後立即刪除臨時文件
return true;
}
return false;
}
當路徑以 / 結尾時,視為目錄。通過生成唯一臨時文件名(uniqid(mt_rand()) 保證唯一性),遞歸調用自身測試目錄是否可寫。這比單純檢查權限位更可靠,因為它實際嘗試了文件系統操作。
使用 fopen($filename, 'r+') 而非 'w' 或 'a',原因在於:
r+:以讀寫模式打開,文件指針置於開頭,**不會截斷文件內容**w:會清空文件內容,破壞原有數據a:指針置於結尾,無法驗證文件開頭可寫性若打開成功即關閉句柄返回 true,失敗返回 false。
對於不存在的路徑,嘗試以 w 模式創建。成功後立即 fclose() 並 unlink() 刪除,避免留下垃圾文件。這模擬了實際寫入場景,包含目錄權限、磁盤空間、inode 限制等所有約束條件。
fileperms() 更準確,繞過 ACL、SELinux 等複雜權限系統的誤判雖然此實現較健壯,但須注意:
false此實現可作為 is_writable() 的可靠補充,特別適合需要精確判斷寫入權限的文件上傳、緩存系統、日誌輪轉等場景。