[BUGFIX] Suggest Wizard: support for PAGE_TSCONFIG_*-values in addWhere
[Packages/TYPO3.CMS.git] / typo3 / sysext / extensionmanager / Classes / Controller / UploadExtensionFileController.php
1 <?php
2 namespace TYPO3\CMS\Extensionmanager\Controller;
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
17 use TYPO3\CMS\Core\Messaging\FlashMessage;
18 use TYPO3\CMS\Core\Utility\GeneralUtility;
19 use TYPO3\CMS\Extensionmanager\Exception\ExtensionManagerException;
20
21 /**
22 * Controller for handling upload of a local extension file
23 * Handles .t3x or .zip files
24 *
25 * @author Susanne Moog <typo3@susannemoog.de>
26 */
27 class UploadExtensionFileController extends AbstractController {
28
29 /**
30 * @var \TYPO3\CMS\Extensionmanager\Utility\FileHandlingUtility
31 * @inject
32 */
33 protected $fileHandlingUtility;
34
35 /**
36 * @var \TYPO3\CMS\Extensionmanager\Utility\Connection\TerUtility
37 * @inject
38 */
39 protected $terUtility;
40
41 /**
42 * @var \TYPO3\CMS\Extensionmanager\Utility\InstallUtility
43 * @inject
44 */
45 protected $installUtility;
46
47 /**
48 * @var string
49 */
50 protected $extensionBackupPath = '';
51
52 /**
53 * @var bool
54 */
55 protected $removeFromOriginalPath = FALSE;
56
57 /**
58 * Render upload extension form
59 *
60 * @return void
61 */
62 public function formAction() {
63 }
64
65 /**
66 * Extract an uploaded file and install the matching extension
67 *
68 * @param boolean $overwrite Overwrite existing extension if TRUE
69 * @throws ExtensionManagerException
70 * @return void
71 */
72 public function extractAction($overwrite = FALSE) {
73 $file = $_FILES['tx_extensionmanager_tools_extensionmanagerextensionmanager'];
74 $fileExtension = pathinfo($file['name']['extensionFile'], PATHINFO_EXTENSION);
75 $fileName = pathinfo($file['name']['extensionFile'], PATHINFO_BASENAME);
76 try {
77 if (empty($file['name']['extensionFile'])) {
78 throw new ExtensionManagerException('No file given.', 1342858852);
79 }
80 if ($fileExtension !== 't3x' && $fileExtension !== 'zip') {
81 throw new ExtensionManagerException('Wrong file format given.', 1342858853);
82 }
83 if (!empty($file['tmp_name']['extensionFile'])) {
84 $tempFile = GeneralUtility::upload_to_tempfile($file['tmp_name']['extensionFile']);
85 } else {
86 throw new ExtensionManagerException(
87 'Creating temporary file failed. Check your upload_max_filesize and post_max_size limits.',
88 1342864339
89 );
90 }
91
92 // Import extension
93 if ($fileExtension === 't3x') {
94 $extensionData = $this->getExtensionFromT3xFile($tempFile, $overwrite);
95 } else {
96 $extensionData = $this->getExtensionFromZipFile($tempFile, $fileName, $overwrite);
97 }
98 $this->installUtility->install($extensionData['extKey']);
99 $this->removeBackupFolder();
100 $this->addFlashMessage(
101 htmlspecialchars($this->translate('extensionList.uploadFlashMessage.message', array($extensionData['extKey']))),
102 htmlspecialchars($this->translate('extensionList.uploadFlashMessage.title')),
103 FlashMessage::OK
104 );
105 $this->addFlashMessage(
106 htmlspecialchars($this->translate('extensionList.installedFlashMessage.message', array($extensionData['extKey']))),
107 '',
108 FlashMessage::OK
109 );
110 } catch (\Exception $exception) {
111 $this->removeExtensionAndRestoreFromBackup($fileName);
112 $this->addFlashMessage(htmlspecialchars($exception->getMessage()), '', FlashMessage::ERROR);
113 }
114 $this->redirect('index', 'List', NULL, array(self::TRIGGER_RefreshModuleMenu => TRUE));
115 }
116
117 /**
118 * Extracts a given t3x file and installs the extension
119 *
120 * @param string $file Path to uploaded file
121 * @param boolean $overwrite Overwrite existing extension if TRUE
122 * @throws ExtensionManagerException
123 * @return array
124 */
125 protected function getExtensionFromT3xFile($file, $overwrite = FALSE) {
126 $fileContent = GeneralUtility::getUrl($file);
127 if (!$fileContent) {
128 throw new ExtensionManagerException('File had no or wrong content.', 1342859339);
129 }
130 $extensionData = $this->terUtility->decodeExchangeData($fileContent);
131 if (empty($extensionData['extKey'])) {
132 throw new ExtensionManagerException('Decoding the file went wrong. No extension key found', 1342864309);
133 }
134 $isExtensionAvailable = $this->installUtility->isAvailable($extensionData['extKey']);
135 if (!$overwrite && $isExtensionAvailable) {
136 throw new ExtensionManagerException($this->translate('extensionList.overwritingDisabled'), 1342864310);
137 }
138 if ($isExtensionAvailable) {
139 $this->copyExtensionFolderToTempFolder($extensionData['extKey']);
140 }
141 $this->removeFromOriginalPath = TRUE;
142 $this->fileHandlingUtility->unpackExtensionFromExtensionDataArray($extensionData);
143
144 return $extensionData;
145 }
146
147 /**
148 * Extracts a given zip file and installs the extension
149 * As there is no information about the extension key in the zip
150 * we have to use the file name to get that information
151 * filename format is expected to be extensionkey_version.zip
152 *
153 * @param string $file Path to uploaded file
154 * @param string $fileName Filename (basename) of uploaded file
155 * @param boolean $overwrite Overwrite existing extension if TRUE
156 * @return array
157 * @throws ExtensionManagerException
158 */
159 protected function getExtensionFromZipFile($file, $fileName, $overwrite = FALSE) {
160 // Remove version and extension from filename to determine the extension key
161 $extensionKey = $this->getExtensionKeyFromFileName($fileName);
162 $isExtensionAvailable = $this->installUtility->isAvailable($extensionKey);
163 if (!$overwrite && $isExtensionAvailable) {
164 throw new ExtensionManagerException('Extension is already available and overwriting is disabled.', 1342864311);
165 }
166 if ($isExtensionAvailable) {
167 $this->copyExtensionFolderToTempFolder($extensionKey);
168 }
169 $this->removeFromOriginalPath = TRUE;
170 $this->fileHandlingUtility->unzipExtensionFromFile($file, $extensionKey);
171
172 return array('extKey' => $extensionKey);
173 }
174
175 /**
176 * Removes version and file extension from filename to determine extension key
177 *
178 * @param string $fileName
179 * @return string
180 */
181 protected function getExtensionKeyFromFileName($fileName) {
182 return preg_replace('/_(\\d+)(\\.|\\-)(\\d+)(\\.|\\-)(\\d+).*/i', '', strtolower(substr($fileName, 0, -4)));
183 }
184
185 /**
186 * Copies current extension folder to typo3temp directory as backup
187 *
188 * @param string $extensionKey
189 * @throws \TYPO3\CMS\Extensionmanager\Exception\ExtensionManagerException
190 * @return void
191 */
192 protected function copyExtensionFolderToTempFolder($extensionKey) {
193 $this->extensionBackupPath = PATH_site . 'typo3temp/' . $extensionKey . substr(sha1($extensionKey . microtime()), 0, 7) . '/';
194 GeneralUtility::mkdir($this->extensionBackupPath);
195 GeneralUtility::copyDirectory(
196 $this->fileHandlingUtility->getExtensionDir($extensionKey),
197 $this->extensionBackupPath
198 );
199 }
200
201 /**
202 * Removes the extension directory and restores the extension from the backup directory
203 *
204 * @param string $fileName
205 * @see UploadExtensionFileController::extractAction
206 * @return void
207 */
208 protected function removeExtensionAndRestoreFromBackup($fileName) {
209 $extDirPath = $this->fileHandlingUtility->getExtensionDir($this->getExtensionKeyFromFileName($fileName));
210 if ($this->removeFromOriginalPath && is_dir($extDirPath)) {
211 GeneralUtility::rmdir($extDirPath, TRUE);
212 }
213 if (!empty($this->extensionBackupPath)) {
214 GeneralUtility::mkdir($extDirPath);
215 GeneralUtility::copyDirectory($this->extensionBackupPath, $extDirPath);
216 $this->removeBackupFolder();
217 }
218 }
219
220 /**
221 * Removes the backup folder in typo3temp
222 * @return void
223 */
224 protected function removeBackupFolder() {
225 if (!empty($this->extensionBackupPath)) {
226 GeneralUtility::rmdir($this->extensionBackupPath, TRUE);
227 $this->extensionBackupPath = '';
228 }
229 }
230 }