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

PHP 多級目錄創建完全指南:mkdir 遞歸參數與自定義遞歸函數

     編輯:PHP 相關知識

原生 mkdir() 遞歸參數 (PHP 5.0+)

// 第三參數 true 開啟遞歸創建
$path = 'data/2024/03/15/logs';
if (!is_dir($path)) {
    mkdir($path, 0755, true); // 權限受 umask 影響,實際為 0755 & ~umask
    echo "創建成功: $path";
}

// 中文路徑需注意編碼 (Windows 文件系統通常為 GBK)
$zhPath = '數據/日誌/錯誤';
mkdir(iconv('UTF-8', 'GBK', $zhPath), 0755, true); // Linux 一般無需轉碼

自定義遞歸函數一:逐級創建 (兼容老版本、可控權限)

function mkdirs($path, $mode = 0755) {
    $path = rtrim($path, '/\\');
    if (is_dir($path)) return true;

    $parts = explode(DIRECTORY_SEPARATOR, $path);
    $current = '';
    foreach ($parts as $part) {
        $current .= $part . DIRECTORY_SEPARATOR;
        if (!is_dir($current)) {
            if (!@mkdir($current, $mode)) {
                error_log("mkdirs 失敗: $current");
                return false;
            }
        }
    }
    return true;
}

自定義遞歸函數二:從最深層向上檢查 (效率略高)

function mkdirsRecursive($path, $mode = 0755) {
    if (is_dir($path) || @mkdir($path, $mode)) return true;
    $parent = dirname($path);
    if ($parent === '.' || $parent === '/') return false;
    return mkdirsRecursive($parent, $mode) && @mkdir($path, $mode);
}

實戰封裝:FileSystem 工具類

class FileSystem {
    public static function ensureDir($path, $mode = 0755) {
        $path = rtrim($path, '/\\');
        if (is_dir($path)) return true;

        // Windows 路徑標準化
        if (DIRECTORY_SEPARATOR === '\\') {
            $path = str_replace('/', '\\', $path);
        }

        // 嘗試原生遞歸
        if (@mkdir($path, $mode, true)) return true;

        // 失敗則逐級重試 (處理權限、並發競爭)
        $parts = explode(DIRECTORY_SEPARATOR, $path);
        $current = '';
        foreach ($parts as $part) {
            $current .= $part . DIRECTORY_SEPARATOR;
            if (!is_dir($current)) {
                if (!@mkdir($current, $mode)) {
                    // 最後嘗試:可能是並發創建,再次檢查
                    if (!is_dir($current)) {
                        throw new RuntimeException("無法創建目錄: $current");
                    }
                }
            }
        }
        return true;
    }

    public static function removeDir($path) {
        $path = rtrim($path, '/\\');
        if (!is_dir($path)) return false;
        $items = new RecursiveIteratorIterator(
            new RecursiveDirectoryIterator($path, RecursiveDirectoryIterator::SKIP_DOTS),
            RecursiveIteratorIterator::CHILD_FIRST
        );
        foreach ($items as $item) {
            $item->isDir() ? rmdir($item->getPathname()) : unlink($item->getPathname());
        }
        return rmdir($path);
    }
}

// 使用
FileSystem::ensureDir('storage/app/public/uploads/2024/03');
FileSystem::removeDir('storage/tmp/old');

權限最佳實踐

  • 目錄 0755 (rwxr-xr-x),文件 0644 (rw-r--r--)。
  • Web 服務器用戶 (www-data/nginx) 需擁有寫入權限:chown -R www-data:www-data storage。
  • 共享主機環境避免 0777,若必須則配合 .user.ini 禁用執行權限。
  • Laravel/ThinkPHP 等框架已內置 Storage::makeDirectory(),優先使用框架封裝。

常見錯誤排查

錯誤原因解決
Permission denied父目錄不可寫chmod/chown 父目錄,或調整 PHP-FPM 用戶組
File exists同名文件非目錄unlink 後再 mkdir
No such file or directory路徑過深/編碼問題逐級創建、iconv 轉碼
Operation not permittedSELinux/AppArmor 限制調整安全策略或放寬上下文
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved