Search code examples
phpphp-ziparchive

PHP unzip deflate64


I am currently facing an issue while trying to decompress a ZIP file that utilizes Deflate64 compression in PHP using the ZipArchive class. The extraction process seems to be working well for regular Deflate compression, but encounters difficulties when dealing with Deflate64.

Here's an example of a successful extraction using regular Deflate compression:

$zip = new ZipArchive();
$zip->open('deflate.zip');
$zip->extractTo('/tmp/test_extract');
(bool) true

However, when attempting to extract a ZIP file that uses Deflate64 compression, the process fails:

$zip = new ZipArchive();
$zip->open('deflate64.zip');
$zip->extractTo('/tmp/test_extract');
(bool) false

Furthermore, checking if Deflate64 compression is supported using ZipArchive::isCompressionMethodSupported returns false:

ZipArchive::isCompressionMethodSupported(ZipArchive::CM_DEFLATE64);
(bool) false

On the other hand, regular Deflate compression is supported:

ZipArchive::isCompressionMethodSupported(ZipArchive::CM_DEFLATE);
(bool) true

I am reaching out to the community to inquire if there is a known solution or workaround to enable the extraction of ZIP files using Deflate64 compression in PHP's ZipArchive class. Any insights or code snippets that address this issue would be greatly appreciated.

Thank you in advance for your assistance!


Solution

  • It looks like the libzip team just don't want to support deflate64 yet, you can use zlib to inflate each file individually.

    $destination = '/tmp/test_extract';
    for ($i = 0; $i < $zip->numFiles; $i++) {
        $st = $zip->statIndex($i);
        $filename = $stat['name'];
        if ($st['comp_method'] === ZipArchive::CM_DEFLATE64){
            $data = $zip->getFromIndex($i, 0, ZipArchive::FL_COMPRESSED);
            file_put_contents("$destination/$filename", gzinflate($data));
        } else {
            $zip->extractTo($destination, $filename);
        }
    }
    

    Note: You need to create subfolders by yourself.


    Update: Decompress large files (PHP >= 8.2)

    $inf = inflate_init(ZLIB_ENCODING_RAW);
    for ...
        $src = $zip->getStreamIndex($i, ZipArchive::FL_COMPRESSED);
        $dst = fopen("$destination/$filename", 'wb');
    
        while(!feof($src)){
            $data = fread($src, 8192);
            $data = inflate_add($inf, $data, feof($src) ? ZLIB_FINISH : ZLIB_NO_FLUSH);
            fwrite($dst, $data);
        }
    
        fclose($src);
        fclose($dst);
    ...