1
//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('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
header('Content-Length: ' . filesize($file)); 
// deliver the zip file
$fp = fopen("$tmp_zip","r");
echo fpassthru($fp);
// clean up the tmp zip file
unlink($tmp_zip);

This following code creates me blank zip files.

This is my ip localhostfilemanager/zip_folder.php?directtozip=Screenshots

Directory tree

Screenshots
- Image.jpg
Uploads
^Screenshots
- Image.jpg

And it basically doesn't get any of those files. Why is that? I search recently nearly all codes in google and the codes which worked wasn't based with header output just creating the zip in a directory ./ . Could you provide me with a working code im hopeless :(

3 Answers3

2

copy all your files into a temp location then use this to create a zip file of your temp folder then delete your temp folder

/** 
* Function will recursively zip up files in a directory and all sub directories / files in the specified source
* @param - $source - directory that you want contents of zipping - note does NOT zip primary directory only files and folders within directory
* @param - $destination - filepath and filename you are storing your created zip files in (could also be used to stream files down using the correct stream headers) eg: "/createdzips/zippy.zip"
* @return nothing - nada - null - zero - zilch - zip :)
*/
function zipcreate($source, $destination) {
    if (!extension_loaded('zip') || !file_exists($source)) {
        return false;
    }
    $zip = new ZipArchive();
    if (!$zip->open($destination, ZIPARCHIVE::CREATE)) {
        return false;
    }
    $source = str_replace('\\', '/', realpath($source));
    if (is_dir($source) === true) {
        $files = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($source), RecursiveIteratorIterator::SELF_FIRST);
        foreach ($files as $file) {
            $file = str_replace('\\', '/', realpath($file));
            if (is_dir($file) === true) {
                $zip->addEmptyDir(str_replace($source . '/', '', $file . '/'));
            } else if (is_file($file) === true) {
                $zip->addFromString(str_replace($source . '/', '', $file), file_get_contents($file));
            }
        }
    } else if (is_file($source) === true) {
        $zip->addFromString(basename($source), file_get_contents($source));
    }
    return $zip->close();
}

zipcreate("c:/xampp/htdocs/filemanager/Screenshots", "c:/xampp/htdocs/filemanager/uploads/screenshots.zip");


