tags:

views:

52

answers:

3

Hi, I'm trying to unzip a 14MB archive with PHP with code like this:

    $zip = zip_open("c:\kosmas.zip");
    while ($zip_entry = zip_read($zip)) {
    $fp = fopen("c:/unzip/import.xml", "w");
    if (zip_entry_open($zip, $zip_entry, "r")) {
     $buf = zip_entry_read($zip_entry, zip_entry_filesize($zip_entry));
     fwrite($fp,"$buf");
     zip_entry_close($zip_entry);
     fclose($fp);
     break;
    }
   zip_close($zip);
  }

It fails on my localhost with 128MB memory limit with the classic "Allowed memory size of blablabla bytes exhausted". On the server, I've got 16MB limit, is there a better way to do this so that I could fit into this limit? I don't see why this has to allocate more than 128MB of memory. Thanks in advance.

Solution: I started reading the files in 10Kb chunks, problem solved with peak memory usage arnoud 1.5MB.

        $filename = 'c:\kosmas.zip';
        $archive = zip_open($filename);
        while($entry = zip_read($archive)){
            $size = zip_entry_filesize($entry);
            $name = zip_entry_name($entry);
            $unzipped = fopen('c:/unzip/'.$name,'wb');
            while($size > 0){
                $chunkSize = ($size > 10240) ? 10240 : $size;
                $size -= $chunkSize;
                $chunk = zip_entry_read($entry, $chunkSize);
                if($chunk !== false) fwrite($unzipped, $chunk);
            }

            fclose($unzipped);
        }
+1  A: 

Just because a zip is less than PHP's memory limit & perhaps the unzipped is as well, doesn't take account of PHP's overhead generally and more importantly the memory needed to actually unzip the file, which whilst I'm not expert with compression I'd expect may well be a lot more than the final unzipped size.

46Bit
Yes, but there always seems to be an alternative, i.e. I can ungzip much larger archive with peak memory usage lower than 1MB, I can parse 1.5GB xml file with peak memory usage lower than 3MB, why couldn't there be such alternative for zip files...
cypher
+1  A: 

For a file of that size, perhaps it is better if you use shell_exec() instead:

shell_exec('unzip archive.zip -d /destination_path');

PHP must not be running in safe mode and you must have access to both shell_exec and unzip for this method to work.

Update:

Given that command line tools are not available, all I can think of is to create a script and send the file to a remote server where command line tools are available, extract the file and download the contents.

Anax
Unfortunately, command line tools are disabled by the server.
cypher
+1  A: 

Why do you read the whole file at once?

 $buf = zip_entry_read($zip_entry, zip_entry_filesize($zip_entry));
 fwrite($fp,"$buf");

Try reading small chinks of it and writing them to a file...

Quamis
That is exactly what I did and I'm gonna post the solution in a minute, if anyone is interested.
cypher