TYPO3 CMS  TYPO3_8-7
UploadExtensionFileController.php
Go to the documentation of this file.
1 <?php
3 
4 /*
5  * This file is part of the TYPO3 CMS project.
6  *
7  * It is free software; you can redistribute it and/or modify it under
8  * the terms of the GNU General Public License, either version 2
9  * of the License, or any later version.
10  *
11  * For the full copyright and license information, please read the
12  * LICENSE.txt file that was distributed with this source code.
13  *
14  * The TYPO3 project - inspiring people to share!
15  */
16 
22 
28 {
33 
38 
43 
47  protected $terUtility;
48 
52  protected $managementService;
53 
57  protected $extensionBackupPath = '';
58 
62  protected $removeFromOriginalPath = false;
63 
67  public function injectConfigurationUtility(\TYPO3\CMS\Extensionmanager\Utility\ConfigurationUtility $configurationUtility)
68  {
69  $this->configurationUtility = $configurationUtility;
70  }
71 
75  public function injectExtensionRepository(\TYPO3\CMS\Extensionmanager\Domain\Repository\ExtensionRepository $extensionRepository)
76  {
77  $this->extensionRepository = $extensionRepository;
78  }
79 
83  public function injectFileHandlingUtility(\TYPO3\CMS\Extensionmanager\Utility\FileHandlingUtility $fileHandlingUtility)
84  {
85  $this->fileHandlingUtility = $fileHandlingUtility;
86  }
87 
91  public function injectTerUtility(\TYPO3\CMS\Extensionmanager\Utility\Connection\TerUtility $terUtility)
92  {
93  $this->terUtility = $terUtility;
94  }
95 
99  public function injectManagementService(\TYPO3\CMS\Extensionmanager\Service\ExtensionManagementService $managementService)
100  {
101  $this->managementService = $managementService;
102  }
103 
107  public function __destruct()
108  {
109  $this->removeBackupFolder();
110  }
111 
115  public function formAction()
116  {
118  throw new ExtensionManagerException(
119  'Composer mode is active. You are not allowed to upload any extension file.',
120  1444725828
121  );
122  }
123  }
124 
131  public function extractAction($overwrite = false)
132  {
134  throw new ExtensionManagerException(
135  'Composer mode is active. You are not allowed to upload any extension file.',
136  1444725853
137  );
138  }
139  $file = $_FILES['tx_extensionmanager_tools_extensionmanagerextensionmanager'];
140  $fileName = pathinfo($file['name']['extensionFile'], PATHINFO_BASENAME);
141  try {
142  // If the file name isn't valid an error will be thrown
143  $this->checkFileName($fileName);
144  if (!empty($file['tmp_name']['extensionFile'])) {
145  $tempFile = GeneralUtility::upload_to_tempfile($file['tmp_name']['extensionFile']);
146  } else {
147  throw new ExtensionManagerException(
148  'Creating temporary file failed. Check your upload_max_filesize and post_max_size limits.',
149  1342864339
150  );
151  }
152  $extensionData = $this->extractExtensionFromFile($tempFile, $fileName, $overwrite);
153  $emConfiguration = $this->configurationUtility->getCurrentConfiguration('extensionmanager');
154  if (!$emConfiguration['automaticInstallation']['value']) {
155  $this->addFlashMessage(
156  $this->translate('extensionList.uploadFlashMessage.message', [$extensionData['extKey']]),
157  $this->translate('extensionList.uploadFlashMessage.title'),
159  );
160  } else {
161  if ($this->activateExtension($extensionData['extKey'])) {
162  $this->addFlashMessage(
163  $this->translate('extensionList.installedFlashMessage.message', [$extensionData['extKey']]),
164  '',
166  );
167  } else {
168  $this->redirect('unresolvedDependencies', 'List', null, ['extensionKey' => $extensionData['extKey']]);
169  }
170  }
171  } catch (\TYPO3\CMS\Extbase\Mvc\Exception\StopActionException $exception) {
172  throw $exception;
173  } catch (DependencyConfigurationNotFoundException $exception) {
174  $this->addFlashMessage($exception->getMessage(), '', FlashMessage::ERROR);
175  } catch (\Exception $exception) {
176  $this->removeExtensionAndRestoreFromBackup($fileName);
177  $this->addFlashMessage($exception->getMessage(), '', FlashMessage::ERROR);
178  }
179  $this->redirect('index', 'List', null, [
180  self::TRIGGER_RefreshModuleMenu => true,
181  self::TRIGGER_RefreshTopbar => true
182  ]);
183  }
184 
191  public function checkFileName($fileName)
192  {
193  $extension = pathinfo($fileName, PATHINFO_EXTENSION);
194  if (empty($fileName)) {
195  throw new ExtensionManagerException('No file given.', 1342858852);
196  }
197  if ($extension !== 't3x' && $extension !== 'zip') {
198  throw new ExtensionManagerException('Wrong file format "' . $extension . '" given. Allowed formats are t3x and zip.', 1342858853);
199  }
200  }
201 
212  public function extractExtensionFromFile($uploadPath, $fileName, $overwrite)
213  {
214  $fileExtension = pathinfo($fileName, PATHINFO_EXTENSION);
215  if ($fileExtension === 't3x') {
216  $extensionData = $this->getExtensionFromT3xFile($uploadPath, $overwrite);
217  } else {
218  $extensionData = $this->getExtensionFromZipFile($uploadPath, $fileName, $overwrite);
219  }
220 
221  return $extensionData;
222  }
223 
228  public function activateExtension($extensionKey)
229  {
230  $this->managementService->reloadPackageInformation($extensionKey);
231  $extension = $this->managementService->getExtension($extensionKey);
232  return is_array($this->managementService->installExtension($extension));
233  }
234 
244  protected function getExtensionFromT3xFile($file, $overwrite = false)
245  {
246  $fileContent = file_get_contents($file);
247  if (!$fileContent) {
248  throw new ExtensionManagerException('File had no or wrong content.', 1342859339);
249  }
250  $extensionData = $this->terUtility->decodeExchangeData($fileContent);
251  if (empty($extensionData['extKey'])) {
252  throw new ExtensionManagerException('Decoding the file went wrong. No extension key found', 1342864309);
253  }
254  $isExtensionAvailable = $this->managementService->isAvailable($extensionData['extKey']);
255  if (!$overwrite && $isExtensionAvailable) {
256  throw new ExtensionManagerException($this->translate('extensionList.overwritingDisabled'), 1342864310);
257  }
258  if ($isExtensionAvailable) {
259  $this->copyExtensionFolderToTempFolder($extensionData['extKey']);
260  }
261  $this->removeFromOriginalPath = true;
262  $extension = $this->extensionRepository->findOneByExtensionKeyAndVersion($extensionData['extKey'], $extensionData['EM_CONF']['version']);
263  $this->fileHandlingUtility->unpackExtensionFromExtensionDataArray($extensionData, $extension);
264 
265  if (empty($extension)
266  && empty($extensionData['EM_CONF']['constraints'])
267  && !isset($extensionData['FILES']['ext_emconf.php'])
268  && !isset($extensionData['FILES']['/ext_emconf.php'])
269  ) {
270  throw new DependencyConfigurationNotFoundException('Extension cannot be installed automatically because no dependencies could be found! Please check dependencies manually (on typo3.org) before installing the extension.', 1439587168);
271  }
272 
273  return $extensionData;
274  }
275 
288  protected function getExtensionFromZipFile($file, $fileName, $overwrite = false)
289  {
290  // Remove version and extension from filename to determine the extension key
291  $extensionKey = $this->getExtensionKeyFromFileName($fileName);
292  $isExtensionAvailable = $this->managementService->isAvailable($extensionKey);
293  if (!$overwrite && $isExtensionAvailable) {
294  throw new ExtensionManagerException('Extension is already available and overwriting is disabled.', 1342864311);
295  }
296  if ($isExtensionAvailable) {
297  $this->copyExtensionFolderToTempFolder($extensionKey);
298  }
299  $this->removeFromOriginalPath = true;
300  $this->fileHandlingUtility->unzipExtensionFromFile($file, $extensionKey);
301 
302  return ['extKey' => $extensionKey];
303  }
304 
311  protected function getExtensionKeyFromFileName($fileName)
312  {
313  return preg_replace('/_(\\d+)(\\.|\\-)(\\d+)(\\.|\\-)(\\d+).*/i', '', strtolower(substr($fileName, 0, -4)));
314  }
315 
322  protected function copyExtensionFolderToTempFolder($extensionKey)
323  {
324  $this->extensionBackupPath = PATH_site . 'typo3temp/var/transient/' . $extensionKey . substr(sha1($extensionKey . microtime()), 0, 7) . '/';
325  GeneralUtility::mkdir($this->extensionBackupPath);
327  $this->fileHandlingUtility->getExtensionDir($extensionKey),
329  );
330  }
331 
338  protected function removeExtensionAndRestoreFromBackup($fileName)
339  {
340  $extDirPath = $this->fileHandlingUtility->getExtensionDir($this->getExtensionKeyFromFileName($fileName));
341  if ($this->removeFromOriginalPath && is_dir($extDirPath)) {
342  GeneralUtility::rmdir($extDirPath, true);
343  }
344  if (!empty($this->extensionBackupPath)) {
345  GeneralUtility::mkdir($extDirPath);
346  GeneralUtility::copyDirectory($this->extensionBackupPath, $extDirPath);
347  }
348  }
349 
353  protected function removeBackupFolder()
354  {
355  if (!empty($this->extensionBackupPath)) {
356  GeneralUtility::rmdir($this->extensionBackupPath, true);
357  $this->extensionBackupPath = '';
358  }
359  }
360 }
injectConfigurationUtility(\TYPO3\CMS\Extensionmanager\Utility\ConfigurationUtility $configurationUtility)
injectFileHandlingUtility(\TYPO3\CMS\Extensionmanager\Utility\FileHandlingUtility $fileHandlingUtility)
redirect($actionName, $controllerName=null, $extensionName=null, array $arguments=null, $pageUid=null, $delay=0, $statusCode=303)
static copyDirectory($source, $destination)
static upload_to_tempfile($uploadedFileName)
static rmdir($path, $removeNonEmpty=false)
injectExtensionRepository(\TYPO3\CMS\Extensionmanager\Domain\Repository\ExtensionRepository $extensionRepository)
addFlashMessage($messageBody, $messageTitle='', $severity=\TYPO3\CMS\Core\Messaging\AbstractMessage::OK, $storeInSession=true)
injectManagementService(\TYPO3\CMS\Extensionmanager\Service\ExtensionManagementService $managementService)
injectTerUtility(\TYPO3\CMS\Extensionmanager\Utility\Connection\TerUtility $terUtility)