header("Content-Description: File Transfer");
header("Content-type: application/octet-stream");
header("Content-Disposition: attachment; filename=\"c:/xampp/htdocs/filemanager/uploads/screenshots.zip\"");
header("Content-Transfer-Encoding: binary");
header("Content-Length: ".filesize("c:/xampp/htdocs/filemanager/uploads/screenshots.zip"));
Dave
  • 3,280
  • 2
  • 22
  • 40
  • zipcreate("zip.zip", "/Screenshots"); and did nothing. – user2945583 Nov 01 '13 at 16:31
  • @user2945583 its `zipcreate($source, $destination)` not `zipcreate($destination, $source)` – Lawrence Cherone Nov 01 '13 at 16:33
  • needs a complete filesystem path so if your screen shots folder lives at /home/user/www/Screenshots/ then you'd pass it in `zipcreate("/home/user/www/Screenshots","/tmp/screenshots.zip");` – Dave Nov 01 '13 at 16:33
  • I refresh the page and nothing happens why is that so? zipcreate("/Screenshots", "zip.zip"); – user2945583 Nov 01 '13 at 16:34
  • or `zipcreate("./Screenshots","./screenshots.zip");` ;p – Lawrence Cherone Nov 01 '13 at 16:34
  • Your web server user does have permission to write to the folder doesn't it ? it can't save the output zip file location if the web server cannot write to the destination location – Dave Nov 01 '13 at 16:35
  • It stores but the zip contains C: (file/icon) don't know why :o but the rest is good – user2945583 Nov 01 '13 at 16:40
  • it'll recursively save anything under the screenshots folder including all the other files/folders even hidden stuff etc. post the exact creation call you're using including the paths and the full path to the c: (file/icon) as I have no idea what that is and we can work it out from there. – Dave Nov 01 '13 at 16:41
  • Its [ZIP] [DIR]Screenshots [INSIDE DIR]- Image.jpg C: – user2945583 Nov 01 '13 at 16:43
  • That makes no sense to me in the slightest any chance of a screenshot or something to describe it better? It should just create a .zip file with the contents of your folder that you requested zipping it shouldn't touch the c: folder or anything like that unless that is inside the path you told it to zip. – Dave Nov 01 '13 at 16:47
  • Sure check this all linked nicely http://oi44.tinypic.com/mj5xj9.jpg – user2945583 Nov 01 '13 at 16:52
  • Right give me 2 minutes I'll alter code above for you – Dave Nov 01 '13 at 16:57
  • Delete all the existing created files etc and use the code posted above that should work for you hopefully – Dave Nov 01 '13 at 17:01
  • This is frustrating.. – user2945583 Nov 01 '13 at 17:25
  • I'm fresh out of idea's then since this code works fine on 4 webservers and my local server although they're all unix machines could be something specific to xampp/windows I don't know about ? you do have the zip module enabled for php don't you ? – Dave Nov 01 '13 at 17:26
  • Not quite sure where to check it. But since it created me previously zips does it mean it could be off? – user2945583 Nov 01 '13 at 17:58
  • if it created zips before its probably on then not sure why the code isn't working properly for you though – Dave Nov 01 '13 at 17:59
  • header("Content-Disposition: attachment; filename=\"c:/xampp/htdocs/filemanager/uploads/screenshots.zip"\"); this line makes a error due to \ – user2945583 Nov 01 '13 at 18:10
  • yeah i've fixed that line now I just copy and pasted that bit from below – Dave Nov 01 '13 at 18:25
  • Still nothing : zip name c--xampp-htdocs-filemanager-uploads-screenshots.zip – user2945583 Nov 01 '13 at 18:30
  • It works without the headers so :/ – user2945583 Nov 01 '13 at 18:34
  • Ok it works but now : Fatal error: Maximum execution time of 60 seconds exceeded in C:\xampp\htdocs\filemanager\zip_folder.php on line 26 The zip created ( didn't send to header cause of the error ) Zip size 480mb It sends to header smaller zipped files. Any solutions? – user2945583 Nov 01 '13 at 18:53
  • increase the page time out header with something like set_timeout(6000) its because the file is huge. Rather than streaming it down tbh you're probably better just saving it to the filesystem then creating a normal href link Click Here to Download type thing – Dave Nov 02 '13 at 11:13
1

Why not try the ZipArchive library

<?php
$zip = new ZipArchive;
$filename = "text.zip";
$filepath = "path/to/zip";
if ($zip->open('test.zip') === TRUE) {
    $zip->addFile('/path/to/index.txt', 'newname.txt');
    $zip->close();
    header("Content-Description: File Transfer");
    header("Content-type: application/octet-stream");
    header("Content-Disposition: attachment; filename=\".$filename."\");
    header("Content-Transfer-Encoding: binary");
    header("Content-Length: ".filesize($filepath.$filename));
} else {
    echo 'failed';
}
?>

Its older but for what you're trying to do, it is much cleaner.

Zip a folder (include itself). Usage: HZip::zipDir('/path/to/sourceDir', '/path/to/out.zip');

<?php 
class HZip 
{ 
  /** 
   * Add files and sub-directories in a folder to zip file. 
   * @param string $folder 
   * @param ZipArchive $zipFile 
   * @param int $exclusiveLength Number of text to be exclusived from the file path. 
   */ 
  private static function folderToZip($folder, &$zipFile, $exclusiveLength) { 
    $handle = opendir($folder); 
    while (false !== $f = readdir($handle)) { 
      if ($f != '.' && $f != '..') { 
        $filePath = "$folder/$f"; 
        // Remove prefix from file path before add to zip. 
        $localPath = substr($filePath, $exclusiveLength); 
        if (is_file($filePath)) { 
          $zipFile->addFile($filePath, $localPath); 
        } elseif (is_dir($filePath)) { 
          // Add sub-directory. 
          $zipFile->addEmptyDir($localPath); 
          self::folderToZip($filePath, $zipFile, $exclusiveLength); 
        } 
      } 
    } 
    closedir($handle); 
  } 

  /** 
   * Zip a folder (include itself). 
   * Usage: 
   *   HZip::zipDir('/path/to/sourceDir', '/path/to/out.zip'); 
   * 
   * @param string $sourcePath Path of directory to be zip. 
   * @param string $outZipPath Path of output zip file. 
   */ 
  public static function zipDir($sourcePath, $outZipPath) 
  { 
    $pathInfo = pathInfo($sourcePath); 
    $parentPath = $pathInfo['dirname']; 
    $dirName = $pathInfo['basename']; 

    $z = new ZipArchive(); 
    $z->open($outZipPath, ZIPARCHIVE::CREATE); 
    $z->addEmptyDir($dirName); 
    self::folderToZip($sourcePath, $z, strlen("$parentPath/")); 
    $z->close(); 
  } 
} 
?>

as per Usage: Methods are static so you dont need to instantiate an option like in the first example, just call the function direct using heirarchical operators

HZip::zipDir('/path/to/sourceDir', '/path/to/out.zip');
hammus
  • 2,602
  • 2
  • 19
  • 37
  • Well firstly I want get a whole directory. And it has to be sent in a header. Cause I know that this kind without headers work for me. Its because Im creating like 300mb zip's that have a lot of files and it simply crashes the site ( somehow ) - to a white page but it generated the zip thats why I need a header sent – user2945583 Nov 01 '13 at 16:19
  • Yes its working but I need a header:( to send it directly into browser – user2945583 Nov 01 '13 at 16:24
  • try header('Content-type: application/zip'); instead of archive/zip – hammus Nov 01 '13 at 16:31
  • Could you add that on the code? Im not quite confident placing it. – user2945583 Nov 01 '13 at 16:33
  • added an octet stream header as its a bit more flexible and a few more headers. this should work fine – hammus Nov 01 '13 at 16:36
  • Im using @Dave's script and I added header('Content-type: octet/stream'); zipcreate("./uploads","./screenshots.zip"); Why it returns me zip_folder.php not a zip? – user2945583 Nov 01 '13 at 16:42
0

Two points to note 1. User -r in your exec , if you want to include the subdirectories as well. 2. replace * with . in your exec command and it will zip.

Althaf M
  • 498
  • 4
  • 12