63

I'm trying to use php to create a zip file (which it does - taken from this page - http://davidwalsh.name/create-zip-php), however inside the zip file are all of the folder names to the file itself.

Is it possible to just have the file inside the zip minus all the folders?

Here's my code:

function create_zip($files = array(), $destination = '', $overwrite = true) {

    if(file_exists($destination) && !$overwrite) { return false; };
    $valid_files = array();
    if(is_array($files)) {
        foreach($files as $file) { 
            if(file_exists($file)) { 
                $valid_files[] = $file;
            };
        };
    };
    if(count($valid_files)) { 
        $zip = new ZipArchive();
        if($zip->open($destination,$overwrite ? ZIPARCHIVE::OVERWRITE : ZIPARCHIVE::CREATE) !== true) { 
            return false;
        };
        foreach($valid_files as $file) { 
            $zip->addFile($file,$file);
        };
        $zip->close();
        return file_exists($destination);
    } else {
        return false;
    };

};


$files_to_zip = array('/media/138/file_01.jpg','/media/138/file_01.jpg','/media/138/file_01.jpg');

$result = create_zip($files_to_zip,'/...full_site_path.../downloads/138/138_files.zip');
SoulieBaby
  • 5,405
  • 25
  • 95
  • 145

4 Answers4

148

The problem here is that $zip->addFile is being passed the same two parameters.

According to the documentation:

bool ZipArchive::addFile ( string $filename [, string $localname ] )

filename
The path to the file to add.

localname
local name inside ZIP archive.

This means that the first parameter is the path to the actual file in the filesystem and the second is the path & filename that the file will have in the archive.

When you supply the second parameter, you'll want to strip the path from it when adding it to the zip archive. For example, on Unix-based systems this would look like:

$new_filename = substr($file,strrpos($file,'/') + 1);
$zip->addFile($file,$new_filename);
Nathan Osman
  • 71,149
  • 71
  • 256
  • 361
  • Strange that this identical problem has cropped up twice in two days... http://stackoverflow.com/questions/3988496/how-to-add-a-txt-file-and-create-a-zip-in-php/3989210#3989210 – Mark Baker Oct 22 '10 at 11:00
  • LOL popular question? strange. – SoulieBaby Oct 24 '10 at 21:29
  • 3
    Thanks Nathan, still useful 5 years later. The reason this popped up is we all grabbed the same ZipArchive script from the very popular David Walsh: https://davidwalsh.name/create-zip-php Which contains that issue :) – David G Mar 05 '16 at 13:44
  • 1
    For some reason, when I do this I get the files at both the base of the ZIP file and within their nested directory structure, which essentially causes all of the files to be there twice and double the size of the ZIP archive. Anyone else having this problem and found a solve? Thanks. – HartleySan Nov 29 '16 at 14:15
  • To expand on my previous comment a bit, I've just discovered that the exact same code causes the above problem in my dev environment, but not in my prod environment. In my prod environment, it works as expected without the duplication of files in the nested directory structure. Could this be a PHP environment variable causing this issue? – HartleySan Nov 29 '16 at 14:24
  • I had the same issue as HartleySan resolved by using a different method all together similar to CarlosEvora – FreeSoftwareServers Feb 25 '17 at 21:35
  • 2
    @HartleySan, it's because the ZIP was created before and it's being opened to be extended with the new files without path. Try deleting the ZIP first and you won't get both files with and without path. – sergio Jun 27 '17 at 09:19
57

I think a better option would be:

$zip->addFile($file,basename($file));

Which simply extracts the filename from the path.

Carlos Évora
  • 571
  • 4
  • 2
0

This is just another method that I found that worked for me

$zipname = 'file.zip';
$zip = new ZipArchive();
$tmp_file = tempnam('.','');
$zip->open($tmp_file, ZipArchive::CREATE);
$download_file = file_get_contents($file);
$zip->addFromString(basename($file),$download_file);
$zip->close();
header('Content-disposition: attachment; filename='.$zipname);
header('Content-type: application/zip');
readfile($tmp_file);
FreeSoftwareServers
  • 2,271
  • 1
  • 33
  • 57
0

I use this to remove root folder from zip

D:\xampp\htdocs\myapp\assets\index.php

wil be in zip:

assets\index.php

our code:

echo $main_path = str_replace("\\", "/", __DIR__ );// get current folder, which call scipt
$zip_file = 'myapp.zip';

if (file_exists($main_path) && is_dir($main_path))  
{
    $zip = new ZipArchive();

    if (file_exists($zip_file)) {
        unlink($zip_file); // truncate ZIP
    }
    if ($zip->open($zip_file, ZIPARCHIVE::CREATE)!==TRUE) {
        die("cannot open <$zip_file>\n");
    }

    $files = 0;
    $paths = array($main_path);
    while (list(, $path) = each($paths))
    {
        foreach (glob($path.'/*') as $p)
        {
            if (is_dir($p)) {
                $paths[] = $p;
            } else {
                // special here: we remove root folder ("D:\xampp\htdocs\myapp\") :D
                $new_filename = str_replace($main_path."/" , "", $p);
                $zip->addFile($p, $new_filename);
                $files++;

                echo $p."<br>\n";
            }
        }
    }

    echo 'Total files: '.$files;

    $zip->close();
}
Hoàng Vũ Tgtt
  • 1,863
  • 24
  • 8