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

PHP mkdir 建立目錄失敗常見原因與遞歸創建最佳實踐

     編輯:PHP 相關知識

核心問題:父目錄不存在導致失敗

mkdir('/a/b/c') 若 /a/b 不存在,**直接返回 false** 並拋出 Warning。這是新手最常踩的坑。

解決方案:開啟遞歸參數

<?php
// PHP 5.0.0+ 支援第三參數 $recursive
mkdir('/a/b/c', 0755, true); // true = 遞歸創建所有不存在的父目錄
?>
  • 0755:權限掩碼(八進制),建議目錄用 0755,文件用 0644。
  • true:遞歸模式,**務必加上**。

獲取當前腳本所在目錄(實際物理路徑)

原文提供的 fileDir() 寫法較繁瑣,現代 PHP 推薦:

<?php
// 當前腳本目錄(絕對路徑,無尾部斜槓)
$scriptDir = __DIR__;                    // PHP 5.3+ 魔術常數,最推薦
// 或
$scriptDir = dirname(__FILE__);          // 兼容舊版本

// 當前工作目錄(可能非腳本目錄,視執行方式而定)
$cwd = getcwd();

// 組合目標路徑
$targetDir = $scriptDir . '/uploads/images/2024/';
mkdir($targetDir, 0755, true);
?>

完整健壯封裝函數

<?php
/**
 * 安全創建目錄(遞歸、權限、異常處理、競爭條件緩解)
 * @param string $path 目標目錄絕對路徑
 * @param int $mode 權限掩碼,預設 0755
 * @return bool 是否創建成功或已存在
 * @throws RuntimeException 權限不足或路徑非法
 */
function ensure_dir(string $path, int $mode = 0755): bool {
    // 1. 規範化路徑
    $path = rtrim($path, '/\\');
    if ($path === '') throw new InvalidArgumentException('路徑不能為空');

    // 2. 已存在且是目錄 → 直接成功
    if (is_dir($path)) return true;

    // 3. 存在但非目錄(同名文件/連結)→ 拋錯
    if (file_exists($path)) {
        throw new RuntimeException("路徑已存在但非目錄:{$path}");
    }

    // 4. 遞歸創建(使用 @ 抑制 warning,自行判斷返回值)
    $result = @mkdir($path, $mode, true);
    if ($result === false) {
        // 可能是併發下其他進程剛創建好,再次檢查
        if (is_dir($path)) return true;
        $error = error_get_last();
        throw new RuntimeException("創建目錄失敗:{$path} - " . ($error['message'] ?? '未知錯誤'));
    }

    // 5. 可選:修正權限(受 umask 影響)
    @chmod($path, $mode);

    return true;
}

// 使用
try {
    ensure_dir(__DIR__ . '/storage/logs');
    ensure_dir('/var/www/html/uploads/avatar');
} catch (Throwable $e) {
    error_log($e->getMessage());
}
?>

權限與 umask 關係圖解

模式 0755 & umask 0022 = 實際 0755  (rwxr-xr-x)
模式 0777 & umask 0022 = 實際 0755  (umask 預設會拿走寫權限)
建議:顯式 chmod 或設置 umask(0) 後創建(需謹慎,影響全局)

常見場景與對策

場景對策
上傳目錄按日期分層ensure_dir("uploads/" . date('Y/m/d'));
緩存目錄需 Web 寫入、CLI 讀取設置 0775 + 同組用戶;或 ACL setfacl -m g:www-data:rwx
Windows 開發、Linux 生產路徑分隔符用 DIRECTORY_SEPARATOR 或統一正斜槓 /(PHP 自動兼容)
Nginx + PHP-FPM 權限不一致確保目錄擁有者為 www-data 或 PHP-FPM 運行用戶,組權限 rwx

總結

  1. 永遠使用 mkdir($path, 0755, true) 遞歸創建。
  2. 路徑基準用 __DIR__ 而非 getcwd()。
  3. 封裝 ensure_dir() 統一處理異常、權限、併發。
  4. 生產環境關注用戶/組權限、umask、ACL、SELinux。

掌握這幾點,徹底告別「mkdir 失敗」煩惱。

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