Thursday, July 23, 2009

Another Gotcha Of The Day: empty Zip file generated by PHP

I wanted to use the Zip library offered by PHP to generate a .zip file. The API is nice and simple, you just do something like:

$zip = new ZipArchive();
$filename = "test.zip";
if ($zip->open($filename, ZIPARCHIVE::CREATE)!==TRUE) {
    user_error("cannot open <$filename>\n");
}
$zip->addFile("/usr/local/foo.gif","/foo.gif");
$zip->addFile("/usr/local/baz.gif","/bar.gif");
$zip->close();

For the life of me, though, I couldn't figure out why my code was generating an empty (0 byte) zip file. I could see the temporary files I was added to the zip file were on disk, but for some reason they wouldn't end up in my Zip archive.

To add insult to injury, the methods on the ZipArchive object just return back true or false, and don't say why they failed.

Eventually I narrowed down my woes to $zip->close() failing. But why? It would not say.

Finally, I put even more checks in place and realized that of the 20 files or so I was adding to the ZipArchive, one of them did not exist. The call to addFile() worked fine, but apparently later on when I called close() the archive was corrupted.

To avoid this type of issue in the future, I wrote a quick wrapper class around ZipArchive. Calling addFile on a non-existent or non-readable file will immediately raise an error. Here it is - enjoy!

<?php
/*
 * An extension to ZipArchive that's more verbose about 
 * issues that may cause things to break
 */

class SafeZipArchive extends ZipArchive {

  function open($file, $mode) {
    $result = parent::open($file, $mode);
    if($result !== true) {
      user_error("Failed to open the zip file $file ($mode)");
    }
    return true;
  }

  function addFile($path, $local) {
    if(!file_exists($path)) {
      user_error("Can't add |$path| to zip file, the path does not exist");
    }
    if(!is_readable($path)) {
      user_error("Can't add |$path| to zip file, the file is not readable");
    }

    $result = parent::addFile($path, $local);
    if($result !== true) {
      user_error("Unexpected error while adding the file |$path| as |$local|");
    }
    return $result;
  }

  function close() {
    $result = parent::close();
    if($result !== true) {
      user_error("Failed to close (and build) the zip archive");
    }
    return $result;
  }
}
?>

2 comments:

  1. I have been working with zip files for some years. And I have never met with such situation. Some days ago I lost whole my hundreds zip archives. I kept one's head and found - check repair zip file on a soft forum. It worked out my issue quite easy and I didn't spend the money!

    ReplyDelete
  2. Anonymous12:25 PM

    Had been tearing my hair out trying to work out why my folder of files wouldn't zip-up. This has fixed everything! Many thanks :)

    ReplyDelete