f851c507d57561fb54314bb45619d8d8d31f6e7d
[Packages/TYPO3.CMS.git] / typo3 / sysext / backend / Classes / Controller / File / CreateFolderController.php
1 <?php
2 declare(strict_types = 1);
3 namespace TYPO3\CMS\Backend\Controller\File;
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
18 use Psr\Http\Message\ResponseInterface;
19 use Psr\Http\Message\ServerRequestInterface;
20 use TYPO3\CMS\Backend\Routing\UriBuilder;
21 use TYPO3\CMS\Backend\Template\ModuleTemplate;
22 use TYPO3\CMS\Backend\Utility\BackendUtility;
23 use TYPO3\CMS\Core\Compatibility\PublicPropertyDeprecationTrait;
24 use TYPO3\CMS\Core\Http\HtmlResponse;
25 use TYPO3\CMS\Core\Imaging\Icon;
26 use TYPO3\CMS\Core\Localization\LanguageService;
27 use TYPO3\CMS\Core\Resource\Exception\InsufficientFolderAccessPermissionsException;
28 use TYPO3\CMS\Core\Resource\OnlineMedia\Helpers\OnlineMediaHelperRegistry;
29 use TYPO3\CMS\Core\Resource\ResourceFactory;
30 use TYPO3\CMS\Core\Utility\GeneralUtility;
31 use TYPO3\CMS\Core\Utility\MathUtility;
32 use TYPO3\CMS\Fluid\View\StandaloneView;
33
34 /**
35 * Script class for the create-new script
36 *
37 * Displays forms for creating folders (1 to 10), a media asset or a new file.
38 */
39 class CreateFolderController
40 {
41 use PublicPropertyDeprecationTrait;
42
43 /**
44 * @var array
45 */
46 protected $deprecatedPublicProperties = [
47 'number' => 'Using $number of class CreateFolderController from outside is discouraged, as this variable is only used for internal storage.',
48 'folderNumber' => 'Using $folderNumber of class CreateFolderController from outside is discouraged, as this variable is only used for internal storage.',
49 'target' => 'Using $target of class CreateFolderController from outside is discouraged, as this variable is only used for internal storage.',
50 'content' => 'Using $content of class CreateFolderController from outside is discouraged, as this variable is only used for internal storage.',
51 'returnUrl' => 'Using $content of class CreateFolderController from outside is discouraged, as this variable is only used for internal storage.',
52 'title' => 'Using $content of class CreateFolderController from outside is discouraged, as this variable is only used for internal storage.',
53 ];
54
55 /**
56 * @var int
57 */
58 protected $folderNumber = 10;
59
60 /**
61 * Name of the filemount
62 *
63 * @var string
64 * @deprecated since v9, will be removed in v10, unused
65 */
66 protected $title;
67
68 /**
69 * @var int
70 */
71 protected $number;
72
73 /**
74 * Set with the target path inputted in &target
75 *
76 * @var string
77 */
78 protected $target;
79
80 /**
81 * The folder object which is the target directory
82 *
83 * @var \TYPO3\CMS\Core\Resource\Folder $folderObject
84 */
85 protected $folderObject;
86
87 /**
88 * Return URL of list module.
89 *
90 * @var string
91 */
92 protected $returnUrl;
93
94 /**
95 * @var array
96 */
97 protected $pathInfo;
98
99 /**
100 * Accumulating content
101 *
102 * @var string
103 * @deprecated since v9, will be removed in v10, unused
104 */
105 protected $content;
106
107 /**
108 * ModuleTemplate object
109 *
110 * @var ModuleTemplate
111 */
112 protected $moduleTemplate;
113
114 /**
115 * Constructor
116 */
117 public function __construct()
118 {
119 $this->moduleTemplate = GeneralUtility::makeInstance(ModuleTemplate::class);
120 $GLOBALS['SOBE'] = $this;
121 // @deprecated since v9, will be moved out of __construct() in v10
122 $this->init($GLOBALS['TYPO3_REQUEST']);
123 }
124
125 /**
126 * Processes the request, currently everything is handled and put together via "main()"
127 *
128 * @param ServerRequestInterface $request the current request
129 * @return ResponseInterface the response with the content
130 */
131 public function mainAction(ServerRequestInterface $request): ResponseInterface
132 {
133 $this->main();
134 return new HtmlResponse($this->moduleTemplate->renderContent());
135 }
136
137 /**
138 * @param ServerRequestInterface|null $request
139 *
140 * @throws InsufficientFolderAccessPermissionsException
141 * @throws \RuntimeException
142 */
143 protected function init(ServerRequestInterface $request): void
144 {
145 $parsedBody = $request->getParsedBody();
146 $queryParams = $request->getQueryParams();
147
148 $this->number = $parsedBody['number'] ?? $queryParams['number'] ?? 0;
149 $this->target = ($combinedIdentifier = $parsedBody['target'] ?? $queryParams['target'] ?? '');
150 $this->returnUrl = GeneralUtility::sanitizeLocalUrl($parsedBody['returnUrl'] ?? $queryParams['returnUrl'] ?? '');
151 // create the folder object
152 if ($combinedIdentifier) {
153 $this->folderObject = ResourceFactory::getInstance()
154 ->getFolderObjectFromCombinedIdentifier($combinedIdentifier);
155 }
156 // Cleaning and checking target directory
157 if (!$this->folderObject) {
158 $title = $this->getLanguageService()->sL('LLL:EXT:filelist/Resources/Private/Language/locallang_mod_file_list.xlf:paramError');
159 $message = $this->getLanguageService()->sL('LLL:EXT:filelist/Resources/Private/Language/locallang_mod_file_list.xlf:targetNoDir');
160 throw new \RuntimeException($title . ': ' . $message, 1294586845);
161 }
162 if ($this->folderObject->getStorage()->getUid() === 0) {
163 throw new InsufficientFolderAccessPermissionsException(
164 'You are not allowed to access folders outside your storages',
165 1375889838
166 );
167 }
168
169 $pathInfo = [
170 'combined_identifier' => $this->folderObject->getCombinedIdentifier(),
171 ];
172 $uriBuilder = GeneralUtility::makeInstance(UriBuilder::class);
173
174 $this->moduleTemplate->getDocHeaderComponent()->setMetaInformation($pathInfo);
175 $this->moduleTemplate->getPageRenderer()->loadRequireJsModule('TYPO3/CMS/Backend/ContextMenu');
176 $this->moduleTemplate->addJavaScriptCode(
177 'CreateFolderInlineJavaScript',
178 'var path = "' . $this->target . '";
179 var confirmTitle = '
180 . GeneralUtility::quoteJSvalue(
181 $this->getLanguageService()->sL('LLL:EXT:core/Resources/Private/Language/locallang_common.xlf:pleaseConfirm')
182 )
183 . ';
184 var confirmText = '
185 . GeneralUtility::quoteJSvalue(
186 $this->getLanguageService()->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:mess.redraw')
187 )
188 . ';
189 function reload(a) {
190 var params = "&target="+encodeURIComponent(path)+"&number="+a+"&returnUrl=' . rawurlencode($this->returnUrl) . '";
191 var url = \'' . (string)$uriBuilder->buildUriFromRoute('file_newfolder') . '\';
192 if (!changed) {
193 window.location.href = url + params;
194 } else {
195 var modal = top.TYPO3.Modal.confirm(confirmTitle, confirmText);
196 modal.on(\'confirm.button.cancel\', function(e) {
197 top.TYPO3.Modal.currentModal.trigger(\'modal-dismiss\');
198 });
199 modal.on(\'confirm.button.ok\', function(e) {
200 top.TYPO3.Modal.currentModal.trigger(\'modal-dismiss\');
201 window.location.href = url + params;
202 });
203 }
204 }
205 function backToList() {
206 top.goToModule("file_FilelistList");
207 }
208 var changed = 0;'
209 );
210 }
211
212 /**
213 * Main function, rendering the main module content
214 */
215 public function main()
216 {
217 // Foreign class call? Method will be protected in v10, giving core freedom to move stuff around
218 $backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2);
219 if (end($backtrace)['class'] !== __CLASS__) {
220 // @deprecated since TYPO3 v9, this method will be set to protected in v10
221 trigger_error('Method main() will be set to protected in v10. Do not call from other extension', E_USER_DEPRECATED);
222 }
223
224 $lang = $this->getLanguageService();
225 $assigns = [];
226 $assigns['target'] = $this->target;
227 if ($this->folderObject->checkActionPermission('add')) {
228 $uriBuilder = GeneralUtility::makeInstance(UriBuilder::class);
229 $assigns['moduleUrlTceFile'] = (string)$uriBuilder->buildUriFromRoute('tce_file');
230 $assigns['cshFileNewFolder'] = BackendUtility::cshItem('xMOD_csh_corebe', 'file_newfolder');
231 // Making the selector box for the number of concurrent folder-creations
232 $this->number = MathUtility::forceIntegerInRange($this->number, 1, 10);
233 for ($a = 1; $a <= $this->folderNumber; $a++) {
234 $options = [];
235 $options['value'] = $a;
236 $options['selected'] = ($this->number == $a ? ' selected="selected"' : '');
237 $assigns['options'][] = $options;
238 }
239 // Making the number of new-folder boxes needed:
240 for ($a = 0; $a < $this->number; $a++) {
241 $folder = [];
242 $folder['this'] = $a;
243 $folder['next'] = $a + 1;
244 $assigns['folders'][] = $folder;
245 }
246 // Making submit button for folder creation:
247 $assigns['returnUrl'] = $this->returnUrl;
248 }
249
250 if ($this->folderObject->getStorage()->checkUserActionPermission('add', 'File')) {
251 $uriBuilder = GeneralUtility::makeInstance(UriBuilder::class);
252 $assigns['moduleUrlOnlineMedia'] = (string)$uriBuilder->buildUriFromRoute('online_media');
253 $assigns['cshFileNewMedia'] = BackendUtility::cshItem('xMOD_csh_corebe', 'file_newMedia');
254 // Create a list of allowed file extensions with the readable format "youtube, vimeo" etc.
255 $fileExtList = [];
256 $onlineMediaFileExt = OnlineMediaHelperRegistry::getInstance()->getSupportedFileExtensions();
257 foreach ($onlineMediaFileExt as $fileExt) {
258 if (GeneralUtility::verifyFilenameAgainstDenyPattern('.' . $fileExt)) {
259 $fileExtList[] = strtoupper(htmlspecialchars($fileExt));
260 }
261 }
262 $assigns['fileExtList'] = $fileExtList;
263
264 $assigns['moduleUrlTceFile'] = (string)$uriBuilder->buildUriFromRoute('tce_file');
265 $assigns['cshFileNewFile'] = BackendUtility::cshItem('xMOD_csh_corebe', 'file_newfile');
266 // Create a list of allowed file extensions with a text format "*.txt, *.css" etc.
267 $fileExtList = [];
268 $textFileExt = GeneralUtility::trimExplode(',', $GLOBALS['TYPO3_CONF_VARS']['SYS']['textfile_ext'], true);
269 foreach ($textFileExt as $fileExt) {
270 if (GeneralUtility::verifyFilenameAgainstDenyPattern('.' . $fileExt)) {
271 $fileExtList[] = strtoupper(htmlspecialchars($fileExt));
272 }
273 }
274 $assigns['txtFileExtList'] = $fileExtList;
275 }
276
277 $buttonBar = $this->moduleTemplate->getDocHeaderComponent()->getButtonBar();
278 // CSH button
279 $helpButton = $buttonBar->makeHelpButton()
280 ->setFieldName('file_new')
281 ->setModuleName('xMOD_csh_corebe');
282 $buttonBar->addButton($helpButton);
283
284 // Back
285 if ($this->returnUrl) {
286 $backButton = $buttonBar->makeLinkButton()
287 ->setHref($this->returnUrl)
288 ->setTitle($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.goBack'))
289 ->setIcon($this->moduleTemplate->getIconFactory()->getIcon('actions-view-go-back', Icon::SIZE_SMALL));
290 $buttonBar->addButton($backButton);
291 }
292
293 // Rendering of the output via fluid
294 $view = GeneralUtility::makeInstance(StandaloneView::class);
295 $view->setTemplateRootPaths([GeneralUtility::getFileAbsFileName('EXT:backend/Resources/Private/Templates')]);
296 $view->setPartialRootPaths([GeneralUtility::getFileAbsFileName('EXT:backend/Resources/Private/Partials')]);
297 $view->setTemplatePathAndFilename(GeneralUtility::getFileAbsFileName(
298 'EXT:backend/Resources/Private/Templates/File/CreateFolder.html'
299 ));
300 $view->assignMultiple($assigns);
301 $this->moduleTemplate->setContent($view->render());
302 }
303
304 /**
305 * Returns LanguageService
306 *
307 * @return LanguageService
308 */
309 protected function getLanguageService(): LanguageService
310 {
311 return $GLOBALS['LANG'];
312 }
313 }