5

Can I zip files using relative paths?

For example:

$zip->addFile('c:/wamp/www/foo/file.txt');

the ZIP should have a directory structure like:

foo
 -> file.txt

and not:

wamp
 -> www
     -> foo
         -> file.txt

like it is by default...

ps: my full code is here (I'm using ZipArchive to compress contents of a directory into a zip file)

Community
  • 1
  • 1
Alex
  • 66,732
  • 177
  • 439
  • 641

3 Answers3

10

See the addFile() function definition, you can override the archive filename:

$zip->addFile('/path/to/index.txt', 'newname.txt');
Alex Howansky
  • 50,515
  • 8
  • 78
  • 98
  • oh tx. How can I do the same with empty directories? It looks like the addEmptyDir function doesn't have that 2nd argument? – Alex Oct 15 '12 at 19:15
  • 1
    Just pass the new destination name. I.e., if your source is /path/to/empty then just call `$zip->addEmptyDir("empty");` – Alex Howansky Oct 15 '12 at 19:16
4

If you are trying to recursively add all subfolders and files of a folder, you can try the code below (I modified this code/note in the php manual).

class Zipper extends ZipArchive {
    public function addDir($path, $parent_dir = '') {
        if($parent_dir != ''){
            $this->addEmptyDir($parent_dir);
            $parent_dir .= '/';
            print '<br>adding dir ' . $parent_dir . '<br>';
        }
        $nodes = glob($path . '/*');
        foreach ($nodes as $node) {
            if (is_dir($node)) {
                $this->addDir($node, $parent_dir.basename($node));
            }
            else if (is_file($node))  {
                $this->addFile($node, $parent_dir.basename($node));
                print 'adding file '.$parent_dir.basename($node) . '<br>';
            }
        }
    }
} // class Zipper

So basically what this does is it does not include the directories (absolute path) before the actual directory/folder that you want zipped but instead only starts from the actual folder (relative path) you want zipped.

Paolo
  • 390
  • 2
  • 5
  • 20
  • Thank's this works greatly! Better than any other code snippet I have ever seen to recursively zip current folder using PHP. – gaborous Dec 12 '14 at 04:20
  • In fact this solution doesn't store dot files (like .htaccess) because GLOB filters them automatically. There's a workaround for GLOB but you can also use scandir() or opendir(), which in fact are faster. I'll post a code below. – gaborous Dec 12 '14 at 18:03
  • I already posted just below but don't change your answer, it's already perfect and my answer is just a follow-up from yours :) – gaborous Dec 15 '14 at 15:07
  • Ah right! I didn't notice your post above/below. Thanks for the additional info. – Paolo Dec 15 '14 at 15:57
1

Here is a modified version of Paolo's script in order to also include dot files like .htaccess, and it should also be a bit faster since I replaced glob by opendir as adviced here.

<?php

$password = 'set_a_password'; // password to avoid listing your files to anybody

if (strcmp(md5($_GET['password']), md5($password))) die();

// Make sure the script can handle large folders/files
ini_set('max_execution_time', 600);
ini_set('memory_limit','1024M');

//path to directory to scan
if (!empty($_GET['path'])) {
    $fullpath = realpath($_GET['path']); // append path if set in GET
} else { // else by default, current directory
    $fullpath = realpath(dirname(__FILE__)); // current directory where the script resides
}

$directory = basename($fullpath); // parent directry name (not fullpath)
$zipfilepath = $fullpath.'/'.$directory.'_'.date('Y-m-d_His').'.zip';

$zip = new Zipper();

if ($zip->open($zipfilepath, ZipArchive::CREATE)!==TRUE) {
    exit("cannot open/create zip <$zipfilepath>\n");
}

$past = time();

$zip->addDir($fullpath);

$zip->close();

print("<br /><hr />All done! Zipfile saved into ".$zipfilepath);
print('<br />Done in '.(time() - $past).' seconds.');

class Zipper extends ZipArchive { 

    // Thank's to Paolo for this great snippet: http://stackoverflow.com/a/17440780/1121352
    // Modified by LRQ3000
    public function addDir($path, $parent_dir = '') {
        if($parent_dir != '' and $parent_dir != '.' and $parent_dir != './') {
            $this->addEmptyDir($parent_dir);
            $parent_dir .= '/';
            print '<br />--> ' . $parent_dir . '<br />';
        }

        $dir = opendir($path);
        if (empty($dir)) return; // skip if no files in folder
        while(($node = readdir($dir)) !== false) {
            if ( $node == '.' or $node == '..' ) continue; // avoid these special directories, but not .htaccess (except with GLOB which anyway do not show dot files)
            $nodepath = $parent_dir.basename($node); // with opendir
            if (is_dir($nodepath)) {
                $this->addDir($nodepath, $parent_dir.basename($node));
            } elseif (is_file($nodepath)) {
                $this->addFile($nodepath, $parent_dir.basename($node));
                print $parent_dir.basename($node).'<br />';
            }
        }
    }
} // class Zipper 

?>

This is a standalone script, just copy/paste it into a .php file (eg: zipall.php) and open it in your browser (eg: zipall.php?password=set_a_password , if you don't set the correct password, the page will stay blank for security). You must use a FTP account to retrieve the zip file afterwards, this is also a security measure.

gaborous
  • 15,832
  • 10
  • 83
  • 102