php 7.4 可通过 webkitdirectory 属性+js 实现文件夹批量上传,后端用相对路径重建目录结构并安全保存;下载支持单文件直传和 zip 打包整目录。

PHP 7.4 本身不支持浏览器端直接上传整个文件夹(这是浏览器安全限制,不是 PHP 的问题),但可以通过 HTML5 的 webkitdirectory 属性 + JavaScript 配合 PHP 实现「模拟文件夹批量上传」。下载功能则由 PHP 后端控制文件流输出即可。下面是一套完整、可运行的实现方案。
一、前端:启用文件夹选择并递归收集文件
现代 Chrome、Edge、Opera 支持 webkitdirectory 属性,允许用户选择一个文件夹,浏览器会自动列出其下所有文件(不含子文件夹元信息,但含完整路径字符串)。
注意:Firefox 不支持该属性;Safari 仅部分支持且行为不稳定,生产环境建议降级为多文件选择(multiple)作为兜底。
示例 HTML + JS:
<input type="file" id="folderInput" webkitdirectory directory multiple><button onclick="uploadFiles()">上传所有文件</button>
<div id="log"></div>
<script>
const input = document.getElementById('folderInput');
const log = document.getElementById('log');
input.addEventListener('change', function(e) {
const files = Array.from(e.target.files);
log.innerHTML = `共选中 ${files.length} 个文件`;
});
async function uploadFiles() {
const files = Array.from(input.files);
if (files.length === 0) return;
const formData = new FormData();
files.forEach(file => {
// 关键:保留原始相对路径(如 folder/sub/a.txt),用于后端重建目录结构
const relativePath = file.webkitRelativePath || file.name;
formData.append('files[]', file, relativePath); // 第三个参数设为自定义文件名(含路径)
});
const res = await fetch('upload.php', {
method: 'POST',
body: formData
});
const result = await res.json();
alert(result.message || '上传完成');
}
</script>
二、后端:PHP 7.4 接收并按路径保存文件(支持文件夹结构)
PHP 不解析 webkitRelativePath,但你已通过 formData.append(..., relativePath) 把路径传进来了。服务端需从 $_FILES['files']['name'] 中提取该路径,并安全地创建子目录、写入文件。
⚠️ 安全重点:必须过滤路径遍历(../)、禁止绝对路径、限定根目录范围。
完整 upload.php 示例:
<?php header('Content-Type: application/json; charset=utf-8');
$uploadRoot = __DIR__ . '/uploads'; // 所有上传文件存到此目录下
if (!is_dir($uploadRoot)) mkdir($uploadRoot, 0755, true);
if ($_SERVER['REQUEST_METHOD'] !== 'POST' || !isset($_FILES['files'])) {
die(json_encode(['error' => '非法请求']));
}
$files = $_FILES['files'];
$uploaded = [];
$errors = [];
// 处理每个文件
for ($i = 0; $i $uploaded,
'count' => count($uploaded),
'errors' => $errors,
'message' => empty($errors) ? "成功上传 {$uploaded} 个文件" : '部分上传失败'
];
echo json_encode($response, JSON_UNESCAPED_UNICODE);
?>
三、下载功能:单文件下载 & 文件夹打包下载(zip)
单文件下载直接用 readfile();整文件夹下载需用 PHP 的 ZipArchive 扩展(PHP 7.4 默认启用)动态打包。
✅ 示例:download.php —— 支持下载单个文件或指定路径下的全部内容(自动 zip):
<?php $baseDir = __DIR__ . '/uploads';
$path = $_GET['path'] ?? '';
// 安全校验:只允许相对路径,禁止 ../ 和绝对路径
$path = trim($path, '/\');
if (empty($path) || str_contains($path, '..') || str_starts_with($path, '/')) {
die('非法路径');
}
$fullPath = $baseDir . '/' . $path;
if (!is_dir($fullPath) && !is_file($fullPath)) {
die('文件或目录不存在');
}
// 情况1:下载单个文件
if (is_file($fullPath)) {
$filename = basename($fullPath);
header('Content-Type: application/octet-stream');
header("Content-Disposition: attachment; filename="{$filename}"");
header('Content-Length: ' . filesize($fullPath));
readfile($fullPath);
exit;
}
// 情况2:打包整个文件夹(含子目录)
$zip = new ZipArchive();
$tmpZip = tempnam(sys_get_temp_dir(), 'folder_') . '.zip';
if ($zip->open($tmpZip, ZipArchive::CREATE) !== TRUE) {
die('无法创建 ZIP 文件');
}
$iterator = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($fullPath),
RecursiveIteratorIterator::LEAVES_ONLY
);
foreach ($iterator as $file) {
if ($file->isFile()) {
$relPath = substr($file->getPathname(), strlen($fullPath) + 1);
$zip->addFile($file->getPathname(), $relPath);
}
}
$zip->close();
header('Content-Type: application/zip');
header("Content-Disposition: attachment; filename="{$path}.zip"");
header('Content-Length: ' . filesize($tmpZip));
readfile($tmpZip);
unlink($tmpZip); // 下载完立即清理临时文件
exit;
?>
调用方式:
- 下载单个文件:
download.php?path=report.pdf - 下载整个文件夹:
download.php?path=project/src
四、补充说明与注意事项
• 浏览器兼容性:仅 Chromium 内核浏览器(Chrome ≥ 19、Edge ≥ 79)稳定支持 webkitdirectory。Firefox 可用第三方库(如 react-dropzone 的文件夹拖拽)配合后端解析,但非原生。
• 大文件/大量文件:建议增加分片上传逻辑(如使用 tus-js-client),避免超时和内存溢出。PHP 需调整 upload_max_filesize、post_max_size、max_execution_time 等配置。
• 权限与安全:上传目录不要放在 Web 可访问路径下(如 /uploads 应置于 public_html 外);若必须 Web 访问,请配合 .htaccess 或 Nginx 配置禁止执行 PHP;对 ZIP 下载做白名单扩展名过滤更稳妥。
• 中文路径支持:PHP 7.4 在 Linux 下默认 UTF-8,Windows 需确认 locale;前端传参时 URL 编码已由浏览器自动处理,无需额外 encodeURI。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











