‪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;
28 use TYPO3\CMS\Extensionmanager\Service\ExtensionManagementService;
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 
52  public function ‪__destruct()
53  {
54  $this->‪removeBackupFolder();
55  }
56 
60  public function ‪formAction(): ResponseInterface
61  {
63  throw new ExtensionManagerException(
64  'Composer mode is active. You are not allowed to upload any extension file.',
65  1444725828
66  );
67  }
68 
69  return $this->‪htmlResponse();
70  }
71 
77  public function ‪extractAction(bool $overwrite = false): ResponseInterface
78  {
80  throw new ExtensionManagerException(
81  'Composer mode is active. You are not allowed to upload any extension file.',
82  1444725853
83  );
84  }
85 
86  try {
87  $fileName = null;
88  $file = $this->request->getUploadedFiles()['extensionFile'] ?? null;
89  if ($file === null) {
90  throw new ExtensionManagerException(
91  'Uploading file failed. Check your upload_max_filesize and post_max_size limits.',
92  1342864339
93  );
94  }
95  $fileName = pathinfo($file->getClientFilename(), PATHINFO_BASENAME);
96  // If the file name isn't valid an error will be thrown
97  $this->‪checkFileName($fileName);
98 
99  $tempFile = GeneralUtility::tempnam('upload_temp_');
100  $file->moveTo($tempFile);
101 
102  // Remove version and extension from filename to determine the extension key
103  $extensionKey = $this->‪getExtensionKeyFromFileName($fileName);
104  if (empty($extensionKey)) {
105  throw new ExtensionManagerException(
106  'Could not extract extension key from uploaded file name. File name must be something like "my_extension_4.2.2.zip".',
107  1603087515
108  );
109  }
110  $this->‪extractExtensionFromZipFile($tempFile, $extensionKey, (bool)$overwrite);
111  $isAutomaticInstallationEnabled = (bool)$this->extensionConfiguration->get('extensionmanager', 'automaticInstallation');
112  if (!$isAutomaticInstallationEnabled) {
113  $this->‪addFlashMessage(
114  $this->‪translate('extensionList.uploadFlashMessage.message', [$extensionKey]),
115  $this->‪translate('extensionList.uploadFlashMessage.title')
116  );
117  } else {
118  // @todo This cannot work without reloading the package information
119  if ($this->‪activateExtension($extensionKey)) {
120  $this->‪addFlashMessage(
121  $this->‪translate('extensionList.installedFlashMessage.message', [$extensionKey]),
122  ''
123  );
124  } else {
125  return $this->‪redirect(
126  'unresolvedDependencies',
127  'List',
128  null,
129  [
130  'extensionKey' => $extensionKey,
131  'returnAction' => ['controller' => 'List', 'action' => 'index'],
132  ]
133  );
134  }
135  }
136  } catch (InvalidFileException $exception) {
137  $this->‪addFlashMessage($exception->getMessage(), '', ContextualFeedbackSeverity::ERROR);
138  } catch (\Exception $exception) {
139  if ($fileName !== null) {
140  $this->‪removeExtensionAndRestoreFromBackup($fileName);
141  }
142  $this->‪addFlashMessage($exception->getMessage(), '', ContextualFeedbackSeverity::ERROR);
143  }
144  return $this->‪redirect('index', 'List', null, [
145  self::TRIGGER_RefreshModuleMenu => true,
146  self::TRIGGER_RefreshTopbar => true,
147  ]);
148  }
149 
156  protected function ‪checkFileName($fileName)
157  {
158  if (empty($fileName)) {
159  throw new InvalidFileException('No file given.', 1342858852);
160  }
161  $fileExtension = pathinfo($fileName, PATHINFO_EXTENSION);
162  if ($fileExtension !== 'zip') {
163  throw new InvalidFileException('Wrong file format "' . $fileExtension . '" given. Only .zip files are allowed.', 1342858853);
164  }
165  }
166 
167  protected function ‪activateExtension(string $extensionKey): bool
168  {
169  $this->managementService->reloadPackageInformation($extensionKey);
170  $extension = $this->managementService->getExtension($extensionKey);
171  return is_array($this->managementService->installExtension($extension));
172  }
173 
181  protected function ‪extractExtensionFromZipFile(string $uploadedFile, string $extensionKey, bool $overwrite = false): string
182  {
183  $isExtensionAvailable = $this->managementService->isAvailable($extensionKey);
184  if (!$overwrite && $isExtensionAvailable) {
185  throw new ‪ExtensionManagerException('Extension is already available and overwriting is disabled.', 1342864311);
186  }
187  if ($isExtensionAvailable) {
188  $this->‪copyExtensionFolderToTempFolder($extensionKey);
189  }
190  $this->removeFromOriginalPath = true;
191  $this->fileHandlingUtility->unzipExtensionFromFile($uploadedFile, $extensionKey);
192  return $extensionKey;
193  }
194 
204  protected function ‪getExtensionKeyFromFileName(string $fileName): string
205  {
206  return (string)preg_replace('/_(\\d+)(\\.|\\-)(\\d+)(\\.|\\-)(\\d+).*/i', '', strtolower(substr($fileName, 0, -4)));
207  }
208 
212  protected function ‪copyExtensionFolderToTempFolder(string $extensionKey): void
213  {
214  $this->extensionBackupPath = ‪Environment::getVarPath() . '/transient/' . $extensionKey . substr(sha1($extensionKey . microtime()), 0, 7) . '/';
215  ‪GeneralUtility::mkdir($this->extensionBackupPath);
216  GeneralUtility::copyDirectory(
217  $this->fileHandlingUtility->getExtensionDir($extensionKey),
218  $this->extensionBackupPath
219  );
220  }
221 
228  protected function ‪removeExtensionAndRestoreFromBackup(string $fileName): void
229  {
230  $extDirPath = $this->fileHandlingUtility->getExtensionDir($this->‪getExtensionKeyFromFileName($fileName));
231  if ($this->removeFromOriginalPath && is_dir($extDirPath)) {
232  ‪GeneralUtility::rmdir($extDirPath, true);
233  }
234  if (!empty($this->extensionBackupPath)) {
235  ‪GeneralUtility::mkdir($extDirPath);
236  GeneralUtility::copyDirectory($this->extensionBackupPath, $extDirPath);
237  }
238  }
239 
243  protected function ‪removeBackupFolder(): void
244  {
245  if (!empty($this->extensionBackupPath)) {
246  ‪GeneralUtility::rmdir($this->extensionBackupPath, true);
247  $this->extensionBackupPath = '';
248  }
249  }
250 }
‪TYPO3\CMS\Extbase\Mvc\Controller\ActionController\addFlashMessage
‪addFlashMessage(string $messageBody, string $messageTitle='', ContextualFeedbackSeverity $severity=ContextualFeedbackSeverity::OK, bool $storeInSession=true)
Definition: ActionController.php:633
‪TYPO3\CMS\Core\Utility\GeneralUtility\mkdir
‪static bool mkdir(string $newFolder)
Definition: GeneralUtility.php:1638
‪TYPO3\CMS\Extensionmanager\Controller\UploadExtensionFileController\formAction
‪formAction()
Definition: UploadExtensionFileController.php:59
‪TYPO3\CMS\Core\Package\Exception
Definition: Exception.php:21
‪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:51
‪TYPO3\CMS\Extensionmanager\Controller\UploadExtensionFileController\extractExtensionFromZipFile
‪extractExtensionFromZipFile(string $uploadedFile, string $extensionKey, bool $overwrite=false)
Definition: UploadExtensionFileController.php:180
‪TYPO3\CMS\Extensionmanager\Controller\UploadExtensionFileController\removeExtensionAndRestoreFromBackup
‪removeExtensionAndRestoreFromBackup(string $fileName)
Definition: UploadExtensionFileController.php:227
‪TYPO3\CMS\Extensionmanager\Controller
Definition: AbstractController.php:18
‪TYPO3\CMS\Extensionmanager\Controller\UploadExtensionFileController\getExtensionKeyFromFileName
‪string getExtensionKeyFromFileName(string $fileName)
Definition: UploadExtensionFileController.php:203
‪TYPO3\CMS\Core\Core\Environment\getVarPath
‪static getVarPath()
Definition: Environment.php:197
‪TYPO3\CMS\Extensionmanager\Utility\FileHandlingUtility
Definition: FileHandlingUtility.php:40
‪TYPO3\CMS\Core\Type\ContextualFeedbackSeverity
‪ContextualFeedbackSeverity
Definition: ContextualFeedbackSeverity.php:25
‪TYPO3\CMS\Extensionmanager\Exception\InvalidFileException
Definition: InvalidFileException.php:23
‪TYPO3\CMS\Core\Security\BlockSerializationTrait
Definition: BlockSerializationTrait.php:28
‪TYPO3\CMS\Extensionmanager\Controller\UploadExtensionFileController\copyExtensionFolderToTempFolder
‪copyExtensionFolderToTempFolder(string $extensionKey)
Definition: UploadExtensionFileController.php:211
‪TYPO3\CMS\Extbase\Mvc\Controller\ActionController\htmlResponse
‪htmlResponse(string $html=null)
Definition: ActionController.php:802
‪TYPO3\CMS\Extensionmanager\Controller\UploadExtensionFileController\activateExtension
‪activateExtension(string $extensionKey)
Definition: UploadExtensionFileController.php:166
‪TYPO3\CMS\Extensionmanager\Controller\UploadExtensionFileController\$removeFromOriginalPath
‪bool $removeFromOriginalPath
Definition: UploadExtensionFileController.php:40
‪TYPO3\CMS\Core\Utility\GeneralUtility\rmdir
‪static bool rmdir(string $path, bool $removeNonEmpty=false)
Definition: GeneralUtility.php:1702
‪TYPO3\CMS\Extensionmanager\Exception\ExtensionManagerException
Definition: ExtensionManagerException.php:25
‪TYPO3\CMS\Extensionmanager\Controller\AbstractController
Definition: AbstractController.php:32
‪TYPO3\CMS\Extensionmanager\Controller\UploadExtensionFileController\$extensionBackupPath
‪string $extensionBackupPath
Definition: UploadExtensionFileController.php:39
‪TYPO3\CMS\Extbase\Mvc\Controller\ActionController\redirect
‪redirect(?string $actionName, ?string $controllerName=null, ?string $extensionName=null, ?array $arguments=null, ?int $pageUid=null, $_=null, int $statusCode=303)
Definition: ActionController.php:684
‪TYPO3\CMS\Extensionmanager\Controller\UploadExtensionFileController\removeBackupFolder
‪removeBackupFolder()
Definition: UploadExtensionFileController.php:242
‪TYPO3\CMS\Core\Core\Environment
Definition: Environment.php:41
‪TYPO3\CMS\Extensionmanager\Controller\UploadExtensionFileController\checkFileName
‪checkFileName($fileName)
Definition: UploadExtensionFileController.php:155
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:52
‪TYPO3\CMS\Extensionmanager\Controller\UploadExtensionFileController\extractAction
‪extractAction(bool $overwrite=false)
Definition: UploadExtensionFileController.php:76
‪TYPO3\CMS\Extensionmanager\Controller\UploadExtensionFileController\__construct
‪__construct(protected readonly FileHandlingUtility $fileHandlingUtility, protected readonly ExtensionManagementService $managementService, protected readonly ExtensionConfiguration $extensionConfiguration,)
Definition: UploadExtensionFileController.php:42