Tuesday, August 31, 2010

PHP:function to extract files from zip

The unzip.php program, shown in Example, extracts files from a ZIP archive. It uses the pc_mkdir_parents( ) function. 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 justturtles.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 reachesanimals/turtles.html, it writes out turtles.html without creating any additional directories.

Example. 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");             }         }     } }

Making New Directories

You want to create a directory.


The second argument to mkdir( ) is the permission mode for the new directory, which must be an octal number. The current umask is taken away from this permission value to create the permissions for the new directory. So, if the current umask is 0002, calling mkdir('/tmp/apples',0777) sets the permissions on the resulting directory to 0775 (user and group can read, write, and execute; others can only read and execute).

PHP's built-in mkdir( ) can make a directory only if its parent exists. For example, if /tmp/a doesn't exist, you can't create /tmp/a/b until /tmp/a is created. To create a directory and its parents, you have two choices: you can call your system's mkdir program, or you can use the pc_mkdir_parents( ) function, shown in Example. To use your system's mkdir program, on Unix, use this:

system('/bin/mkdir -p '.escapeshellarg($directory));

On Windows do:

system('mkdir '.escapeshellarg($directory));

You can also use the pc_mkdir_parents( ) function shown in Example

Example . pc_mkdir_parents( )

function pc_mkdir_parents($d,$umask = 0777) {     $dirs = array($d);     $d = dirname($d);     $last_dirname = '';     while($last_dirname != $d) {          array_unshift($dirs,$d);         $last_dirname = $d;         $d = dirname($d);     }      foreach ($dirs as $dir) {         if (! file_exists($dir)) {             if (! mkdir($dir,$umask)) {                 error_log("Can't make directory: $dir");                 return false;             }         } elseif (! is_dir($dir)) {             error_log("$dir is not a directory");             return false;         }     }     return true; }

For example: