Skip to content
Advertisement

ZipArchive::addFile() creates zip files with tree structure in Windows but flattened in Linux

I used PHP’s ZipArchive library to create a zip file to easily transfer images for some e-shop synchronization service from a desktop to the web server of the e-shop. The script I used to create the zip is below:

function compress(string $path)
{
    $zip = new ZipArchive();
    $zip->open(dirname(SOURCE_PATH, 1) . '\' . explode('\', SOURCE_PATH)[count(explode('\', SOURCE_PATH)) - 2] . '.zip', ZipArchive::CREATE | ZipArchive::OVERWRITE); // Some path manipulation here, to actually take the whole "parent" folder of the path passed to the function's parameter

    $files = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($path), RecursiveIteratorIterator::LEAVES_ONLY);

    foreach ($files as $file) {
        if (!$file->isDir()) {
            $real = $file->getRealPath();
            $relative = substr($real, strlen($path));

            $zip->addFile($real, $relative);
        }
    }

    $zip->close();
}

My problem is that when you view the zip’s contents in WinRAR, they are shown normally as expected in folders; when you extract the zip, again the whole folder tree along with the files is built. But when you transfer the zip file to the linux server where the e-shop is hosted to and extract it, the files are all extracted in the folder where zip was uploaded, as if the zip file is “flattened”…

Please take a look at the two videos below:

In Windows

In Linux

What have I done wrong? It was the first time I used ZipArchive, so I don’t have much experience with it.

Advertisement

Answer

File path in zip must use / as path separator, you could try the code below

function compress(string $path)
{
    $zip = new ZipArchive();
    $zip->open(dirname(SOURCE_PATH, 1) . '\' . explode('\', SOURCE_PATH)[count(explode('\', SOURCE_PATH)) - 2] . '.zip', ZipArchive::CREATE | ZipArchive::OVERWRITE); // Some path manipulation here, to actually take the whole "parent" folder of the path passed to the function's parameter

    $files = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($path), RecursiveIteratorIterator::LEAVES_ONLY);

    foreach ($files as $file) {
        if (!$file->isDir()) {
            $real = $file->getRealPath();
            $relative = substr($real, strlen($path));
            // replace path separator
            $relative = str_replace('\', '/', $relative);
            $zip->addFile($real, $relative);
        }
    }

    $zip->close();
}
User contributions licensed under: CC BY-SA
10 People found this is helpful
Advertisement