在 PHP 開發中,mkdir() 是創建目錄的核心函數,但「權限不足」導致創建失敗是新手最常遇到的坑。本文系統梳理創建目錄的正確姿勢、失敗原因分析及多種環境下的解決方案。
mkdir(string $path, int $mode = 0777, bool $recursive = false, resource $context = null): bool
| 參數 | 說明 | 默認值 |
|---|---|---|
| path | 目錄路徑(相對/絕對) | 必填 |
| mode | 權限模式(八進制),受 umask 影響 | 0777 |
| recursive | 是否遞歸創建父目錄 | false |
| context | 流上下文(如 FTP 協議) | null |
<?php
$dir = 'uploads/images/2024';
// 遞歸創建,權限 0755(擁有者讀寫執行,組/其他讀執行)
if (mkdir($dir, 0755, true)) {
echo "目錄創建成功:$dir";
} else {
echo "創建失敗,請檢查權限或路徑";
}
?>
現象:mkdir() 返回 false,error_get_last() 顯示 Permission denied。
排查:
<?php
$parent = dirname($dir);
echo "父目錄權限: " . substr(sprintf('%o', fileperms($parent)), -4);
echo " 當前用戶: " . get_current_user();
?>
解決:
chmod 755 /var/www/html/uploadschmod($parent, 0755);(需當前用戶有權限)虛擬主機常見:FTP 上傳的目錄屬於 FTP 用戶,而 PHP-FPM 以 www-data 運行,無法寫入。
方案:
chown -R www-data:www-data /path/to/dirsetfacl -R -m u:www-data:rwx /path/to/dirlisten.owner/listen.group 匹配 FTP 用戶CentOS/RHEL 預設開啟 SELinux,即使權限 777 也可能被阻擋。
檢查:getenforce 返回 Enforcing 即開啟。
臨時關閉:setenforce 0(重啟失效)
永久策略:
# 允許 httpd 讀寫特定目錄
semanage fcontext -a -t httpd_sys_rw_content_t "/var/www/html/uploads(/.*)?"
restorecon -Rv /var/www/html/uploads
__DIR__ 構建絕對路徑:$dir = __DIR__ . '/data/cache';rawurlencode() 處理無法修改服務器權限時,可用 FTP 擴展代理創建:
<?php
$ftp = ftp_connect('localhost');
ftp_login($ftp, 'user', 'pass');
ftp_mkdir($ftp, '/public_html/uploads/newdir'); // 以 FTP 用戶身份創建
ftp_chmod($ftp, 0755, '/public_html/uploads/newdir');
ftp_close($ftp);
?>
recursive=true 遞歸創建0755 而非 0777(安全原則)is_writable(dirname($path))error_get_last()['message']掌握這些核心知識點,目錄創建失敗將不再是難題。建議在部署腳本中自動化處理權限設置,從源頭避免問題。