note 67735 deleted from function.zip-open by bjori
| From: | bjori@php.net | 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']);
}
?>