Zip and Unzip Files with PHP

Example code for zipping and unzipping files. Code taken from a tool called phpfilemanager.php

/* Source: https://github.com/gbif/dwca-adapters/tree/master/classes/zip */
/*--------------------------------------------------
 | TAR/GZIP/BZIP2/ZIP ARCHIVE CLASSES 2.1
 | By Devin Doucette
 | Copyright (c) 2005 Devin Doucette
 | Email: darksnoopy@shaw.ca
 +--------------------------------------------------
 | Email bugs/suggestions to darksnoopy@shaw.ca
 +--------------------------------------------------
 | This script has been created and released under
 | the GNU GPL and is free to use and redistribute
 | only if this copyright statement is not removed
 +--------------------------------------------------*/
class archive
{
 function archive($name)
 {
  $this->options = array (
   'basedir' => ".",
   'name' => $name,
   'prepend' => "",
   'inmemory' => 0,
   'overwrite' => 0,
   'recurse' => 1,
   'storepaths' => 1,
   'followlinks' => 0,
   'level' => 3,
   'method' => 1,
   'sfx' => "",
   'type' => "",
   'comment' => ""
  );
  $this->files = array ();
  $this->exclude = array ();
  $this->storeonly = array ();
  $this->error = array ();
 }
 function set_options($options)
 {
  foreach ($options as $key => $value)
   $this->options[$key] = $value;
  if (!empty ($this->options['basedir']))
  {
   $this->options['basedir'] = str_replace("\\", "/", $this->options['basedir']);
   $this->options['basedir'] = preg_replace("/\/+/", "/", $this->options['basedir']);
   $this->options['basedir'] = preg_replace("/\/$/", "", $this->options['basedir']);
  }
  if (!empty ($this->options['name']))
  {
   $this->options['name'] = str_replace("\\", "/", $this->options['name']);
   $this->options['name'] = preg_replace("/\/+/", "/", $this->options['name']);
  }
  if (!empty ($this->options['prepend']))
  {
   $this->options['prepend'] = str_replace("\\", "/", $this->options['prepend']);
   $this->options['prepend'] = preg_replace("/^(\.*\/+)+/", "", $this->options['prepend']);
   $this->options['prepend'] = preg_replace("/\/+/", "/", $this->options['prepend']);
   $this->options['prepend'] = preg_replace("/\/$/", "", $this->options['prepend']) . "/";
  }
 }
 function create_archive()
 {
  $this->make_list();
  if ($this->options['inmemory'] == 0)
  {
   $pwd = getcwd();
   chdir($this->options['basedir']);
   if ($this->options['overwrite'] == 0 && file_exists($this->options['name'] . ($this->options['type'] == "gzip" || $this->options['type'] == "bzip" ? ".tmp" : "")))
   {
    $this->error[] = "File {$this->options['name']} already exists.";
    chdir($pwd);
    return 0;
   }
   else if ($this->archive = @fopen($this->options['name'] . ($this->options['type'] == "gzip" || $this->options['type'] == "bzip" ? ".tmp" : ""), "wb+"))
    chdir($pwd);
   else
   {
    $this->error[] = "Could not open {$this->options['name']} for writing.";
    chdir($pwd);
    return 0;
   }
  }
  else
   $this->archive = "";
  switch ($this->options['type'])
  {
  case "zip":
   if (!$this->create_zip())
   {
    $this->error[] = "Could not create zip file.";
    return 0;
   }
   break;
  case "bzip":
   if (!$this->create_tar())
   {
    $this->error[] = "Could not create tar file.";
    return 0;
   }
   if (!$this->create_bzip())
   {
    $this->error[] = "Could not create bzip2 file.";
    return 0;
   }
   break;
  case "gzip":
   if (!$this->create_tar())
   {
    $this->error[] = "Could not create tar file.";
    return 0;
   }
   if (!$this->create_gzip())
   {
    $this->error[] = "Could not create gzip file.";
    return 0;
   }
   break;
  case "tar":
   if (!$this->create_tar())
   {
    $this->error[] = "Could not create tar file.";
    return 0;
   }
  }
  if ($this->options['inmemory'] == 0)
  {
   fclose($this->archive);
   if ($this->options['type'] == "gzip" || $this->options['type'] == "bzip")
    unlink($this->options['basedir'] . "/" . $this->options['name'] . ".tmp");
  }
 }
 function add_data($data)
 {
  if ($this->options['inmemory'] == 0)
   fwrite($this->archive, $data);
  else
   $this->archive .= $data;
 }
 function make_list()
 {
  if (!empty ($this->exclude))
   foreach ($this->files as $key => $value)
    foreach ($this->exclude as $current)
     if ($value['name'] == $current['name'])
      unset ($this->files[$key]);
  if (!empty ($this->storeonly))
   foreach ($this->files as $key => $value)
    foreach ($this->storeonly as $current)
     if ($value['name'] == $current['name'])
      $this->files[$key]['method'] = 0;
  unset ($this->exclude, $this->storeonly);
 }
 function add_files($list)
 {
  $temp = $this->list_files($list);
  foreach ($temp as $current)
   $this->files[] = $current;
 }
 function exclude_files($list)
 {
  $temp = $this->list_files($list);
  foreach ($temp as $current)
   $this->exclude[] = $current;
 }
 function store_files($list)
 {
  $temp = $this->list_files($list);
  foreach ($temp as $current)
   $this->storeonly[] = $current;
 }
 function list_files($list)
 {
  if (!is_array ($list))
  {
   $temp = $list;
   $list = array ($temp);
   unset ($temp);
  }
  $files = array ();
  $pwd = getcwd();
  chdir($this->options['basedir']);
  foreach ($list as $current)
  {
   $current = str_replace("\\", "/", $current);
   $current = preg_replace("/\/+/", "/", $current);
   $current = preg_replace("/\/$/", "", $current);
   if (strstr($current, "*"))
   {
    $regex = preg_replace("/([\\\^\$\.\[\]\|\(\)\?\+\{\}\/])/", "\\\\\\1", $current);
    $regex = str_replace("*", ".*", $regex);
    $dir = strstr($current, "/") ? substr($current, 0, strrpos($current, "/")) : ".";
    $temp = $this->parse_dir($dir);
    foreach ($temp as $current2)
     if (preg_match("/^{$regex}$/i", $current2['name']))
      $files[] = $current2;
    unset ($regex, $dir, $temp, $current);
   }
   else if (@is_dir($current))
   {
    $temp = $this->parse_dir($current);
    foreach ($temp as $file)
     $files[] = $file;
    unset ($temp, $file);
   }
   else if (@file_exists($current))
    $files[] = array ('name' => $current, 'name2' => $this->options['prepend'] .
     preg_replace("/(\.+\/+)+/", "", ($this->options['storepaths'] == 0 && strstr($current, "/")) ?
     substr($current, strrpos($current, "/") + 1) : $current),
     'type' => @is_link($current) && $this->options['followlinks'] == 0 ? 2 : 0,
     'ext' => substr($current, strrpos($current, ".")), 'stat' => stat($current));
  }
  chdir($pwd);
  unset ($current, $pwd);
  usort($files, array ("archive", "sort_files"));
  return $files;
 }
 function parse_dir($dirname)
 {
  if ($this->options['storepaths'] == 1 && !preg_match("/^(\.+\/*)+$/", $dirname))
   $files = array (array ('name' => $dirname, 'name2' => $this->options['prepend'] .
    preg_replace("/(\.+\/+)+/", "", ($this->options['storepaths'] == 0 && strstr($dirname, "/")) ?
    substr($dirname, strrpos($dirname, "/") + 1) : $dirname), 'type' => 5, 'stat' => stat($dirname)));
  else
   $files = array ();
  $dir = @opendir($dirname);
  while ($file = @readdir($dir))
  {
   $fullname = $dirname . "/" . $file;
   if ($file == "." || $file == "..")
    continue;
   else if (@is_dir($fullname))
   {
    if (empty ($this->options['recurse']))
     continue;
    $temp = $this->parse_dir($fullname);
    foreach ($temp as $file2)
     $files[] = $file2;
   }
   else if (@file_exists($fullname))
    $files[] = array ('name' => $fullname, 'name2' => $this->options['prepend'] .
     preg_replace("/(\.+\/+)+/", "", ($this->options['storepaths'] == 0 && strstr($fullname, "/")) ?
     substr($fullname, strrpos($fullname, "/") + 1) : $fullname),
     'type' => @is_link($fullname) && $this->options['followlinks'] == 0 ? 2 : 0,
     'ext' => substr($file, strrpos($file, ".")), 'stat' => stat($fullname));
  }
  @closedir($dir);
  return $files;
 }
 function sort_files($a, $b)
 {
  if ($a['type'] != $b['type'])
   if ($a['type'] == 5 || $b['type'] == 2)
    return -1;
   else if ($a['type'] == 2 || $b['type'] == 5)
    return 1;
  else if ($a['type'] == 5)
   return strcmp(strtolower($a['name']), strtolower($b['name']));
  else if ($a['ext'] != $b['ext'])
   return strcmp($a['ext'], $b['ext']);
  else if ($a['stat'][7] != $b['stat'][7])
   return $a['stat'][7] > $b['stat'][7] ? -1 : 1;
  else
   return strcmp(strtolower($a['name']), strtolower($b['name']));
  return 0;
 }
 function download_file()
 {
  if ($this->options['inmemory'] == 0)
  {
   $this->error[] = "Can only use download_file() if archive is in memory. Redirect to file otherwise, it is faster.";
   return;
  }
  switch ($this->options['type'])
  {
  case "zip":
   header("Content-Type: application/zip");
   break;
  case "bzip":
   header("Content-Type: application/x-bzip2");
   break;
  case "gzip":
   header("Content-Type: application/x-gzip");
   break;
  case "tar":
   header("Content-Type: application/x-tar");
  }
  $header = "Content-Disposition: attachment; filename=\"";
  $header .= strstr($this->options['name'], "/") ? substr($this->options['name'], strrpos($this->options['name'], "/") + 1) : $this->options['name'];
  $header .= "\"";
  header($header);
  header("Content-Length: " . strlen($this->archive));
  header("Content-Transfer-Encoding: binary");
  header("Cache-Control: no-cache, must-revalidate, max-age=60");
  header("Expires: Sat, 01 Jan 2000 12:00:00 GMT");
  print($this->archive);
 }
 function save_file( $output_file = 'tmp' )
 {
  if ($this->options['inmemory'] == 0)
  {
   $this->error[] = "Can only use download_file() if archive is in memory. Redirect to file otherwise, it is faster.";
   return;
  }
  file_put_contents( $output_file, $this->archive);
 }
}

