Reputation: 113
I got this code for Upload multiple files but now I don't know how can I upload a folder with multiple files and maybe subfolder with more files. etc As you can see I'm using javscript for getting and php for procesing and saving the files right now with files around 2MB I was trying to get like $_Folder with a foreach but it doesn't work for me :/
Index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Upload Files</title>
</head>
<body>
<form method="post" enctype="multipart/form-data">
<input type="file" name="files[]" multiple>
<input type="submit" value="Upload File" name="submit">
</form>
<script src="upload.js"></script>
</body>
</html>
process.php
<?php
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
if (isset($_FILES['files'])) {
$errors = [];
$path = 'uploads/';
$extensions = ['jpg', 'jpeg', 'png', 'gif'];
$all_files = count($_FILES['files']['tmp_name']);
for ($i = 0; $i < $all_files; $i++) {
$file_name = $_FILES['files']['name'][$i];
$file_tmp = $_FILES['files']['tmp_name'][$i];
$file_type = $_FILES['files']['type'][$i];
$file_size = $_FILES['files']['size'][$i];
$file_ext = strtolower(end(explode('.', $_FILES['files']['name'][$i])));
$file = $path . $file_name;
if (!in_array($file_ext, $extensions)) {
$errors[] = 'Extension not allowed: ' . $file_name . ' ' . $file_type;
}
if ($file_size > 2097152) {
$errors[] = 'File size exceeds limit: ' . $file_name . ' ' . $file_type;
}
if (empty($errors)) {
move_uploaded_file($file_tmp, $file);
}
}
if ($errors) print_r($errors);
}
}
upload.js
const url = 'process.php';
const form = document.querySelector('form');
form.addEventListener('submit', e => {
e.preventDefault();
const files = document.querySelector('[type=file]').files;
const formData = new FormData();
for (let i = 0; i < files.length; i++) {
let file = files[i];
formData.append('files[]', file);
}
fetch(url, {
method: 'POST',
body: formData
}).then(response => {
console.log(response);
});
});
Expecting to Upload something like this
Upload:
-(1Folder)
--Image.png
--Imagen.jpg
--(2Folder)
---Image2.png
--(3Folder)
---Image3.jpg
--Imagen.gif
Upvotes: 6
Views: 8900
Reputation: 42736
In modern Chrome, Firefox, and Edge you can set a html attribute, webkitdiretory
to let the file input become a directory select window instead. And if you also use the multiple
attribute after selecting the folder all contents (and contents in subfolders) will be in the .files
list
<input type="file" webkitdirectory multiple>
You would then just use the same code to include all the files for upload.
Now if you want to keep the folder structure you would have to also include the webkitRelativePath
which holds the relative path for that file within the folder you selected. And use that path to create the folders on the server.
for (let i = 0; i < files.length; i++) {
let file = files[i];
let fileParamName = `file${i}`;
let filePathParamName = `filepath${i}`;
formData.append(fileParamName, file);
formData.append(filePathParamName,file.webkitRelativePath);
}
And then on the server use filePathParamName to make the directory structure and move the file to it:
//Just for example
//make sure to used sanitized data in production
$folderpath = $path.dirname($_POST["filepath23"]);
$file = $path.$_POST["filepath23"];
$file_tmp = $_FILES["file23"]["tmp_name"];
//third option is for recursive folder creation (make subfolders)
mkdir($path,0644,true);
move_uploaded_file($file_tmp, $file)
For an easier method you could put all the files into a zip file within javascript and just upload the single zip file and extract on the server. Using JSZip and PHP ZipArchive class:
var zip = new JSZip();
for (let i = 0; i < files.length; i++) {
let file = files[i];
zip.file(file.webkitRelativePath, file);
}
zip.generateAsync({type:"blob"})
.then(function(content) {
formData.append("folderzip",content);
fetch(url, {
method: 'POST',
body: formData
}).then(response => {
console.log(response);
});
});
Then in php unzip the folder to where you want it:
move_uploaded_file($file_tmp, $path);
$zip = new ZipArchive();
if($zip->open($path)){
$zip->extractTo($somepath);
$zip->close();
//delete zip file
unlink($path);
}
Client side demo of file listing using webkitRelativePath:
var output = document.querySelector("#output");
document.querySelector("input").onchange = function() {
var files = this.files;
for (file of files) {
output.insertAdjacentHTML('beforeend', `<div>${file.webkitRelativePath}</div>`);
}
}
<input type="file" webkitdirectory multiple>
<div id="output"></div>
Upvotes: 10