note 67735 deleted from function.zip-open by bjori

From: Date: Fri, 09 Jun 2006 10:58:16 +0000
Subject: note 67735 deleted from function.zip-open by bjori
References: 1  Groups: php.notes 
Request: Send a blank email to php-notes+get-114157@lists.php.net to get a copy of this message
Note Submitter: Michael ---- I had some trouble reading a bunch of Zip-Files in a loop, each containing about 10,000 small files - The original php_zip extension memory consumption was huge and the replacement hack way to slow (it makes one call to "unzip -p" per entry of the zip file). Here is a revised version of the unzip hack. It streams the whole zip content at once (uncompressing on the fly). The interface is exactly the same, only some "byte-arithmetic" within the functions was needed to offset to the proper position of the stream. Compared to the original hack, my own script finishes now after 6 minutes instead of 4.5 hours. <?php function ShellFix($s) { return '"'.str_replace("'", "'\''", $s).'"'; } function zip_open($s) { $fp = @fopen($s, 'rb'); if(!$fp) return false; $lines = Array(); $cmd = 'unzip -v '.ShellFix($s); exec($cmd, $lines); $contents = Array(); $startpos = 0; $ok=false; foreach($lines as $line) { if($line[2]=='-') { $ok=!$ok; continue; } if(!$ok) continue; $length = (int)$line; $fn = trim(substr($line,58)); array_push($contents, Array('name' => $fn, 'length' => $length, 'startpos' => $startpos)); $startpos += $length; // startpos of next file; } //// we already open the pipe for later reading ALL files at once... $cmd = 'unzip -p '.ShellFix($s); $stream = popen($cmd, 'rb'); //////////////////////////////////// return Array('fp' => $fp, 'name' => $s, 'contents' => $contents, 'pointer' => -1, 'stream' => $stream ); } function zip_read(&$fp) { if(!$fp) return false; $next = $fp['pointer'] + 1; if($next >= count($fp['contents'])) return false; // add the length from the (now) previous file to current position. if ($fp['pointer'] >= 0) { $fp['startpos'] += $fp['contents'][$fp['pointer']]['length']; } $fp['pointer'] = $next; return $fp['contents'][$next]; // == $res } function zip_entry_name(&$res) { if(!$res) return false; return $res['name']; } function zip_entry_filesize(&$res) { if(!$res) return false; return $res['length']; } function zip_entry_open(&$fp, &$res) { if(!$res) return false; // now more or less a dummy, stream should be already open... $res['fp'] = $fp['stream']; return !!$fp['stream']; } function zip_entry_read(&$res, $nbytes) { $curpos = ftell($res['fp']); // current bytepos in (unpacked)zip stream... $startpos = $res['startpos']; $length = $res['length']; // length of current file $seekcnt = 0; if ($curpos < $startpos) { $seekcnt = $startpos - $curpos ; fseek($res['fp'],$seekcnt,SEEK_CUR); $curpos = $startpos; } // determine how much is left for reading from current file: $remain = $length - ($curpos - $startpos ); // do we want to read less? if ($nbytes < $remain) {$remain = $nbytes; } while (($remain > 0 ) && ($s = fread($res['fp'],(($remain > 1024)?1024:$remain) ))) { $data .= $s; $remain -= strlen($s) ; } return $data; } function zip_entry_close(&$res) { // do nothing ... (Todo: Some cleanup needed?) } function zip_close(&$fp) { fclose($fp['stream']); unset($fp['stream']); fclose($fp['fp']); unset($fp['fp']); } ?>

« previous php.notes (#114157) next »