Search code examples
phpphp-ziparchive

zip with ZipArchive to PPTX errors


Got a bit of a weird problem.

I have a folder with PowerPoint data that I need to zip and then rename to pptx. If I manually create a .zip and copy the files into it, then rename, it works like expected, but when I use ZipArchive to archive the data and then rename the created file, it doesn't work.

The programmatically created archive is also a few kB smaller than the manually created one. Archive comparison tools tell me that I've got the exact same files in both zips, including hidden files.

But here is where it gets really weird: if I make another, empty archive, then copy-paste the files from the programmatically created archive with a simple select, drag and drop, that new archive will work when renamed to a .pptx and has the same size as the first manually created file.

    $dir = 'pptx/test/compiled';
    $zip_file = 'pptx/test/file.zip';

    // Get real path for our folder
    $rootPath = realpath($dir);

    // Initialize archive object
    $zip = new \ZipArchive();
    $zip->open($zip_file, \ZipArchive::CREATE | \ZipArchive::OVERWRITE);

    // Create recursive directory iterator
    /** @var SplFileInfo[] $files */
    $files = new \RecursiveIteratorIterator(
        new \RecursiveDirectoryIterator($rootPath),
        \RecursiveIteratorIterator::LEAVES_ONLY
    );

    foreach ($files as $name => $file)
    {
        // Skip directories (they would be added automatically)
        if (!$file->isDir())
        {
            // Get real and relative path for current file
            $filePath = $file->getRealPath();
            $relativePath = substr($filePath, strlen($rootPath) + 1);

            // Add current file to archive
            $zip->addFile($filePath, $relativePath);
        }
    }

    // Zip archive will be created only after closing object
    $zip->close();

update

This only seems to be a problem on Windows, when tested on a Mac, it works without issues.


Solution

  • I ran into this problem again, and after asking help on a LibreOffice forum (the problem was specific for Impress), I've discovered that in windows the filepaths used when archiving had backslashes, that caused the issues.

    I've added two lines in my archiving function to clean up the paths:

            // Get real and relative path for current file
            $filePath = $file->getRealPath();
            $relativePath = substr($filePath, strlen($rootPath) + 1);
    
            // Replace backward with forward slashes, for compatibility issues
            $filePath = str_replace('\\', '/', $filePath);
            $relativePath = str_replace('\\', '/', $relativePath);
    
            // Add current file to archive
            $zip->addFile($filePath, $relativePath);
    

    Now my code runs without problems. (I use the LibreOffice headless as an exec() to convert to pdf, which wouldn't work previously)