PHP中mkdir()本身不锚定路径,防范目录穿越需开发者主动校验:先定义可信绝对根目录,再用basename()提取子名或realpath()+str_starts_with()确认路径在根内,最后安全创建。

PHP 中 mkdir() 本身不提供“路径锚定”机制,它只是按你传入的 $path 创建目录。所谓“锚定在指定根目录内”,实际是由开发者主动控制路径构造逻辑,防止路径穿越(如 ../)、越权写入或误操作。关键不是 mkdir() 本身,而是你怎么生成和校验那个 $path。
✅ 明确你的“指定根目录”
先定义一个可信的、你允许创建子目录的绝对基路径,例如:
$root = '/var/www/uploads'; // 或用 __DIR__ . '/data' 等
这个 $root 必须是绝对路径,且 Web 服务器进程(如 www-data、nginx 用户)对该目录有写权限。
✅ 构造安全子路径:避免 ../ 和绝对路径注入
不能直接拼接用户输入,比如:
// ❌ 危险!用户传入 '../etc/passwd' 就可能逃逸 $userInput = $_GET['dir']; mkdir($root . '/' . $userInput);
正确做法是:
- 用
basename()提取合法文件夹名(只保留最后一级) - 或用
realpath()+str_starts_with()校验是否仍在根内
$subDir = basename($_GET['dir']); // 仅取干净的文件夹名,如 '2026/11' → 变成 '11'
$target = $root . '/' . $subDir;
if (is_dir($target)) {
echo "目录已存在";
} else {
mkdir($target, 0755, true);
}
更严格的做法(推荐用于用户可控场景):
$root = realpath('/var/www/uploads');
$userPath = $_GET['dir'] ?? '';
// 归一化并解析为绝对路径
$fullPath = realpath($root . '/' . $userPath);
// 校验:是否仍以 $root 开头?且是目录(非文件)
if ($fullPath === false || !str_starts_with($fullPath, $root) || !is_dir($fullPath)) {
die('非法路径');
}
// 安全创建(递归)
mkdir($fullPath, 0755, true);
✅ 使用 open_basedir 或 chroot 做系统级防护(可选)
-
open_basedir是 PHP 配置项,限制脚本只能访问指定目录树,mkdir()也会受其约束:open_basedir = "/var/www/uploads:/tmp"
这样即使代码误写
mkdir('/etc'),也会失败。 生产环境建议配合
chroot或容器(如 Docker)做更彻底的隔离。
✅ 补充:Windows 下注意路径分隔符与特殊字符
- 统一用
/拼接路径(PHP 内部会自动适配 Windows) - 过滤非法字符(
:,,>,|,?,*,",),否则mkdir()直接返回false且无明确报错:
$cleanName = preg_replace('/[\\/:*?"|]/', '_', $rawName);
不复杂但容易忽略
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











