‪TYPO3CMS  ‪main
UploadExtensionFileController.php
Go to the documentation of this file.
1 <?php
2 
3 declare(strict_types=1);
4 
5 /*
6  * This file is part of the TYPO3 CMS project.
7  *
8  * It is free software; you can redistribute it and/or modify it under
9  * the terms of the GNU General Public License, either version 2
10  * of the License, or any later version.
11  *
12  * For the full copyright and license information, please read the
13  * LICENSE.txt file that was distributed with this source code.
14  *
15  * The TYPO3 project - inspiring people to share!
16  */
17 
19 
20 use Psr\Http\Message\ResponseInterface;
30 
37 {
39 
40  protected string ‪$extensionBackupPath = '';
41  protected bool ‪$removeFromOriginalPath = false;
42 
43  public function ‪__construct(
44  protected readonly ‪FileHandlingUtility $fileHandlingUtility,
45  protected readonly ‪ExtensionManagementService $managementService,
46  protected readonly ‪ExtensionConfiguration $extensionConfiguration,
47  ) {
48  }
49 
53  public function ‪__destruct()
54  {
55  $this->‪removeBackupFolder();
56  }
57 
61  public function ‪formAction(): ResponseInterface
62  {
64  throw new ExtensionManagerException(
65  'Composer mode is active. You are not allowed to upload any extension file.',
66  1444725828
67  );
68  }
69 
70  return $this->‪htmlResponse();
71  }
72 
78  public function ‪extractAction(bool $overwrite = false): ResponseInterface
79  {
81  throw new ExtensionManagerException(
82  'Composer mode is active. You are not allowed to upload any extension file.',
83  1444725853
84  );
85  }
86 
87  try {
88  $fileName = null;
89  $file = $this->request->getUploadedFiles()['extensionFile'] ?? null;
90  if ($file === null) {
91  throw new ExtensionManagerException(
92  'Uploading file failed. Check your upload_max_filesize and post_max_size limits.',
93  1342864339
94  );
95  }
96  $fileName = pathinfo($file->getClientFilename(), PATHINFO_BASENAME);
97  // If the file name isn't valid an error will be thrown
98  $this->‪checkFileName($fileName);
99 
100  $tempFile = GeneralUtility::tempnam('upload_temp_');
101  $file->moveTo($tempFile);
102 
103  // Remove version and extension from filename to determine the extension key
104  $extensionKey = $this->‪getExtensionKeyFromFileName($fileName);
105  if (empty($extensionKey)) {
106  throw new ExtensionManagerException(
107  'Could not extract extension key from uploaded file name. File name must be something like "my_extension_4.2.2.zip".',
108  1603087515
109  );
110  }
111  $this->‪extractExtensionFromZipFile($tempFile, $extensionKey, (bool)$overwrite);
112  $isAutomaticInstallationEnabled = (bool)$this->extensionConfiguration->get('extensionmanager', 'automaticInstallation');
113  if (!$isAutomaticInstallationEnabled) {
114  $this->‪addFlashMessage(
115  $this->‪translate('extensionList.uploadFlashMessage.message', [$extensionKey]),
116  $this->‪translate('extensionList.uploadFlashMessage.title')
117  );
118  } else {
119  // @todo This cannot work without reloading the package information
120  if ($this->‪activateExtension($extensionKey)) {
121  $this->‪addFlashMessage(
122  $this->‪translate('extensionList.installedFlashMessage.message', [$extensionKey]),
123  ''
124  );
125  } else {
126  return $this->‪redirect(
127  'unresolvedDependencies',
128  'List',
129  null,
130  [
131  'extensionKey' => $extensionKey,
132  'returnAction' => ['controller' => 'List', 'action' => 'index'],
133  ]
134  );
135  }
136  }
137  } catch (InvalidFileException $exception) {
138  $this->‪addFlashMessage($exception->getMessage(), '', ContextualFeedbackSeverity::ERROR);
139  } catch (\Exception $exception) {
140  if ($fileName !== null) {
141  $this->‪removeExtensionAndRestoreFromBackup($fileName);
142  }
143  $this->‪addFlashMessage($exception->getMessage(), '', ContextualFeedbackSeverity::ERROR);
144  }
145  return $this->‪redirect('index', 'List', null, [
146  self::TRIGGER_RefreshModuleMenu => true,
147  self::TRIGGER_RefreshTopbar => true,
148  ]);
149  }
150 
157  protected function ‪checkFileName($fileName)
158  {
159  if (empty($fileName)) {
160  throw new InvalidFileException('No file given.', 1342858852);
161  }
162  $fileExtension = pathinfo($fileName, PATHINFO_EXTENSION);
163  if ($fileExtension !== 'zip') {
164  throw new InvalidFileException('Wrong file format "' . $fileExtension . '" given. Only .zip files are allowed.', 1342858853);
165  }
166  }
167 
168  protected function ‪activateExtension(string $extensionKey): bool
169  {
170  $this->managementService->reloadPackageInformation($extensionKey);
171  $extension = $this->managementService->getExtension($extensionKey);
172  return is_array($this->managementService->installExtension($extension));
173  }
174 
182  protected function ‪extractExtensionFromZipFile(string $uploadedFile, string $extensionKey, bool $overwrite = false): string
183  {
184  $isExtensionAvailable = $this->managementService->isAvailable($extensionKey);
185  if (!$overwrite && $isExtensionAvailable) {
186  throw new ‪ExtensionManagerException('Extension is already available and overwriting is disabled.', 1342864311);
187  }
188  if ($isExtensionAvailable) {
189  $this->‪copyExtensionFolderToTempFolder($extensionKey);
190  }
191  $this->removeFromOriginalPath = true;
192  $this->fileHandlingUtility->unzipExtensionFromFile($uploadedFile, $extensionKey);
193  return $extensionKey;
194  }
195 
205  protected function ‪getExtensionKeyFromFileName(string $fileName): string
206  {
207  return (string)preg_replace('/_(\\d+)(\\.|\\-)(\\d+)(\\.|\\-)(\\d+).*/i', '', strtolower(substr($fileName, 0, -4)));
208  }
209 
213  protected function ‪copyExtensionFolderToTempFolder(string $extensionKey): void
214  {
215  $this->extensionBackupPath = ‪Environment::getVarPath() . '/transient/' . $extensionKey . substr(sha1($extensionKey . microtime()), 0, 7) . '/';
216  ‪GeneralUtility::mkdir($this->extensionBackupPath);
217  GeneralUtility::copyDirectory(
218  $this->fileHandlingUtility->getExtensionDir($extensionKey),
219  $this->extensionBackupPath
220  );
221  }
222 
229  protected function ‪removeExtensionAndRestoreFromBackup(string $fileName): void
230  {
231  $extDirPath = $this->fileHandlingUtility->getExtensionDir($this->‪getExtensionKeyFromFileName($fileName));
232  if ($this->removeFromOriginalPath && is_dir($extDirPath)) {
233  ‪GeneralUtility::rmdir($extDirPath, true);
234  }
235  if (!empty($this->extensionBackupPath)) {
236  ‪GeneralUtility::mkdir($extDirPath);
237  GeneralUtility::copyDirectory($this->extensionBackupPath, $extDirPath);
238  }
239  }
240 
244  protected function ‪removeBackupFolder(): void
245  {
246  if (!empty($this->extensionBackupPath)) {
247  ‪GeneralUtility::rmdir($this->extensionBackupPath, true);
248  $this->extensionBackupPath = '';
249  }
250  }
251 }
‪TYPO3\CMS\Extbase\Mvc\Controller\ActionController\redirect
‪redirect($actionName, $controllerName=null, $extensionName=null, array $arguments=null, $pageUid=null, $_=null, $statusCode=303)
Definition: ActionController.php:766
‪TYPO3\CMS\Extensionmanager\Controller\UploadExtensionFileController\formAction
‪formAction()
Definition: UploadExtensionFileController.php:60
‪TYPO3\CMS\Core\Package\Exception
Definition: Exception.php:22
‪TYPO3\CMS\Extensionmanager\Controller\UploadExtensionFileController
Definition: UploadExtensionFileController.php:37
‪TYPO3\CMS\Core\Configuration\ExtensionConfiguration
Definition: ExtensionConfiguration.php:47
‪TYPO3\CMS\Extensionmanager\Controller\AbstractController\translate
‪translate(string $key, ?array $arguments=null)
Definition: AbstractController.php:51
‪TYPO3\CMS\Core\Core\Environment\isComposerMode
‪static isComposerMode()
Definition: Environment.php:137
‪TYPO3\CMS\Extensionmanager\Controller\UploadExtensionFileController\__destruct
‪__destruct()
Definition: UploadExtensionFileController.php:52
‪TYPO3\CMS\Extensionmanager\Controller\UploadExtensionFileController\extractExtensionFromZipFile
‪extractExtensionFromZipFile(string $uploadedFile, string $extensionKey, bool $overwrite=false)
Definition: UploadExtensionFileController.php:181
‪TYPO3\CMS\Extensionmanager\Controller\UploadExtensionFileController\removeExtensionAndRestoreFromBackup
‪removeExtensionAndRestoreFromBackup(string $fileName)
Definition: UploadExtensionFileController.php:228
‪TYPO3\CMS\Extensionmanager\Controller
Definition: AbstractController.php:18
‪TYPO3\CMS\Extensionmanager\Controller\UploadExtensionFileController\getExtensionKeyFromFileName
‪string getExtensionKeyFromFileName(string $fileName)
Definition: UploadExtensionFileController.php:204
‪TYPO3\CMS\Core\Core\Environment\getVarPath
‪static getVarPath()
Definition: Environment.php:197
‪TYPO3\CMS\Extensionmanager\Utility\FileHandlingUtility
Definition: FileHandlingUtility.php:36
‪TYPO3\CMS\Core\Type\ContextualFeedbackSeverity
‪ContextualFeedbackSeverity
Definition: ContextualFeedbackSeverity.php:25
‪TYPO3\CMS\Extensionmanager\Exception\InvalidFileException
Definition: InvalidFileException.php:24
‪TYPO3\CMS\Core\Security\BlockSerializationTrait
Definition: BlockSerializationTrait.php:28
‪TYPO3\CMS\Extensionmanager\Controller\UploadExtensionFileController\copyExtensionFolderToTempFolder
‪copyExtensionFolderToTempFolder(string $extensionKey)
Definition: UploadExtensionFileController.php:212
‪TYPO3\CMS\Extbase\Mvc\Controller\ActionController\htmlResponse
‪htmlResponse(string $html=null)
Definition: ActionController.php:886
‪TYPO3\CMS\Extbase\Mvc\Controller\ActionController\addFlashMessage
‪addFlashMessage($messageBody, $messageTitle='', $severity=ContextualFeedbackSeverity::OK, $storeInSession=true)
Definition: ActionController.php:712
‪TYPO3\CMS\Extensionmanager\Controller\UploadExtensionFileController\activateExtension
‪activateExtension(string $extensionKey)
Definition: UploadExtensionFileController.php:167
‪TYPO3\CMS\Extensionmanager\Controller\UploadExtensionFileController\$removeFromOriginalPath
‪bool $removeFromOriginalPath
Definition: UploadExtensionFileController.php:40
‪TYPO3\CMS\Extensionmanager\Exception\ExtensionManagerException
Definition: ExtensionManagerException.php:24
‪TYPO3\CMS\Extensionmanager\Controller\AbstractController
Definition: AbstractController.php:32
‪TYPO3\CMS\Extensionmanager\Controller\UploadExtensionFileController\$extensionBackupPath
‪string $extensionBackupPath
Definition: UploadExtensionFileController.php:39
‪TYPO3\CMS\Extensionmanager\Service\ExtensionManagementService
Definition: ExtensionManagementService.php:36
‪TYPO3\CMS\Extensionmanager\Controller\UploadExtensionFileController\removeBackupFolder
‪removeBackupFolder()
Definition: UploadExtensionFileController.php:243
‪TYPO3\CMS\Core\Core\Environment
Definition: Environment.php:41
‪TYPO3\CMS\Extensionmanager\Controller\UploadExtensionFileController\checkFileName
‪checkFileName($fileName)
Definition: UploadExtensionFileController.php:156
‪TYPO3\CMS\Core\Utility\GeneralUtility\rmdir
‪static bool rmdir($path, $removeNonEmpty=false)
Definition: GeneralUtility.php:1806
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:51
‪TYPO3\CMS\Extensionmanager\Controller\UploadExtensionFileController\extractAction
‪extractAction(bool $overwrite=false)
Definition: UploadExtensionFileController.php:77
‪TYPO3\CMS\Core\Utility\GeneralUtility\mkdir
‪static bool mkdir($newFolder)
Definition: GeneralUtility.php:1736
‪TYPO3\CMS\Extensionmanager\Controller\UploadExtensionFileController\__construct
‪__construct(protected readonly FileHandlingUtility $fileHandlingUtility, protected readonly ExtensionManagementService $managementService, protected readonly ExtensionConfiguration $extensionConfiguration,)
Definition: UploadExtensionFileController.php:42