tinyfilemanager icon indicating copy to clipboard operation
tinyfilemanager copied to clipboard

Fix multiple download and browse while download

Open vadasziattila opened this issue 1 year ago • 5 comments

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]

vadasziattila avatar Oct 15 '24 22:10 vadasziattila

@ner00 can you review this PR.

prasathmani avatar Oct 16 '24 04:10 prasathmani

@ner00 can you review this PR.

Looks good, works nicely. Thanks @vadasziattila!

ner00 avatar Oct 16 '24 20:10 ner00

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);
}

ner00 avatar Oct 16 '24 21:10 ner00

@vadasziattila Download is not working when select the folder

prasathmani avatar Oct 19 '24 06:10 prasathmani

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));
}

ner00 avatar Oct 19 '24 13:10 ner00