mkdir() 函數完整簽名
mkdir(
string $directory,
int $permissions = 0777,
bool $recursive = false,
?resource $context = null
): bool
參數詳解
| 參數 | 說明 | 注意事項 |
$directory | 目錄路徑(相對/絕對) | 建議用絕對路徑避免工作目錄混淆 |
$permissions | 八進位權限模式 | 預設 0777,實際受 umask 影響;Windows 忽略此參數 |
$recursive | 是否遞歸建立父目錄 | 關鍵參數,預設 false 導致父目錄不存在時失敗 |
$context | 串流上下文 | 罕用,支援 FTP/SSH2 等封裝協定 |
基本範例
<?php
$dir = "/var/www/project/storage/logs/2024/12";
// 1. 單層建立(父目錄必須存在)
if (!is_dir($dir)) {
if (mkdir($dir)) {
echo "單層建立成功";
} else {
echo "失敗:父目錄不存在";
}
}
// 2. 遞歸建立(推薦:一次建立完整路徑)
if (!is_dir($dir)) {
if (mkdir($dir, 0755, true)) { // true = recursive
echo "遞歸建立成功: {$dir}";
} else {
echo "遞歸建立失敗";
}
}
?>
權限模式深度解析
<?php
// umask 影響實際權限:最終權限 = mode & ~umask
// 預設 umask 通常為 0022
$mode = 0777; // 程式指定
$umask = umask(); // 取得目前 umask,如 0022
$actual = $mode & ~$umask; // 0777 & ~0022 = 0755
echo "指定: " . decoct($mode) . " | umask: " . decoct($umask) . " | 實際: " . decoct($actual);
// 最佳實踐:明確指定 0755 (目錄) 或 0644 (檔案)
// 目錄需有 x 權限才能進入/列出
mkdir('/path/to/dir', 0755, true);
?>
進階:原子性建立與競態條件處理
<?php
/**
* 安全建立目錄,處理競態條件
* @return bool true=建立成功或已存在, false=失敗
*/
function safeMkdir(string $path, int $mode = 0755): bool {
// 快速路徑:已存在且為目錄
if (is_dir($path)) {
return true;
}
// 嘗試建立
if (@mkdir($path, $mode, true)) {
return true;
}
// 失敗時再次檢查(可能被其他進程搶先建立)
if (is_dir($path)) {
return true;
}
// 真正失敗
$error = error_get_last();
error_log("mkdir 失敗: {$path} - " . ($error['message'] ?? '未知'));
return false;
}
// 使用
safeMkdir("/var/www/cache/" . date('Y/m/d'));
?>
常見錯誤與解決
| 錯誤訊息 | 原因 | 解決 |
| No such file or directory | 父目錄不存在且 recursive=false | 設定 recursive=true |
| Permission denied | 父目錄無寫入權限 | 調整父目錄擁有者/權限,或用 sudo 執行 |
| File exists | 同名檔案已存在(非目錄) | 檢查 file_exists() && !is_dir() |
| Operation not permitted | SELinux/AppArmor 限制 | 調整安全上下文 chcon -R -t httpd_sys_rw_content_t /path |
Windows 開發環境提醒
- 權限參數被忽略,但建議保留
0755 維持跨平台一致性。
- 路徑長度限制 260 字元(除非啟用 Long Paths)。
- 避免使用保留名稱:
CON, PRN, AUX, NUL, COM1-9, LPT1-9。
善用 mkdir($path, 0755, true) 這組黃金參數,搭配存在性預檢,能可靠建立專案所需的目錄結構。