/sites/all/modules/contrib/civicrm/CRM/Utils/Zip.php

https://gitlab.com/virtualrealms/d7civicrm · PHP · 155 lines · 72 code · 12 blank · 71 comment · 24 complexity · 31324813228c40a3176e0a6938b22e78 MD5 · raw file

  1. <?php
  2. /*
  3. +--------------------------------------------------------------------+
  4. | CiviCRM version 5 |
  5. +--------------------------------------------------------------------+
  6. | Copyright CiviCRM LLC (c) 2004-2019 |
  7. +--------------------------------------------------------------------+
  8. | This file is a part of CiviCRM. |
  9. | |
  10. | CiviCRM is free software; you can copy, modify, and distribute it |
  11. | under the terms of the GNU Affero General Public License |
  12. | Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
  13. | |
  14. | CiviCRM is distributed in the hope that it will be useful, but |
  15. | WITHOUT ANY WARRANTY; without even the implied warranty of |
  16. | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
  17. | See the GNU Affero General Public License for more details. |
  18. | |
  19. | You should have received a copy of the GNU Affero General Public |
  20. | License and the CiviCRM Licensing Exception along |
  21. | with this program; if not, contact CiviCRM LLC |
  22. | at info[AT]civicrm[DOT]org. If you have questions about the |
  23. | GNU Affero General Public License or the licensing of CiviCRM, |
  24. | see the CiviCRM license FAQ at http://civicrm.org/licensing |
  25. +--------------------------------------------------------------------+
  26. */
  27. /**
  28. *
  29. * @package CRM
  30. * @copyright CiviCRM LLC (c) 2004-2019
  31. */
  32. /**
  33. * Utilities for working with zip files
  34. */
  35. class CRM_Utils_Zip {
  36. /**
  37. * Given a zip file which contains a single root directory, determine the root's name.
  38. *
  39. * @param ZipArchive $zip
  40. *
  41. * @return mixed
  42. * FALSE if #root level items !=1; otherwise, the name of base dir
  43. */
  44. public static function findBaseDirName(ZipArchive $zip) {
  45. $cnt = $zip->numFiles;
  46. $base = FALSE;
  47. $baselen = FALSE;
  48. for ($i = 0; $i < $cnt; $i++) {
  49. $filename = $zip->getNameIndex($i);
  50. if ($base === FALSE) {
  51. if (preg_match('/^[^\/]+\/$/', $filename) && $filename != './' && $filename != '../') {
  52. $base = $filename;
  53. $baselen = strlen($filename);
  54. }
  55. else {
  56. return FALSE;
  57. }
  58. }
  59. elseif (0 != substr_compare($base, $filename, 0, $baselen)) {
  60. return FALSE;
  61. }
  62. }
  63. return $base;
  64. }
  65. /**
  66. * Given a zip file, find all directory names in the root
  67. *
  68. * @param ZipArchive $zip
  69. *
  70. * @return array(string)
  71. * no trailing /
  72. */
  73. public static function findBaseDirs(ZipArchive $zip) {
  74. $cnt = $zip->numFiles;
  75. $basedirs = [];
  76. for ($i = 0; $i < $cnt; $i++) {
  77. $filename = $zip->getNameIndex($i);
  78. // hypothetically, ./ or ../ would not be legit here
  79. if (preg_match('/^[^\/]+\/$/', $filename) && $filename != './' && $filename != '../') {
  80. $basedirs[] = rtrim($filename, '/');
  81. }
  82. }
  83. return $basedirs;
  84. }
  85. /**
  86. * Determine the name of the folder within a zip.
  87. *
  88. * @param ZipArchive $zip
  89. * @param $expected
  90. *
  91. * @return string|bool
  92. * Return string or FALSE
  93. */
  94. public static function guessBasedir(ZipArchive $zip, $expected) {
  95. $candidate = FALSE;
  96. $basedirs = CRM_Utils_Zip::findBaseDirs($zip);
  97. if (in_array($expected, $basedirs)) {
  98. $candidate = $expected;
  99. }
  100. elseif (count($basedirs) == 1) {
  101. $candidate = array_shift($basedirs);
  102. }
  103. if ($candidate !== FALSE && preg_match('/^[a-zA-Z0-9]/', $candidate)) {
  104. return $candidate;
  105. }
  106. else {
  107. return FALSE;
  108. }
  109. }
  110. /**
  111. * An inefficient helper for creating a ZIP file from data in memory.
  112. * This is only intended for building temp files for unit-testing.
  113. *
  114. * @param string $zipName
  115. * file name.
  116. * @param array $dirs
  117. * Array, list of directory paths.
  118. * @param array $files
  119. * Array, keys are file names and values are file contents.
  120. * @return bool
  121. */
  122. public static function createTestZip($zipName, $dirs, $files) {
  123. $zip = new ZipArchive();
  124. $res = $zip->open($zipName, ZipArchive::CREATE);
  125. if ($res === TRUE) {
  126. foreach ($dirs as $dir) {
  127. if (!$zip->addEmptyDir($dir)) {
  128. return FALSE;
  129. }
  130. }
  131. foreach ($files as $fileName => $fileData) {
  132. if (!$zip->addFromString($fileName, $fileData)) {
  133. return FALSE;
  134. }
  135. }
  136. $zip->close();
  137. }
  138. else {
  139. return FALSE;
  140. }
  141. return TRUE;
  142. }
  143. }