Zip FIle Method

class zip_file extends archive
{
 function zip_file($name)
 {
  $this->archive($name);
  $this->options['type'] = "zip";
 }
 function create_zip()
 {
  $files = 0;
  $offset = 0;
  $central = "";
  if (!empty ($this->options['sfx']))
   if ($fp = @fopen($this->options['sfx'], "rb"))
   {
    $temp = fread($fp, filesize($this->options['sfx']));
    fclose($fp);
    $this->add_data($temp);
    $offset += strlen($temp);
    unset ($temp);
   }
   else
    $this->error[] = "Could not open sfx module from {$this->options['sfx']}.";
  $pwd = getcwd();
  chdir($this->options['basedir']);
  foreach ($this->files as $current)
  {
   if ($current['name'] == $this->options['name'])
    continue;
   $timedate = explode(" ", date("Y n j G i s", $current['stat'][9]));
   $timedate = ($timedate[0] - 1980 << 25) | ($timedate[1] << 21) | ($timedate[2] << 16) |
    ($timedate[3] << 11) | ($timedate[4] << 5) | ($timedate[5]);
   $block = pack("VvvvV", 0x04034b50, 0x000A, 0x0000, (isset($current['method']) || $this->options['method'] == 0) ? 0x0000 : 0x0008, $timedate);
   if ($current['stat'][7] == 0 && $current['type'] == 5)
   {
    $block .= pack("VVVvv", 0x00000000, 0x00000000, 0x00000000, strlen($current['name2']) + 1, 0x0000);
    $block .= $current['name2'] . "/";
    $this->add_data($block);
    $central .= pack("VvvvvVVVVvvvvvVV", 0x02014b50, 0x0014, $this->options['method'] == 0 ? 0x0000 : 0x000A, 0x0000,
     (isset($current['method']) || $this->options['method'] == 0) ? 0x0000 : 0x0008, $timedate,
     0x00000000, 0x00000000, 0x00000000, strlen($current['name2']) + 1, 0x0000, 0x0000, 0x0000, 0x0000, $current['type'] == 5 ? 0x00000010 : 0x00000000, $offset);
    $central .= $current['name2'] . "/";
    $files++;
    $offset += (31 + strlen($current['name2']));
   }
   else if ($current['stat'][7] == 0)
   {
    $block .= pack("VVVvv", 0x00000000, 0x00000000, 0x00000000, strlen($current['name2']), 0x0000);
    $block .= $current['name2'];
    $this->add_data($block);
    $central .= pack("VvvvvVVVVvvvvvVV", 0x02014b50, 0x0014, $this->options['method'] == 0 ? 0x0000 : 0x000A, 0x0000,
     (isset($current['method']) || $this->options['method'] == 0) ? 0x0000 : 0x0008, $timedate,
     0x00000000, 0x00000000, 0x00000000, strlen($current['name2']), 0x0000, 0x0000, 0x0000, 0x0000, $current['type'] == 5 ? 0x00000010 : 0x00000000, $offset);
    $central .= $current['name2'];
    $files++;
    $offset += (30 + strlen($current['name2']));
   }
   else if ($fp = @fopen($current['name'], "rb"))
   {
    $temp = fread($fp, $current['stat'][7]);
    fclose($fp);
    $crc32 = crc32($temp);
    if (!isset($current['method']) && $this->options['method'] == 1)
    {
     $temp = gzcompress($temp, $this->options['level']);
     $size = strlen($temp) - 6;
     $temp = substr($temp, 2, $size);
    }
    else
     $size = strlen($temp);
    $block .= pack("VVVvv", $crc32, $size, $current['stat'][7], strlen($current['name2']), 0x0000);
    $block .= $current['name2'];
    $this->add_data($block);
    $this->add_data($temp);
    unset ($temp);
    $central .= pack("VvvvvVVVVvvvvvVV", 0x02014b50, 0x0014, $this->options['method'] == 0 ? 0x0000 : 0x000A, 0x0000,
     (isset($current['method']) || $this->options['method'] == 0) ? 0x0000 : 0x0008, $timedate,
     $crc32, $size, $current['stat'][7], strlen($current['name2']), 0x0000, 0x0000, 0x0000, 0x0000, 0x00000000, $offset);
    $central .= $current['name2'];
    $files++;
    $offset += (30 + strlen($current['name2']) + $size);
   }
   else
    $this->error[] = "Could not open file {$current['name']} for reading. It was not added.";
  }
  $this->add_data($central);
  $this->add_data(pack("VvvvvVVv", 0x06054b50, 0x0000, 0x0000, $files, $files, strlen($central), $offset,
   !empty ($this->options['comment']) ? strlen($this->options['comment']) : 0x0000));
  if (!empty ($this->options['comment']))
   $this->add_data($this->options['comment']);
  chdir($pwd);
  return 1;
 }
}

