Fix multiple download and browse while download
this change resolves #744 by adding the option to able to download multiple files, folders and browse while downloading. Signed-off-by: Vadászi Attila [email protected]
@ner00 can you review this PR.
@ner00 can you review this PR.
Looks good, works nicely. Thanks @vadasziattila!
I just have one question, maybe you guys can help me out. I always used FM_Zipper because it was already there and I customized it to a specific compression level... I'm having trouble doing the same for the code in this PR. Here's an example:
// Add the file to the ZIP archive
$zip->addFile($new_path, basename($new_path));
$zip->setCompressionName($f, ZipArchive::CM_STORE); // Setting 'Store' as compression level
This works, but if I have sub-folders with other files, those files will always be compressed as Deflate instead of Store. I've been trying to understand why the files in the sub-folders do not respect the setCompressionName.
EDIT: I think I figured it out, the first foreach that recurses through files and folders goes like this:
if (is_file($fullPath)) {
// Add the file to the ZIP archive
$zipArchive->addFile($fullPath, $zipPath . '/' . $file);
$zipArchive->setCompressionName($zipPath . '/' . $file, ZipArchive::CM_STORE);
}
@vadasziattila Download is not working when select the folder
Download is not working when select the folder
It's definitely working on my end, either only files or only folders, or both. Are we testing the same code even?
Here in full:
// Mass downloading
if (isset($_POST['group'], $_POST['download'], $_POST['token']) && !FM_READONLY) {
// Verify token to ensure it's valid
if (!verifyToken($_POST['token'])) {
fm_set_msg(lng("Invalid Token."), 'error');
exit;
}
$path = FM_ROOT_PATH;
if (FM_PATH != '') {
$path .= '/' . FM_PATH;
}
$errors = 0;
$files = $_POST['file']; // List of selected files and folders
if (is_array($files) && count($files)) {
// Create a new ZIP archive
$zip = new ZipArchive();
$zip_filename = 'download_' . date('Y-m-d_H-i-s') . '.zip';
$zip_filepath = sys_get_temp_dir() . '/' . $zip_filename;
if ($zip->open($zip_filepath, ZipArchive::CREATE) !== TRUE) {
fm_set_msg(lng('Cannot create ZIP file'), 'error');
$FM_PATH = FM_PATH;
fm_redirect(FM_SELF_URL . '?p=' . urlencode($FM_PATH));
}
// Function to recursively add folders and files to the ZIP archive, including empty folders
function addFolderToZip($folderPath, $zipArchive, $zipPath) {
$files = scandir($folderPath);
// Ensure the folder itself is added to the ZIP (even if empty)
$zipArchive->addEmptyDir($zipPath);
foreach ($files as $file) {
if ($file == '.' || $file == '..') continue;
$fullPath = $folderPath . '/' . $file;
if (is_file($fullPath)) {
// Add the file to the ZIP archive
$zipArchive->addFile($fullPath, $zipPath . '/' . $file);
} elseif (is_dir($fullPath)) {
// Recursively add folders (including empty folders)
addFolderToZip($fullPath, $zipArchive, $zipPath . '/' . $file);
}
}
}
foreach ($files as $f) {
if ($f != '') {
$new_path = $path . '/' . fm_clean_path($f); // Sanitize the file path
if (is_file($new_path)) {
// Add the file to the ZIP archive
$zip->addFile($new_path, basename($new_path));
} elseif (is_dir($new_path)) {
// Add the folder and its contents to the ZIP archive (including empty folders)
addFolderToZip($new_path, $zip, basename($new_path));
} else {
$errors++;
}
}
}
// Close the ZIP archive
$zip->close();
// Check for errors
if ($errors == 0) {
// Serve the ZIP file for download
if (file_exists($zip_filepath)) {
header('Content-Type: application/zip');
header('Content-Disposition: attachment; filename="' . $zip_filename . '"');
header('Content-Length: ' . filesize($zip_filepath));
readfile($zip_filepath);
// Remove the ZIP file from the temporary directory after download
unlink($zip_filepath);
exit;
} else {
fm_set_msg(lng('Error creating ZIP file'), 'error');
}
} else {
fm_set_msg(lng('Error while adding items to ZIP'), 'error');
}
} else {
fm_set_msg(lng('Nothing selected'), 'alert');
}
$FM_PATH = FM_PATH;
fm_redirect(FM_SELF_URL . '?p=' . urlencode($FM_PATH));
}