php实现上传文件夹
上传文件夹的基本原理
PHP本身不支持直接上传整个文件夹,但可以通过前端选择文件夹后,将文件夹内的文件逐个上传。核心思路是使用HTML5的<input type="file" webkitdirectory>属性允许选择文件夹,再通过PHP逐个处理上传的文件。
前端实现方法
创建包含文件夹选择功能的HTML表单:
<form action="upload.php" method="post" enctype="multipart/form-data">
<input type="file" name="files[]" webkitdirectory directory multiple>
<input type="submit" value="上传文件夹">
</form>
webkitdirectory和directory属性让浏览器允许选择文件夹,multiple属性允许选择多个文件,files[]表示接收文件数组。
后端PHP处理
在upload.php中处理上传的文件:
if(isset($_FILES['files'])){
$uploadDir = 'uploads/';
foreach($_FILES['files']['name'] as $key => $name){
$tmpName = $_FILES['files']['tmp_name'][$key];
$error = $_FILES['files']['error'][$key];
if($error === UPLOAD_ERR_OK){
$targetPath = $uploadDir . $name;
move_uploaded_file($tmpName, $targetPath);
}
}
echo "文件夹上传完成";
}
保持目录结构
如果需要保留原始文件夹结构,可以从前端获取相对路径信息:
// 前端JavaScript获取文件相对路径
document.querySelector('input[type=file]').addEventListener('change', function(e){
for(let file of e.target.files){
console.log(file.webkitRelativePath);
}
});
修改PHP代码处理路径:
foreach($_FILES['files']['name'] as $key => $name){
$relativePath = $_POST['relative_path'][$key]; // 需要前端传递
$fullPath = $uploadDir . $relativePath;
// 创建不存在的目录
$dirPath = dirname($fullPath);
if(!is_dir($dirPath)){
mkdir($dirPath, 0777, true);
}
move_uploaded_file($_FILES['files']['tmp_name'][$key], $fullPath);
}
安全性考虑
验证文件类型和大小:
$allowedTypes = ['image/jpeg', 'application/pdf'];
$maxSize = 5 * 1024 * 1024; // 5MB
foreach($_FILES['files']['name'] as $key => $name){
$type = $_FILES['files']['type'][$key];
$size = $_FILES['files']['size'][$key];
if(!in_array($type, $allowedTypes) || $size > $maxSize){
continue; // 跳过不符合要求的文件
}
// 处理上传
}
进度显示实现
使用AJAX上传可以显示进度:
// 前端使用FormData和XMLHttpRequest
let formData = new FormData();
for(let file of files){
formData.append('files[]', file);
}
let xhr = new XMLHttpRequest();
xhr.upload.addEventListener('progress', function(e){
let percent = Math.round((e.loaded / e.total) * 100);
console.log(percent + '%');
});
xhr.open('POST', 'upload.php');
xhr.send(formData);
大文件分块上传
对于大文件夹,可以考虑分块上传:
// 前端将大文件分块
const CHUNK_SIZE = 5 * 1024 * 1024; // 5MB每块
let start = 0;
while(start < file.size){
let chunk = file.slice(start, start + CHUNK_SIZE);
formData.append('chunks[]', chunk);
start += CHUNK_SIZE;
}
PHP端需要合并分块:
// 根据文件名合并分块
$targetFile = $uploadDir . $fileName;
file_put_contents($targetFile, file_get_contents($chunkPath), FILE_APPEND);
以上方法实现了文件夹上传的基本功能,包括目录结构保持、安全验证和进度显示等扩展功能。