Unzip File Method

function unzip_file($zip_name, $current_path, $destination_path){
 $zip = zip_open($current_path.$zip_name);
 if($zip){
  while ($zip_entry = zip_read($zip)){
   if(zip_entry_filesize($zip_entry)){
    $complete_path = dirname(zip_entry_name($zip_entry));
    $complete_name = zip_entry_name($zip_entry);
    if(!file_exists($destination_path.$complete_path)){
     $tmp = '';
     foreach(explode('/',$complete_path) as $k){
      $tmp .= $k.'/';
      if(!file_exists($destination_path.$tmp)){
       @mkdir($destination_path.$tmp, 0755);
       @chmod($destination_path.$tmp, 0755 );
      }
     }
    }
    
    if(zip_entry_open($zip, $zip_entry, "r")){
     if($fd = fopen($destination_path.$complete_name, 'w')){
      fwrite($fd, zip_entry_read($zip_entry, zip_entry_filesize($zip_entry)));
      fclose($fd);
      @chmod($destination_path, 0644);
     } else {
      echo "fopen($destination_path.$complete_name) error<br>";
     }
     zip_entry_close($zip_entry);
    } else {
     echo "zip_entry_open($zip,$zip_entry) error<br>";
    }
   }
  }
  zip_close($zip);
 }
}

Example Usage:

Zipping Files:

$current_dir = getcwd();
$files = array('front-page.php', 'functions.php', 'header.php', 'carlo-fontanos');
$zipname = 'myzip_carlo.zip';

ignore_user_abort(true);
ini_set("display_errors",0);
ini_set("max_execution_time",0);
    
$zipfile = new zip_file($zipname);
if($zipfile){
 $zipfile->set_options(array('basedir'=>$current_dir,'overwrite'=>1,'level'=>3));
 
 if($files){
  foreach($files as $file){
   $zipfile->add_files(trim($file));
  }
 }
 
 $zipfile->create_archive();
}

unset($zipfile);

Unzipping Files:

$current_dir = getcwd();
unzip_file('theme-backup-12-11-2017.zip', $current_dir . '/', $current_dir . '/extracted/');


Do you need help with a project? or have a new project in mind that you need help with?

Contact Me