PageRenderTime 54ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/src/Adapter/Module/ModuleZipManager.php

https://bitbucket.org/fanch1/testlb
PHP | 214 lines | 127 code | 22 blank | 65 comment | 14 complexity | 533cb07f90c25954f411afee00dac904 MD5 | raw file
Possible License(s): BSD-3-Clause, Apache-2.0, BSD-2-Clause, GPL-2.0, GPL-3.0
  1. <?php
  2. /**
  3. * 2007-2017 PrestaShop
  4. *
  5. * NOTICE OF LICENSE
  6. *
  7. * This source file is subject to the Open Software License (OSL 3.0)
  8. * that is bundled with this package in the file LICENSE.txt.
  9. * It is also available through the world-wide-web at this URL:
  10. * https://opensource.org/licenses/OSL-3.0
  11. * If you did not receive a copy of the license and are unable to
  12. * obtain it through the world-wide-web, please send an email
  13. * to license@prestashop.com so we can send you a copy immediately.
  14. *
  15. * DISCLAIMER
  16. *
  17. * Do not edit or add to this file if you wish to upgrade PrestaShop to newer
  18. * versions in the future. If you wish to customize PrestaShop for your
  19. * needs please refer to http://www.prestashop.com for more information.
  20. *
  21. * @author PrestaShop SA <contact@prestashop.com>
  22. * @copyright 2007-2017 PrestaShop SA
  23. * @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
  24. * International Registered Trademark & Property of PrestaShop SA
  25. */
  26. namespace PrestaShop\PrestaShop\Adapter\Module;
  27. use Symfony\Component\Filesystem\Filesystem;
  28. use Symfony\Component\Finder\Finder;
  29. use Symfony\Component\Translation\TranslatorInterface;
  30. use Exception;
  31. use Tools;
  32. use ZipArchive;
  33. class ModuleZipManager
  34. {
  35. /*
  36. * Data
  37. */
  38. private static $sources = array();
  39. private $attributes = array('name', 'sandboxPath');
  40. /*
  41. * Services
  42. */
  43. /**
  44. * @var Symfony\Component\Filesystem\Filesystem
  45. */
  46. private $filesystem;
  47. private $translator;
  48. public function __construct(Filesystem $filesystem, TranslatorInterface $translator)
  49. {
  50. $this->filesystem = $filesystem;
  51. $this->translator = $translator;
  52. }
  53. /**
  54. * Detect module name from zipball.
  55. * @param String $source
  56. * @return String
  57. * @throws Exception If unable to find the module name
  58. */
  59. public function getName($source)
  60. {
  61. $this->initSource($source);
  62. if ($this->get($source, 'name') !== null) {
  63. return $this->get($source, 'name');
  64. }
  65. if (!file_exists($source)) {
  66. throw new Exception(
  67. $this->translator->trans(
  68. 'Unable to find uploaded module at the following path: %file%',
  69. array('%file%' => $source),
  70. 'Admin.Modules.Notification'));
  71. }
  72. $sandboxPath = $this->getSandboxPath($source);
  73. $zip = new ZipArchive();
  74. if ($zip->open($source) === false || !$zip->extractTo($sandboxPath) || !$zip->close()) {
  75. throw new Exception(
  76. $this->translator->trans(
  77. 'Cannot extract module in %path% to get its name. %error%',
  78. array(
  79. '%path%' => $sandboxPath,
  80. '%error%' => $zip->getStatusString()),
  81. 'Admin.Modules.Notification'));
  82. }
  83. // Check the structure and get the module name
  84. $directories = Finder::create()
  85. ->directories()
  86. ->in($sandboxPath)
  87. ->depth('== 0')
  88. ->exclude(['__MACOSX'])
  89. ->ignoreVCS(true);
  90. $validModuleStructure = false;
  91. // We must have only one folder in the zip, which contains the module files
  92. if (iterator_count($directories->directories()) == 1) {
  93. $directories = iterator_to_array($directories);
  94. $moduleName = basename(current($directories)->getFileName());
  95. // Inside of this folder, we MUST have a file called <module name>.php
  96. $moduleFolder = Finder::create()
  97. ->files()
  98. ->in($sandboxPath.$moduleName)
  99. ->depth('== 0')
  100. ->exclude(['__MACOSX'])
  101. ->ignoreVCS(true);
  102. foreach (iterator_to_array($moduleFolder) as $file) {
  103. if ($file->getFileName() === $moduleName.'.php') {
  104. $validModuleStructure = true;
  105. break;
  106. }
  107. }
  108. }
  109. if (!$validModuleStructure) {
  110. $this->filesystem->remove($sandboxPath);
  111. throw new Exception($this->translator->trans(
  112. 'This file does not seem to be a valid module zip',
  113. array(),
  114. 'Admin.Modules.Notification'));
  115. }
  116. $this->set($source, 'name', $moduleName);
  117. return $moduleName;
  118. }
  119. /**
  120. * When ready, send the module Zip in the modules folder
  121. * @param String $source
  122. */
  123. public function storeInModulesFolder($source)
  124. {
  125. $name = $this->getName($source);
  126. $sandboxPath = $this->get($source, 'sandboxPath');
  127. // Now we are sure to have a valid module, we copy it to the modules folder
  128. $modulePath = _PS_MODULE_DIR_.$name;
  129. $this->filesystem->mkdir($modulePath);
  130. $this->filesystem->mirror(
  131. $sandboxPath.$name,
  132. $modulePath,
  133. null,
  134. array('override' => true)
  135. );
  136. $this->filesystem->remove($sandboxPath);
  137. }
  138. private function getSandboxPath($source)
  139. {
  140. $sandboxPath = $this->get($source, 'sandboxPath');
  141. if ($sandboxPath === null) {
  142. $sandboxPath = _PS_CACHE_DIR_.'sandbox/'.uniqid().'/';
  143. $this->filesystem->mkdir($sandboxPath);
  144. $this->set($source, 'sandboxPath', $sandboxPath);
  145. }
  146. return $sandboxPath;
  147. }
  148. /**
  149. * Get a attribute value about a source
  150. * @param String $source
  151. * @param String $attr defined in $attributes
  152. * @return mixed
  153. * @throws Exception if $attr value not in list
  154. */
  155. private function get($source, $attr)
  156. {
  157. if (!in_array($attr, $this->attributes)) {
  158. throw new Exception('Unknow source attribute');
  159. }
  160. return self::$sources[$source][$attr];
  161. }
  162. /**
  163. * Store a value about a source
  164. * @param String $source
  165. * @param String $attr
  166. * @param mixed $value
  167. * @throws Exception if $attr value not in list
  168. */
  169. private function set($source, $attr, $value)
  170. {
  171. if (!in_array($attr, $this->attributes)) {
  172. throw new Exception('Unknow source attribute');
  173. }
  174. self::$sources[$source][$attr] = $value;
  175. }
  176. /**
  177. * Init all data regarding a source before proceeding it
  178. * @param String $source
  179. */
  180. private function initSource($source)
  181. {
  182. if ((filter_var($source, FILTER_VALIDATE_URL))) {
  183. $source = Tools::createFileFromUrl($source);
  184. }
  185. if (isset(self::$sources[$source])) {
  186. return;
  187. }
  188. foreach ($this->attributes as $attr) {
  189. self::$sources[$source][$attr] = null;
  190. }
  191. }
  192. }