简体   繁体   中英

ZipArchive can't unzip files that ZipArchive zips in PHP

Trying to get import/export functionality.

  1. With a folder containing a file
  2. Zip the folder in PHP using ZipArchive
  3. Unzip the zipped folder using ZipArchive
  4. New folder is created, but the file inside is missing

     function unArchive(){ $zip = new ZipArchive; $res = $zip->open('zipTest.zip'); if ($res === TRUE) { echo 'ok'; $zip->extractTo("testfolder2"); $zip->close(); } else { echo 'failed, code:' . $res; } } function Zip($source, $destination){ if (!extension_loaded('zip') || !file_exists($source)){ return false; } $zip = new ZipArchive(); if (!$zip->open($destination, ZIPARCHIVE::CREATE)) { return false; } $source = str_replace('\\\\', '/', realpath($source)); if (is_dir($source) === true){ $files = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($source), RecursiveIteratorIterator::SELF_FIRST); foreach ($files as $file){ $file = str_replace('\\\\', '/', realpath($file)); if (is_dir($file) === true){ $zip->addEmptyDir( str_replace($source . '/', '', $file . '/') ); }else if (is_file($file) === true){ $zip->addFromString( str_replace($source . '/', '', $file), file_get_contents($file)); } } }else if (is_file($source) === true){ $zip->addFromString(basename($source), file_get_contents($source)); } return $zip->close(); } Zip( "testfolder/" , "./zipTest.zip" ); unArchive(); 

Code works fine for single files. With a file zipped using ZipArchive, I can manually unzip using WinRAR, then rezip using WinRAR, and then ZipArchive can successfully unzip that file. The problem is that ZipArchive won't extract the archive that it directly zipped. I can also see in Notepad++ that the ZipArchive zip is different from the WinRAR zip, and the file size is different. I can successfully call winrar as a system command in php for the desired functionality, but this seems like a bad idea. Is there some reason ZipArchive creates zip files that it can't extract?

Error message: ZipArchive::extractTo(): Invalid argument in [file] on line [$zip->extractTo("testfolder2");]

The RecursiveIteratorIterator returns the pseudo-files "." and, that's important here, ".." - the parent directory. When you use addEmptyDir to add the parent directory, the ZipArchive will add it (somehow)! You may even try "$zip->addEmptyDir("../something")" and it will not complain.

Now, usually, zip files don't behave this way. When you extract them, you expect all contents to be in the folder you extract them, not in the parent folders. This is why ordinary ZIP extraction programs do not show it.

The PHP ZipArchive will extract even these folders, however. Then, this error will somehow occur, because you tried to include the "." or ".." directories.

Add this at the beginning of the foreach cycle to resolve this:

if (basename($file) === ".") { continue;}
if (basename($file) === "..") { continue; }

Test case:

<?php
$archive = new ZipArchive();
$archive->open('c.zip',ZipArchive::CREATE);
$archive->addFile('a.txt');
$archive->addFile('b.txt');
$archive->addEmptyDir("../../down");
$archive->close();

$archive2 = new ZipArchive();
$archive2->open('c.zip');
$archive2->extractTo('here');
$archive2->close();

I tested this only on Windows.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM