Gentics Portal.Node PHP API
 All Classes Namespaces Functions Variables Pages
ZipHelper.php
1 <?php
2 /**
3  * Class for compressing and extracting set of folders/files in zip format
4  */
5 class ZipHelper
6 {
7  /**
8  * Recursively zip folder
9  *
10  * @param array $sources array of sources. String key means source contains string of content.
11  * Otherwise source contains name of file
12  * @param string $destination zip archive destination folder
13  *
14  * @throws Exception
15  * @return bool
16  */
17  public static function compress($sources, $destination)
18  {
19  if (!extension_loaded('zip')) {
20  throw new Exception('Php Zip extension not loaded');
21  }
22  if (empty($sources)) {
23  return false;
24  }
25  if (is_string($sources)) {
26  $sources = array($sources);
27  }
28  $zip = new ZipArchive();
29  if (!$zip->open($destination, ZIPARCHIVE::CREATE | ZIPARCHIVE::OVERWRITE | ZIPARCHIVE::CHECKCONS)) {
30  return false;
31  }
32  foreach ($sources as $name => $source) {
33  if (is_int($name)) {
34  $exclude = array();
35  $sourcePath = $source;
36  if (is_array($source)) {
37  $sourcePath = $source['path'];
38  if (isset($source['exclude'])) {
39  $exclude = $source['exclude'];
40  }
41  }
42  $sourcePath = str_replace('\\', '/', realpath($sourcePath));
43  if (is_dir($sourcePath) === true) {
44  $iterator = new RecursiveIteratorIterator(
45  new RecursiveDirectoryIterator($sourcePath, RecursiveDirectoryIterator::SKIP_DOTS),
46  RecursiveIteratorIterator::SELF_FIRST
47  );
48  foreach ($iterator as $file) {
49  if ($file->isLink()) {
50  continue;
51  }
52  //for windows systems
53  $file = str_replace('\\', '/', realpath($file));
54  $zipPath = str_replace($sourcePath . '/', '', $file);
55  //if in $exclude skip
56  $skip = count(
57  array_filter(
58  $exclude,
59  function($ex) use ($zipPath)
60  {
61  return strpos($zipPath, $ex) === 0;
62  }
63  )
64  ) > 0;
65  if ($skip) {
66  continue;
67  }
68  //add to archive
69  if (is_dir($file) === true) {
70  $zip->addEmptyDir($zipPath . '/');
71  } else if (is_file($file) === true) {
72  $zip->addFromString($zipPath, file_get_contents($file));
73  }
74  }
75  } else if (is_file($sourcePath) === true) {
76  $zip->addFromString(basename($sourcePath), file_get_contents($sourcePath));
77  }
78  } else {
79  $zip->addFromString($name, $source);
80  }
81  }
82  return $zip->close();
83  }
84 
85  /**
86  * Extract zip archive to folder
87  *
88  * @param string $zipPath path to zip archive
89  * @param string $dest destination folder
90  * @param bool $merge if false replace destination folder by new folders from archive, otherwise merge folders
91  *
92  * @throws Exception
93  * @return bool true if extraction success, false otherwise
94  */
95  public static function extract($zipPath, $dest, $merge = true)
96  {
97  if (!extension_loaded('zip')) {
98  throw new Exception('Php Zip extension not loaded');
99  }
100  $zipH = zip_open($zipPath);
101  if (!$zipH) {
102  throw new Exception("Can't open archive $zipPath");
103  }
104  if (file_exists($dest) && !is_writable($dest)) {
105  throw new Exception("Destination directory $dest is not writable");
106  } elseif (!is_writable($dest) && !mkdir($dest)) {
107  throw new Exception("Can't create directory in $dest");
108  }
109 
110  while ($entry = zip_read($zipH)) {
111  $entryPath = zip_entry_name($entry);
112  $destPath = $dest . '/' . $entryPath;
113  if (substr($entryPath, -1) == '/') {
114  if (file_exists($destPath)) {
115  if (!$merge) {
116  FileHelper::rmdirr($destPath);
117  mkdir($destPath);
118  }
119  } else {
120  mkdir($destPath);
121  }
122  } else {
123  if (!is_dir($dir = dirname($destPath))) {
124  mkdir($dir, 0777, true);
125  }
126  if (@file_put_contents($destPath, zip_entry_read($entry, zip_entry_filesize($entry))) === false) {
127  throw new Exception("$destPath is not writable");
128  }
129  }
130  }
131  }
132 }