[FEATURE] Improve handling of online media
[Packages/TYPO3.CMS.git] / typo3 / sysext / backend / Classes / Controller / File / CreateFolderController.php
1 <?php
2 namespace TYPO3\CMS\Backend\Controller\File;
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\Backend\Template\DocumentTemplate;
18 use TYPO3\CMS\Backend\Utility\BackendUtility;
19 use TYPO3\CMS\Core\Http\ControllerInterface;
20 use TYPO3\CMS\Core\Http\Response;
21 use TYPO3\CMS\Core\Imaging\Icon;
22 use TYPO3\CMS\Core\Imaging\IconFactory;
23 use TYPO3\CMS\Core\Resource\Exception\InsufficientFolderAccessPermissionsException;
24 use TYPO3\CMS\Core\Resource\OnlineMedia\Helpers\OnlineMediaHelperRegistry;
25 use TYPO3\CMS\Core\Resource\ResourceFactory;
26 use TYPO3\CMS\Core\Utility\GeneralUtility;
27 use Psr\Http\Message\ResponseInterface;
28 use Psr\Http\Message\ServerRequestInterface;
29 use TYPO3\CMS\Core\Utility\MathUtility;
30
31 /**
32 * Script Class for the create-new script; Displays a form for creating up to 10 folders or one new text file
33 */
34 class CreateFolderController implements ControllerInterface {
35
36 /**
37 * @var int
38 */
39 public $folderNumber = 10;
40
41 /**
42 * document template object
43 *
44 * @var DocumentTemplate
45 */
46 public $doc;
47
48 /**
49 * Name of the filemount
50 *
51 * @var string
52 */
53 public $title;
54
55 /**
56 * @var int
57 */
58 public $number;
59
60 /**
61 * Set with the target path inputted in &target
62 *
63 * @var string
64 */
65 public $target;
66
67 /**
68 * The folder object which is the target directory
69 *
70 * @var \TYPO3\CMS\Core\Resource\Folder $folderObject
71 */
72 protected $folderObject;
73
74 /**
75 * Return URL of list module.
76 *
77 * @var string
78 */
79 public $returnUrl;
80
81 /**
82 * Accumulating content
83 *
84 * @var string
85 */
86 public $content;
87
88 /**
89 * Constructor
90 */
91 public function __construct() {
92 $GLOBALS['SOBE'] = $this;
93 $this->init();
94 }
95
96 /**
97 * Initialize
98 *
99 * @throws InsufficientFolderAccessPermissionsException
100 * @return void
101 */
102 protected function init() {
103 // Initialize GPvars:
104 $this->number = GeneralUtility::_GP('number');
105 $this->target = ($combinedIdentifier = GeneralUtility::_GP('target'));
106 $this->returnUrl = GeneralUtility::sanitizeLocalUrl(GeneralUtility::_GP('returnUrl'));
107 // create the folder object
108 if ($combinedIdentifier) {
109 $this->folderObject = ResourceFactory::getInstance()->getFolderObjectFromCombinedIdentifier($combinedIdentifier);
110 }
111 // Cleaning and checking target directory
112 if (!$this->folderObject) {
113 $title = $this->getLanguageService()->sL('LLL:EXT:lang/locallang_mod_file_list.xlf:paramError', TRUE);
114 $message = $this->getLanguageService()->sL('LLL:EXT:lang/locallang_mod_file_list.xlf:targetNoDir', TRUE);
115 throw new \RuntimeException($title . ': ' . $message, 1294586845);
116 }
117 if ($this->folderObject->getStorage()->getUid() === 0) {
118 throw new InsufficientFolderAccessPermissionsException('You are not allowed to access folders outside your storages', 1375889838);
119 }
120
121 // Setting the title and the icon
122 /** @var IconFactory $iconFactory */
123 $iconFactory = GeneralUtility::makeInstance(IconFactory::class);
124 $icon = $iconFactory->getIcon('apps-filetree-root', Icon::SIZE_SMALL);
125 $this->title = $icon . htmlspecialchars($this->folderObject->getStorage()->getName()) . ': ' . htmlspecialchars($this->folderObject->getIdentifier());
126 // Setting template object
127 $this->doc = GeneralUtility::makeInstance(DocumentTemplate::class);
128 $this->doc->setModuleTemplate('EXT:backend/Resources/Private/Templates/file_newfolder.html');
129 $this->doc->JScode = $this->doc->wrapScriptTags('
130 var path = "' . $this->target . '";
131
132 function reload(a) {
133 if (!changed || (changed && confirm(' . GeneralUtility::quoteJSvalue($this->getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlf:mess.redraw')) . '))) {
134 var params = "&target="+encodeURIComponent(path)+"&number="+a+"&returnUrl=' . rawurlencode($this->returnUrl) . '";
135 window.location.href = ' . GeneralUtility::quoteJSvalue(BackendUtility::getModuleUrl('file_newfolder')) . '+params;
136 }
137 }
138 function backToList() {
139 top.goToModule("file_FilelistList");
140 }
141
142 var changed = 0;
143 ');
144 }
145
146 /**
147 * Main function, rendering the main module content
148 *
149 * @return void
150 */
151 public function main() {
152 $lang = $this->getLanguageService();
153 // Start content compilation
154 $this->content .= $this->doc->startPage($lang->sL('LLL:EXT:lang/locallang_core.xlf:file_newfolder.php.pagetitle'));
155 // Make page header:
156 $pageContent = $this->doc->header($lang->sL('LLL:EXT:lang/locallang_core.xlf:file_newfolder.php.pagetitle'));
157 if ($this->folderObject->checkActionPermission('add')) {
158 $code = '<form role="form" action="' . htmlspecialchars(BackendUtility::getModuleUrl('tce_file')) . '" method="post" name="editform">';
159 // Making the selector box for the number of concurrent folder-creations
160 $this->number = MathUtility::forceIntegerInRange($this->number, 1, 10);
161 $code .= '
162 <div class="form-group">
163 <div class="form-section">
164 <div class="form-group">
165 <label for="number-of-new-folders">' . $lang->sL('LLL:EXT:lang/locallang_core.xlf:file_newfolder.php.number_of_folders') . ' ' . BackendUtility::cshItem('xMOD_csh_corebe', 'file_newfolder') . '</label>
166 <div class="form-control-wrap">
167 <div class="input-group">
168 <select class="form-control form-control-adapt" name="number" id="number-of-new-folders" onchange="reload(this.options[this.selectedIndex].value);">';
169 for ($a = 1; $a <= $this->folderNumber; $a++) {
170 $code .= '<option value="' . $a . '"' . ($this->number == $a ? ' selected="selected"' : '') . '>' . $a . '</option>';
171 }
172 $code .= '
173 </select>
174 </div>
175 </div>
176 </div>
177 </div>
178 ';
179 // Making the number of new-folder boxes needed:
180 for ($a = 0; $a < $this->number; $a++) {
181 $code .= '
182 <div class="form-section">
183 <div class="form-group">
184 <label for="folder_new_' . $a . '">' . $lang->sL('LLL:EXT:lang/locallang_core.xlf:file_newfolder.php.label_newfolder') . ' ' . ($a + 1) . ':</label>
185 <div class="form-control-wrap">
186 <input type="text" class="form-control" id="folder_new_' . $a . '" name="file[newfolder][' . $a . '][data]" onchange="changed=true;" />
187 <input type="hidden" name="file[newfolder][' . $a . '][target]" value="' . htmlspecialchars($this->target) . '" />
188 </div>
189 </div>
190 </div>';
191 }
192 // Making submit button for folder creation:
193 $code .= '
194 </div><div class="form-group">
195 <input class="btn btn-default" type="submit" value="' . $lang->sL('LLL:EXT:lang/locallang_core.xlf:file_newfolder.php.submit', TRUE) . '" />
196 <input type="hidden" name="redirect" value="' . htmlspecialchars($this->returnUrl) . '" />
197 </div>
198 ';
199 // Switching form tags:
200 $pageContent .= $this->doc->section($lang->sL('LLL:EXT:lang/locallang_core.xlf:file_newfolder.php.newfolders'), $code);
201 $pageContent .= $this->doc->sectionEnd() . '</form>';
202 }
203
204 if ($this->folderObject->getStorage()->checkUserActionPermission('add', 'File')) {
205
206 $pageContent .= '<form action="' . htmlspecialchars(BackendUtility::getModuleUrl('online_media')) . '" method="post" name="editform2">';
207 // Create a list of allowed file extensions with the readable format "youtube, vimeo" etc.
208 $fileExtList = array();
209 $onlineMediaFileExt = OnlineMediaHelperRegistry::getInstance()->getSupportedFileExtensions();
210 foreach ($onlineMediaFileExt as $fileExt) {
211 if (GeneralUtility::verifyFilenameAgainstDenyPattern($fileExt)) {
212 $fileExtList[] = '<span class="label label-success">' . strtoupper(htmlspecialchars($fileExt)) . '</span>';
213 }
214 }
215 // Add form fields for adding media files:
216 $code = '
217 <div class="form-group">
218 <div class="form-section">
219 <div class="form-group">
220 <label for="newMedia">' . $lang->sL('LLL:EXT:lang/locallang_core.xlf:online_media.new_media.label', TRUE) . ' ' . BackendUtility::cshItem('xMOD_csh_corebe', 'file_newMedia') . '</label>
221 <div class="form-control-wrap">
222 <input class="form-control" type="text" id="newMedia" name="file[newMedia][0][url]"
223 placeholder="' . $lang->sL('LLL:EXT:lang/locallang_core.xlf:online_media.new_media.placeholder', TRUE) . '" />
224 <input type="hidden" name="file[newMedia][0][target]" value="' . htmlspecialchars($this->target) . '" />
225 </div>
226 <div class="help-block">
227 ' . $lang->sL('LLL:EXT:lang/locallang_core.xlf:online_media.new_media.allowedProviders', TRUE) . '<br>
228 ' . implode(' ', $fileExtList) . '
229 </div>
230 </div>
231 </div>
232 </div>
233 ';
234 // Submit button for creation of a new media:
235 $code .= '
236 <div class="form-group">
237 <input class="btn btn-default" type="submit" value="' . $lang->sL('LLL:EXT:lang/locallang_core.xlf:online_media.new_media.submit', TRUE) . '" />
238 <input type="hidden" name="redirect" value="' . htmlspecialchars($this->returnUrl) . '" />
239 </div>
240 ';
241 $pageContent .= $this->doc->section($lang->sL('LLL:EXT:lang/locallang_core.xlf:online_media.new_media', TRUE), $code);
242 $pageContent .= $this->doc->sectionEnd();
243 $pageContent .= '</form>';
244
245 $pageContent .= '<form action="' . BackendUtility::getModuleUrl('tce_file') . '" method="post" name="editform3">';
246 // Create a list of allowed file extensions with the nice format "*.jpg, *.gif" etc.
247 $fileExtList = array();
248 $textFileExt = GeneralUtility::trimExplode(',', $GLOBALS['TYPO3_CONF_VARS']['SYS']['textfile_ext'], TRUE);
249 foreach ($textFileExt as $fileExt) {
250 if (GeneralUtility::verifyFilenameAgainstDenyPattern($fileExt)) {
251 $fileExtList[] = '<span class="label label-success">' . strtoupper(htmlspecialchars($fileExt)) . '</span>';
252 }
253 }
254 // Add form fields for creation of a new, blank text file:
255 $code = '
256 <div class="form-group">
257 <div class="form-section">
258 <div class="form-group">
259 <label for="newfile">' . $lang->sL('LLL:EXT:lang/locallang_core.xlf:file_newfolder.php.label_newfile', TRUE) . ' ' . BackendUtility::cshItem('xMOD_csh_corebe', 'file_newfile') . '</label>
260 <div class="form-control-wrap">
261 <input class="form-control" type="text" id="newfile" name="file[newfile][0][data]" onchange="changed=true;" />
262 <input type="hidden" name="file[newfile][0][target]" value="' . htmlspecialchars($this->target) . '" />
263 </div>
264 <div class="help-block">
265 ' . $lang->sL('LLL:EXT:lang/locallang_core.xlf:cm.allowedFileExtensions', TRUE) . '<br>
266 ' . implode(' ', $fileExtList) . '
267 </div>
268 </div>
269 </div>
270 </div>
271 ';
272 // Submit button for creation of a new file:
273 $code .= '
274 <div class="form-group">
275 <input class="btn btn-default" type="submit" value="' . $lang->sL('LLL:EXT:lang/locallang_core.xlf:file_newfolder.php.newfile_submit', TRUE) . '" />
276 <input type="hidden" name="redirect" value="' . htmlspecialchars($this->returnUrl) . '" />
277 </div>
278 ';
279 $pageContent .= $this->doc->section($lang->sL('LLL:EXT:lang/locallang_core.xlf:file_newfolder.php.newfile', TRUE), $code);
280 $pageContent .= $this->doc->sectionEnd();
281 $pageContent .= '</form>';
282 }
283
284 $docHeaderButtons = array(
285 'back' => ''
286 );
287 $iconFactory = GeneralUtility::makeInstance(IconFactory::class);
288 // Back
289 if ($this->returnUrl) {
290 $docHeaderButtons['back'] = '<a href="' . htmlspecialchars(GeneralUtility::linkThisUrl($this->returnUrl)) . '" class="typo3-goBack" title="' . $lang->sL('LLL:EXT:lang/locallang_core.xlf:labels.goBack', TRUE) . '">' . $iconFactory->getIcon('actions-view-go-back', Icon::SIZE_SMALL) . '</a>';
291 }
292 // Add the HTML as a section:
293 $markerArray = array(
294 'CSH' => $docHeaderButtons['csh'],
295 'FUNC_MENU' => '',
296 'CONTENT' => $pageContent,
297 'PATH' => $this->title
298 );
299 $this->content .= $this->doc->moduleBody(array(), $docHeaderButtons, $markerArray);
300 $this->content .= $this->doc->endPage();
301 $this->content = $this->doc->insertStylesAndJS($this->content);
302 }
303
304 /**
305 * Processes the request, currently everything is handled and put together via "main()"
306 *
307 * @param ServerRequestInterface $request The request object
308 * @return ResponseInterface $response The response, created by the controller
309 */
310 public function processRequest(ServerRequestInterface $request) {
311 $this->main();
312 /** @var Response $response */
313 $response = GeneralUtility::makeInstance(Response::class);
314 $response->getBody()->write($this->content);
315 return $response;
316 }
317
318 /**
319 * Outputting the accumulated content to screen
320 *
321 * @return void
322 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8, use the processRequest() method instead
323 */
324 public function printContent() {
325 GeneralUtility::logDeprecatedFunction();
326 echo $this->content;
327 }
328
329 /**
330 * Returns LanguageService
331 *
332 * @return \TYPO3\CMS\Lang\LanguageService
333 */
334 protected function getLanguageService() {
335 return $GLOBALS['LANG'];
336 }
337
338 }