The unzip.php program, shown in Example 18-5, extracts files from a ZIP archive.
It uses the pc_mkdir_parents( ) function which
is defined in Section 19.11. The program also requires PHP's zip extension to be installed. You can
find documentation on the zip extension at http://www.php.net/zip.
This program takes a few arguments on the command line. The
first is the name of the ZIP archive it should unzip. By default, it unzips all
files in the archive. If additional command-line arguments are supplied, it only
unzips files whose name matches any of those arguments. The full path of the
file inside the ZIP archive must be given. If turtles.html is in the ZIP archive inside the animals directory, unzip.php must be passed animals/turtles.html, not just turtles.html, to unzip the file.
Directories are stored as 0-byte files inside ZIP archives, so
unzip.php doesn't try to create them. Instead,
before it creates any other file, it uses pc_mkdir_parents( ) to create
all directories that are parents of that file, if necessary. For example, say
unzip.php sees these entries in the ZIP archive:
animals (0 bytes) animals/frogs/ribbit.html (2123 bytes) animals/turtles.html (1232 bytes)
It ignores animals because it is
0 bytes long. Then it calls pc_mkdir_parents( ) on animals/frogs, creating both animals and animals/frogs, and writes ribbit.html into animals/frogs. Since animals already exists when it reaches animals/turtles.html, it writes out turtles.html without creating any additional
directories.
Example 18-5. unzip.php
// the first argument is the zip file
$in_file = $_SERVER['argv'][1];
// any other arguments are specific files in the archive to unzip
if ($_SERVER['argc'] > 2) {
$all_files = 0;
for ($i = 2; $i < $_SERVER['argc']; $i++) {
$out_files[$_SERVER['argv'][$i]] = true;
}
} else {
// if no other files are specified, unzip all files
$all_files = true;
}
$z = zip_open($in_file) or die("can't open $in_file: $php_errormsg");
while ($entry = zip_read($z)) {
$entry_name = zip_entry_name($entry);
// check if all files should be unzipped, or the name of
// this file is on the list of specific files to unzip
if ($all_files || $out_files[$entry_name]) {
// only proceed if the file is not 0 bytes long
if (zip_entry_filesize($entry)) {
$dir = dirname($entry_name);
// make all necessary directories in the file's path
if (! is_dir($dir)) { pc_mkdir_parents($dir); }
$file = basename($entry_name);
if (zip_entry_open($z,$entry)) {
if ($fh = fopen($dir.'/'.$file,'w')) {
// write the entire file
fwrite($fh,
zip_entry_read($entry,zip_entry_filesize($entry)))
or error_log("can't write: $php_errormsg");
fclose($fh) or error_log("can't close: $php_errormsg");
} else {
error_log("can't open $dir/$file: $php_errormsg");
}
zip_entry_close($entry);
} else {
error_log("can't open entry $entry_name: $php_errormsg");
}
}
}
}