I put together this quick and dirty code for retrieving the filenames and content positions of compressed files in a zip file with PHP. I was having a tough time finding something in PHP to
read zip files that didn't depend on functions such as zip_open or the ZipArchive class. This code is far from full-featured, but it works for simple zip files like you might create by selecting a group of files on your desktop and selecting "send to -> compressed (zipped) folder" from the right-click menu.
Basically a zip file is a series of 30 byte headers of which the first 4 bytes are a signature (0x04034b50) followed by variable length filename and extra info sections, which are in turn followed by variable length sections of compressed content.
The function quickly scans the passed file and returns an array of arrays. Each array includes the filename, offset of the files compressed content in the file, and the size of the compressed content.
The function takes a single argument, the filename of the zip file.
<?php
function zip_list($filename)
{
$size = filesize($filename);
$position = 0;
$signature = 0x04034b50;
$files = array();
$fh = fopen($filename, 'r');
while($position < $size)
{
fseek($fh, $position);
$h = fread($fh, 30); // fixed length section of header.
if(array_shift(unpack('V', substr($h, 0, 4))) != $signature)
{
break;
}
$name_len = array_shift(unpack('v', $h[26].$h[27]));
$xtra_len = array_shift(unpack('v', $h[28].$h[29]));
$comp_size = array_shift(unpack('V', $h[18].$h[19].$h[20].$h[21]));
$filename = implode(array_map('chr', unpack("C{$name_len}", fread($fh, $name_len))));
$files[] = array(
'filename' => $filename,
'offset' => ftell($fh) + $xtra_len,
'length' => $comp_size
);
$position = ftell($fh) + $xtra_len + $comp_size;
}
fclose($fh);
return $files;
}
?>
- <?php
-
- function zip_list($filename)
- {
- $size = filesize($filename);
- $position = 0;
- $signature = 0x04034b50;
- $files = array();
-
- $fh = fopen($filename, 'r');
-
- while($position < $size)
- {
- fseek($fh, $position);
- $h = fread($fh, 30); // fixed length section of header.
-
- if(array_shift(unpack('V', substr($h, 0, 4))) != $signature)
- {
- break;
- }
-
- $name_len = array_shift(unpack('v', $h[26].$h[27]));
- $xtra_len = array_shift(unpack('v', $h[28].$h[29]));
- $comp_size = array_shift(unpack('V', $h[18].$h[19].$h[20].$h[21]));
-
- $filename = implode(array_map('chr', unpack("C{$name_len}", fread($fh, $name_len))));
- $files[] = array(
- 'filename' => $filename,
- 'offset' => ftell($fh) + $xtra_len,
- 'length' => $comp_size
- );
-
- $position = ftell($fh) + $xtra_len + $comp_size;
- }
-
- fclose($fh);
-
- return $files;
- }
-
- ?>
With that you can use
file_get_contents and
gzinflate to retrieve the compressed sections for each file and decompress them.
<?php
$zip = zip_list('file.zip');
for($i = 0, $toi = count($zip); $i < $toi; $i++)
{
$compressed_str = file_get_contents('file.zip', null, null, $zip[$i]['offset'], $zip[$i]['length']);
$decompressed_str = gzinflate($compressed_str);
file_put_contents($zip[$i]['filename'], $decompressed_str);
}
?>
- <?php
-
- $zip = zip_list('file.zip');
-
- for($i = 0, $toi = count($zip); $i < $toi; $i++)
- {
- $compressed_str = file_get_contents('file.zip', null, null, $zip[$i]['offset'], $zip[$i]['length']);
- $decompressed_str = gzinflate($compressed_str);
- file_put_contents($zip[$i]['filename'], $decompressed_str);
- }
-
- ?>
For reference sake, here's my go-to post for when I need to
write zip files without the zip extensions available.
programming-forum/php-zipping-and-entire-directory-t54069.html#p282162 
Strong with this one, the sudo is.