PHP mkdir() 預設不支援遞迴建立多層目錄(PHP 5.0+ 已支援 recursive 參數),但理解手動實作邏輯有助於處理特殊權限、錯誤處理等進階需求。
<?php
/**
* 遞迴建立多層目錄
* @param string $dir 目標路徑(如 a/b/c/d)
* @param int $mode 權限(預設 0700)
* @return string|false 成功回傳路徑,失敗 false
*/
function makedir($dir, $mode = 0700) {
// 正規化路徑分隔符
$dir = str_replace('\\', '/', $dir);
$dir = rtrim($dir, '/');
if (is_dir($dir)) return $dir; // 已存在
$parts = explode('/', $dir);
$current = '';
foreach ($parts as $part) {
$current .= $part . '/';
if (!is_dir($current)) {
if (!@mkdir($current, $mode)) {
trigger_error("建立目錄失敗: $current", E_USER_WARNING);
return false;
}
@chmod($current, $mode); // 確保權限
}
}
return $dir;
}
// 使用範例
makedir('data/cache/user/123/profile');
makedir('../uploads/2024/12/25', 0755);
// 單行搞定,支援遞迴
mkdir('data/cache/user/123/profile', 0755, true);
// 第三參數 true = recursive
class Directory {
public static function make($path, $mode = 0755) {
$path = rtrim(str_replace('\\', '/', $path), '/');
if (is_dir($path)) return ['success' => true, 'path' => $path, 'created' => false];
$created = [];
$parts = explode('/', $path);
$current = '';
foreach ($parts as $part) {
$current .= $part . '/';
if (!is_dir($current)) {
$result = @mkdir($current, $mode);
if (!$result) {
return ['success' => false, 'path' => $current, 'error' => error_get_last()];
}
@chmod($current, $mode);
$created[] = $current;
}
}
return ['success' => true, 'path' => $path, 'created' => $created];
}
}
// 使用
$result = Directory::make('var/log/app/2024/12');
if ($result['success']) {
echo "建立成功,新建目錄: " . implode(', ', $result['created']);
} else {
echo "失敗於 {$result['path']}: {$result['error']['message']}";
}
| 細節 | 手動實作 | 內建 mkdir(recursive) |
|---|---|---|
| PHP 版本需求 | 全版本 | 5.0+ |
| 權限控制 | 逐層 chmod() 可精細控制 | 僅最終目錄套用 mode,父目錄受 umask 影響 |
| 錯誤處理 | 可自訂每層失敗行為 | 整體失敗,無法知曉哪層出問題 |
| 效能 | 多次系統呼叫 | 內核優化,單次呼叫 |
| 競態條件 | 需自行處理 | 內核原子性較好 |
mkdir($path, 0755, true)flock() 鎖定或資料庫協調/,PHP 內部自動轉換理解遞迴建目錄邏輯,能在權限管理、錯誤診斷、跨平台相容等進階場景遊刃有餘。