6f91a53e14ad93ebb82a376ef873c928b8d9f2e5
[Packages/TYPO3.CMS.git] / typo3 / sysext / backend / Classes / Controller / File / EditFileController.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 Psr\Http\Message\ResponseInterface;
18 use Psr\Http\Message\ServerRequestInterface;
19 use TYPO3\CMS\Backend\Module\AbstractModule;
20 use TYPO3\CMS\Backend\Template\Components\ButtonBar;
21 use TYPO3\CMS\Backend\Template\DocumentTemplate;
22 use TYPO3\CMS\Backend\Utility\BackendUtility;
23 use TYPO3\CMS\Core\Imaging\Icon;
24 use TYPO3\CMS\Core\Resource\Exception\InsufficientFileAccessPermissionsException;
25 use TYPO3\CMS\Core\Resource\ResourceFactory;
26 use TYPO3\CMS\Core\Utility\GeneralUtility;
27
28 /**
29 * Script Class for rendering the file editing screen
30 */
31 class EditFileController extends AbstractModule
32 {
33 /**
34 * Module content accumulated.
35 *
36 * @var string
37 */
38 public $content;
39
40 /**
41 * @var string
42 */
43 public $title;
44
45 /**
46 * Document template object
47 *
48 * @var DocumentTemplate
49 */
50 public $doc;
51
52 /**
53 * Original input target
54 *
55 * @var string
56 */
57 public $origTarget;
58
59 /**
60 * The original target, but validated.
61 *
62 * @var string
63 */
64 public $target;
65
66 /**
67 * Return URL of list module.
68 *
69 * @var string
70 */
71 public $returnUrl;
72
73 /**
74 * the file that is being edited on
75 *
76 * @var \TYPO3\CMS\Core\Resource\AbstractFile
77 */
78 protected $fileObject;
79
80 /**
81 * Constructor
82 */
83 public function __construct()
84 {
85 parent::__construct();
86 $GLOBALS['SOBE'] = $this;
87 $this->init();
88 }
89
90 /**
91 * Initialize script class
92 *
93 * @throws InsufficientFileAccessPermissionsException
94 * @throws \InvalidArgumentException
95 * @throws \RuntimeException
96 */
97 protected function init()
98 {
99 // Setting target, which must be a file reference to a file within the mounts.
100 $this->target = ($this->origTarget = ($fileIdentifier = GeneralUtility::_GP('target')));
101 $this->returnUrl = GeneralUtility::sanitizeLocalUrl(GeneralUtility::_GP('returnUrl'));
102 // create the file object
103 if ($fileIdentifier) {
104 $this->fileObject = ResourceFactory::getInstance()
105 ->retrieveFileOrFolderObject($fileIdentifier);
106 }
107 // Cleaning and checking target directory
108 if (!$this->fileObject) {
109 $title = $this->getLanguageService()->sL('LLL:EXT:lang/locallang_mod_file_list.xlf:paramError');
110 $message = $this->getLanguageService()->sL('LLL:EXT:lang/locallang_mod_file_list.xlf:targetNoDir');
111 throw new \RuntimeException($title . ': ' . $message, 1294586841);
112 }
113 if ($this->fileObject->getStorage()->getUid() === 0) {
114 throw new InsufficientFileAccessPermissionsException(
115 'You are not allowed to access files outside your storages',
116 1375889832
117 );
118 }
119
120 // Setting the title and the icon
121 $icon = $this->moduleTemplate->getIconFactory()->getIcon('apps-filetree-root', Icon::SIZE_SMALL)->render();
122 $this->title = $icon
123 . htmlspecialchars(
124 $this->fileObject->getStorage()->getName()
125 ) . ': ' . htmlspecialchars(
126 $this->fileObject->getIdentifier()
127 );
128
129 // Setting template object
130 $this->doc = GeneralUtility::makeInstance(DocumentTemplate::class);
131 $this->moduleTemplate->addJavaScriptCode(
132 'FileEditBackToList',
133 'function backToList() {
134 top.goToModule("file_FilelistList");
135 }'
136 );
137 }
138
139 /**
140 * Main function, redering the actual content of the editing page
141 *
142 * @return void
143 */
144 public function main()
145 {
146 $this->getButtons();
147 // Hook before compiling the output
148 if (isset($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/file_edit.php']['preOutputProcessingHook'])) {
149 $preOutputProcessingHook = &$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/file_edit.php']['preOutputProcessingHook'];
150 if (is_array($preOutputProcessingHook)) {
151 $hookParameters = [
152 'content' => &$this->content,
153 'target' => &$this->target
154 ];
155 foreach ($preOutputProcessingHook as $hookFunction) {
156 GeneralUtility::callUserFunction($hookFunction, $hookParameters, $this);
157 }
158 }
159 }
160
161 $pageContent = '<form action="' . htmlspecialchars(BackendUtility::getModuleUrl('tce_file')) . '" method="post" id="EditFileController" name="editform">';
162 $pageContent .= '<h1>'
163 . $this->getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlf:file_edit.php.pagetitle')
164 . ' ' . htmlspecialchars($this->fileObject->getName()) . '</h1>';
165
166 $code = '';
167 $extList = $GLOBALS['TYPO3_CONF_VARS']['SYS']['textfile_ext'];
168 try {
169 if (!$extList || !GeneralUtility::inList($extList, $this->fileObject->getExtension())) {
170 throw new \Exception('Files with that extension are not editable.', 1476050135);
171 }
172
173 // Read file content to edit:
174 $fileContent = $this->fileObject->getContents();
175
176 // Making the formfields
177 $hValue = BackendUtility::getModuleUrl('file_edit', [
178 'target' => $this->origTarget,
179 'returnUrl' => $this->returnUrl
180 ]);
181 $code .= '
182 <div id="c-edit">
183 <textarea rows="30" name="file[editfile][0][data]" wrap="off" class="form-control text-monospace t3js-enable-tab">' . htmlspecialchars($fileContent) . '</textarea>
184 <input type="hidden" name="file[editfile][0][target]" value="' . $this->fileObject->getUid() . '" />
185 <input type="hidden" name="redirect" value="' . htmlspecialchars($hValue) . '" />
186 </div>
187 <br />';
188 } catch (\Exception $e) {
189 $code .= sprintf(
190 $this->getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlf:file_edit.php.coundNot'),
191 $extList
192 );
193 }
194
195 // Ending of section and outputting editing form:
196 $pageContent .= $code;
197
198 // Hook after compiling the output
199 if (isset($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/file_edit.php']['postOutputProcessingHook'])) {
200 $postOutputProcessingHook = &$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/file_edit.php']['postOutputProcessingHook'];
201 if (is_array($postOutputProcessingHook)) {
202 $hookParameters = [
203 'pageContent' => &$pageContent,
204 'target' => &$this->target
205 ];
206 foreach ($postOutputProcessingHook as $hookFunction) {
207 GeneralUtility::callUserFunction($hookFunction, $hookParameters, $this);
208 }
209 }
210 }
211 $pageContent .= '</form>';
212 $this->content = $pageContent;
213
214 $this->moduleTemplate->setContent($this->content);
215 }
216
217 /**
218 * Processes the request, currently everything is handled and put together via "main()"
219 *
220 * @param ServerRequestInterface $request the current request
221 * @param ResponseInterface $response
222 * @return ResponseInterface the response with the content
223 */
224 public function mainAction(ServerRequestInterface $request, ResponseInterface $response)
225 {
226 $this->main();
227
228 $response->getBody()->write($this->moduleTemplate->renderContent());
229 return $response;
230 }
231
232 /**
233 * Builds the buttons for the docheader and returns them as an array
234 *
235 * @return array
236 */
237 public function getButtons()
238 {
239 $buttonBar = $this->moduleTemplate->getDocHeaderComponent()->getButtonBar();
240
241 $lang = $this->getLanguageService();
242 // CSH button
243 $helpButton = $buttonBar->makeHelpButton()
244 ->setFieldName('file_edit')
245 ->setModuleName('xMOD_csh_corebe');
246 $buttonBar->addButton($helpButton);
247
248 // Save button
249 $saveButton = $buttonBar->makeInputButton()
250 ->setName('_save')
251 ->setValue('1')
252 ->setOnClick('document.editform.submit();')
253 ->setTitle($lang->sL('LLL:EXT:lang/locallang_core.xlf:file_edit.php.submit'))
254 ->setIcon($this->moduleTemplate->getIconFactory()->getIcon('actions-document-save', Icon::SIZE_SMALL));
255
256 // Save and Close button
257 $saveAndCloseButton = $buttonBar->makeInputButton()
258 ->setName('_saveandclose')
259 ->setValue('1')
260 ->setOnClick(
261 'document.editform.redirect.value='
262 . GeneralUtility::quoteJSvalue($this->returnUrl)
263 . '; document.editform.submit();'
264 )
265 ->setTitle($lang->sL('LLL:EXT:lang/locallang_core.xlf:file_edit.php.saveAndClose'))
266 ->setIcon($this->moduleTemplate->getIconFactory()->getIcon(
267 'actions-document-save-close',
268 Icon::SIZE_SMALL
269 ));
270
271 $splitButton = $buttonBar->makeSplitButton()
272 ->addItem($saveButton)
273 ->addItem($saveAndCloseButton);
274 $buttonBar->addButton($splitButton, ButtonBar::BUTTON_POSITION_LEFT, 20);
275
276 // Cancel button
277 $closeButton = $buttonBar->makeLinkButton()
278 ->setHref('#')
279 ->setOnClick('backToList(); return false;')
280 ->setTitle($lang->sL('LLL:EXT:lang/locallang_core.xlf:labels.cancel'))
281 ->setIcon($this->moduleTemplate->getIconFactory()->getIcon('actions-document-close', Icon::SIZE_SMALL));
282 $buttonBar->addButton($closeButton, ButtonBar::BUTTON_POSITION_LEFT, 10);
283
284 // Make shortcut:
285 $shortButton = $buttonBar->makeShortcutButton()
286 ->setModuleName('file_edit')
287 ->setGetVariables(['target']);
288 $buttonBar->addButton($shortButton);
289 }
290
291 /**
292 * Returns LanguageService
293 *
294 * @return \TYPO3\CMS\Lang\LanguageService
295 */
296 protected function getLanguageService()
297 {
298 return $GLOBALS['LANG'];
299 }
300
301 /**
302 * Returns the current BE user.
303 *
304 * @return \TYPO3\CMS\Core\Authentication\BackendUserAuthentication
305 */
306 protected function getBackendUser()
307 {
308 return $GLOBALS['BE_USER'];
309 }
310 }