Search code examples
phpdownloadzipdocument-root

How to download zip file without downloading entire directory path too? (PHP)


I have the following zip download function:

$file='myStuff.zip';
function downloadZip($file){
  $file=$_SERVER["DOCUMENT_ROOT"].'/uploads/'.$file;
   if (headers_sent()) {
    echo 'HTTP header already sent';
   } 
       else {
        if (!is_file($file)) {
            header($_SERVER['SERVER_PROTOCOL'].' 404 Not Found');
            echo 'File not found';
        } else if (!is_readable($file)) {
            header($_SERVER['SERVER_PROTOCOL'].' 403 Forbidden');
            echo 'File not readable';
        } else {
            header($_SERVER['SERVER_PROTOCOL'].' 200 OK');
            header("Content-Type: application/zip");
            header("Content-Transfer-Encoding: Binary");
            header("Content-Length: ".filesize($file));
            header("Content-Disposition: attachment; filename=\"".basename($file)."\"");
            readfile($file);
            exit;
        }
    }
}

The problem is when I call this function, I end up downloading not just myStuff.zip, but the complete directory path with all the folders. I'm on a Mac using XAMPP so this means I get the following:

/applications/xampp/htdocs/uploads/myStuff.zip

meaning i get a folder called applications with all the subfolders and then inside all of them I get myStuff.zip.

How can I just download myStuff.zip without its directories?


Solution

  • Ok, I answered my own question by using the code in this link: http://www.travisberry.com/2010/09/use-php-to-zip-folders-for-download/

    Here's the PHP:

    <?php
    //Get the directory to zip
    $filename_no_ext= $_GET['directtozip'];
    
    // we deliver a zip file
    header("Content-Type: archive/zip");
    
    // filename for the browser to save the zip file
    header("Content-Disposition: attachment; filename=$filename_no_ext".".zip");
    
    // get a tmp name for the .zip
    $tmp_zip = tempnam ("tmp", "tempname") . ".zip";
    
    //change directory so the zip file doesnt have a tree structure in it.
    chdir('user_uploads/'.$_GET['directtozip']);
    
    // zip the stuff (dir and all in there) into the tmp_zip file
    exec('zip '.$tmp_zip.' *');
    
    // calc the length of the zip. it is needed for the progress bar of the browser
    $filesize = filesize($tmp_zip);
    header("Content-Length: $filesize");
    
    // deliver the zip file
    $fp = fopen("$tmp_zip","r");
    echo fpassthru($fp);
    
    // clean up the tmp zip file
    unlink($tmp_zip);
    ?>
    

    and the HTML:

    <a href="zip_folders.php?directtozip=THE USERS DIRECTORY">Download All As Zip</a>
    

    The key step in getting rid of the directory structure appears to be the chdir(). It is also worth noting that the script in this answer makes the zip file on the fly rather than trying to retrieve a previously zipped file as I did in my question.