7e115896aff1aa265b11ab16badb128b5ac0b0fc
[Packages/TYPO3.CMS.git] / typo3 / sysext / rtehtmlarea / Classes / ImageHandler / AddImageHandler.php
1 <?php
2 namespace TYPO3\CMS\Rtehtmlarea\ImageHandler;
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\ServerRequestInterface;
18 use TYPO3\CMS\Backend\Tree\View\ElementBrowserFolderTreeView;
19 use TYPO3\CMS\Backend\Utility\BackendUtility;
20 use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
21 use TYPO3\CMS\Core\Imaging\Icon;
22 use TYPO3\CMS\Core\Imaging\IconFactory;
23 use TYPO3\CMS\Core\Page\PageRenderer;
24 use TYPO3\CMS\Core\Resource\Exception;
25 use TYPO3\CMS\Core\Resource\File;
26 use TYPO3\CMS\Core\Resource\FileInterface;
27 use TYPO3\CMS\Core\Resource\FileRepository;
28 use TYPO3\CMS\Core\Resource\Filter\FileExtensionFilter;
29 use TYPO3\CMS\Core\Resource\Folder;
30 use TYPO3\CMS\Core\Resource\ProcessedFile;
31 use TYPO3\CMS\Core\Resource\ResourceFactory;
32 use TYPO3\CMS\Core\Utility\GeneralUtility;
33 use TYPO3\CMS\Lang\LanguageService;
34 use TYPO3\CMS\Recordlist\Controller\AbstractLinkBrowserController;
35 use TYPO3\CMS\Recordlist\LinkHandler\LinkHandlerInterface;
36 use TYPO3\CMS\Recordlist\Tree\View\LinkParameterProviderInterface;
37 use TYPO3\CMS\Recordlist\View\FolderUtilityRenderer;
38 use TYPO3\CMS\Rtehtmlarea\Controller\SelectImageController;
39
40 class AddImageHandler implements LinkParameterProviderInterface, LinkHandlerInterface
41 {
42 /**
43 * Current mode: One of 'magic' or 'plain'
44 *
45 * @var string
46 */
47 protected $mode;
48
49 /**
50 * @var SelectImageController
51 */
52 protected $selectImageController;
53
54 /**
55 * Relevant for RTE mode "plain": the maximum width an image must have to be selectable.
56 *
57 * @var int
58 */
59 protected $plainMaxWidth;
60
61 /**
62 * Relevant for RTE mode "plain": the maximum height an image must have to be selectable.
63 *
64 * @var int
65 */
66 protected $plainMaxHeight;
67
68 /**
69 * @var string|NULL
70 */
71 protected $expandFolder;
72
73 /**
74 * @var string
75 */
76 protected $defaultClass;
77
78 /**
79 * @var Folder
80 */
81 protected $selectedFolder;
82
83 /**
84 * Holds information about files
85 *
86 * @var mixed[][]
87 */
88 protected $elements = [];
89
90 /**
91 * @var string
92 */
93 protected $searchWord;
94
95 /**
96 * @var FileRepository
97 */
98 protected $fileRepository;
99
100 /**
101 * URL of current request
102 *
103 * @var string
104 */
105 protected $thisScript = '';
106
107 /**
108 * @var IconFactory
109 */
110 protected $iconFactory;
111
112 /**
113 * Initialize the handler
114 *
115 * @param AbstractLinkBrowserController $linkBrowser
116 * @param string $identifier
117 * @param array $configuration Page TSconfig
118 *
119 * @throws \InvalidArgumentException
120 */
121 public function initialize(AbstractLinkBrowserController $linkBrowser, $identifier, array $configuration)
122 {
123 $this->fileRepository = GeneralUtility::makeInstance(FileRepository::class);
124 $this->iconFactory = GeneralUtility::makeInstance(IconFactory::class);
125
126 $this->expandFolder = GeneralUtility::_GP('expandFolder');
127 $this->searchWord = (string)GeneralUtility::_GP('searchWord');
128
129 if ($identifier !== 'plain' && $identifier !== 'magic') {
130 throw new \InvalidArgumentException('The given identifier "' . $identifier . '" is not supported by this handler."', 1455499720);
131 }
132 if (!$linkBrowser instanceof SelectImageController) {
133 throw new \InvalidArgumentException('The given $linkBrowser must be of type SelectImageController."', 1455499721);
134 }
135 $this->mode = $identifier;
136 $this->selectImageController = $linkBrowser;
137
138 $buttonConfiguration = $linkBrowser->getButtonConfiguration();
139 $this->plainMaxWidth = empty($buttonConfiguration['options.']['plain.']['maxWidth'])
140 ? 640
141 : $buttonConfiguration['options.']['plain.']['maxWidth'];
142 $this->plainMaxHeight = empty($buttonConfiguration['options.']['plain.']['maxHeight'])
143 ? 680
144 : $buttonConfiguration['options.']['plain.']['maxHeight'];
145
146 $this->getLanguageService()->includeLLFile('EXT:rtehtmlarea/Resources/Private/Language/locallang_selectimagecontroller.xlf');
147 }
148
149 /**
150 * Render the link handler
151 *
152 * @param ServerRequestInterface $request
153 *
154 * @return string
155 */
156 public function render(ServerRequestInterface $request)
157 {
158 GeneralUtility::makeInstance(PageRenderer::class)->loadRequireJsModule('TYPO3/CMS/Rtehtmlarea/AddImage');
159
160 $backendUser = $this->getBackendUser();
161
162 // The key number 3 of the bparams contains the "allowed" string. Disallowed is not passed to
163 // the element browser at all but only filtered out in DataHandler afterwards
164 $bparams = explode('|', $this->selectImageController->getUrlParameters()['bparams']);
165 if (isset($bparams[3])) {
166 $allowedFileExtensions = GeneralUtility::trimExplode(',', $bparams[3], true);
167 } else {
168 $allowedFileExtensions = GeneralUtility::trimExplode(
169 ',',
170 $this->mode === 'plain'
171 ? SelectImageController::PLAIN_MODE_IMAGE_FILE_EXTENSIONS
172 : $GLOBALS['TYPO3_CONF_VARS']['GFX']['imagefile_ext'],
173 true
174 );
175 }
176 if (!empty($allowedFileExtensions) && $allowedFileExtensions[0] !== 'sys_file' && $allowedFileExtensions[0] !== '*') {
177 // Create new filter object
178 $filterObject = GeneralUtility::makeInstance(FileExtensionFilter::class);
179 $filterObject->setAllowedFileExtensions($allowedFileExtensions);
180 // Set file extension filters on all storages
181 $storages = $backendUser->getFileStorages();
182 /** @var $storage \TYPO3\CMS\Core\Resource\ResourceStorage */
183 foreach ($storages as $storage) {
184 $storage->addFileAndFolderNameFilter([$filterObject, 'filterFileList']);
185 }
186 }
187 if ($this->expandFolder) {
188 $fileOrFolderObject = null;
189
190 // Try to fetch the folder the user had open the last time he browsed files
191 // Fallback to the default folder in case the last used folder is not existing
192 try {
193 $fileOrFolderObject = ResourceFactory::getInstance()->retrieveFileOrFolderObject($this->expandFolder);
194 } catch (Exception $accessException) {
195 // We're just catching the exception here, nothing to be done if folder does not exist or is not accessible.
196 } catch (\InvalidArgumentException $driverMissingExecption) {
197 // We're just catching the exception here, nothing to be done if the driver does not exist anymore.
198 }
199
200 if ($fileOrFolderObject instanceof Folder) {
201 // It's a folder
202 $this->selectedFolder = $fileOrFolderObject;
203 } elseif ($fileOrFolderObject instanceof FileInterface) {
204 // It's a file
205 $this->selectedFolder = $fileOrFolderObject->getParentFolder();
206 }
207 }
208 // Or get the user's default upload folder
209 if (!$this->selectedFolder) {
210 try {
211 $this->selectedFolder = $backendUser->getDefaultUploadFolder();
212 } catch (\Exception $e) {
213 // The configured default user folder does not exist
214 }
215 }
216 // Build the file upload and folder creation form
217 $uploadForm = '';
218 $createFolder = '';
219 if ($this->selectedFolder) {
220 $folderUtilityRenderer = GeneralUtility::makeInstance(FolderUtilityRenderer::class, $this);
221 $uploadForm = $folderUtilityRenderer->uploadForm($this->selectedFolder, $allowedFileExtensions);
222 $createFolder = $folderUtilityRenderer->createFolder($this->selectedFolder);
223 }
224
225 // Getting flag for showing/not showing thumbnails:
226 $noThumbs = $backendUser->getTSConfigVal('options.noThumbsInRTEimageSelect');
227 $_MOD_SETTINGS = [];
228 if (!$noThumbs) {
229 // MENU-ITEMS, fetching the setting for thumbnails from File>List module:
230 $_MOD_MENU = ['displayThumbs' => ''];
231 $_MCONF['name'] = 'file_list';
232 $_MOD_SETTINGS = BackendUtility::getModuleData($_MOD_MENU, GeneralUtility::_GP('SET'), $_MCONF['name']);
233 }
234 $noThumbs = $noThumbs ?: !$_MOD_SETTINGS['displayThumbs'];
235 // Create folder tree:
236 /** @var ElementBrowserFolderTreeView $folderTree */
237 $folderTree = GeneralUtility::makeInstance(ElementBrowserFolderTreeView::class);
238 $folderTree->setLinkParameterProvider($this);
239 $tree = $folderTree->getBrowsableTree();
240 if ($this->selectedFolder) {
241 $files = $this->renderFilesInFolder($this->selectedFolder, $allowedFileExtensions, $noThumbs);
242 } else {
243 $files = '';
244 }
245
246 $content = '';
247 // Insert the upload form on top, if so configured
248 if ($backendUser->getTSConfigVal('options.uploadFieldsInTopOfEB')) {
249 $content .= $uploadForm;
250 }
251 // Putting the parts together, side by side:
252 $content .= '
253
254 <!--
255 Wrapper table for folder tree / filelist:
256 -->
257 <div class="element-browser-section element-browser-filetree">
258 <table border="0" cellpadding="0" cellspacing="0" id="typo3-EBfiles">
259 <tr>
260 <td class="c-wCell" valign="top"><h3>' . htmlspecialchars($this->getLanguageService()->getLL('folderTree')) . ':</h3>' . $tree . '</td>
261 <td class="c-wCell" valign="top">' . $files . '</td>
262 </tr>
263 </table>
264 </div>
265 ';
266 // Add help message
267 switch ($this->mode) {
268 case 'plain':
269 $content .= sprintf($this->getLanguageService()->getLL('plainImage_msg'), $this->plainMaxWidth, $this->plainMaxHeight);
270 break;
271 case 'magic':
272 $content .= sprintf($this->getLanguageService()->getLL('magicImage_msg'));
273 break;
274 }
275 // Adding create folder + upload forms if applicable:
276 if (!$backendUser->getTSConfigVal('options.uploadFieldsInTopOfEB')) {
277 $content .= $uploadForm;
278 }
279 $content .= $createFolder;
280 // Add some space
281 $content .= '<br /><br />';
282
283 return $content;
284 }
285
286 /**
287 * For TYPO3 Element Browser: Expand folder of files.
288 *
289 * @param Folder $folder The folder path to expand
290 * @param array $extensionList List of fileextensions to show
291 * @param bool $noThumbs Whether to show thumbnails or not. If set, no thumbnails are shown.
292 * @return string HTML output
293 */
294 public function renderFilesInFolder(Folder $folder, array $extensionList = [], $noThumbs = false)
295 {
296 if (!$folder->checkActionPermission('read')) {
297 return '';
298 }
299 $lang = $this->getLanguageService();
300 $titleLen = (int)$this->getBackendUser()->uc['titleLen'];
301
302 if ($this->searchWord !== '') {
303 $files = $this->fileRepository->searchByName($folder, $this->searchWord);
304 } else {
305 $extensionList = !empty($extensionList) && $extensionList[0] === '*' ? [] : $extensionList;
306 $files = $this->getFilesInFolder($folder, $extensionList);
307 }
308 $filesCount = count($files);
309
310 $lines = [];
311
312 // Create the header of current folder:
313 $folderIcon = $this->iconFactory->getIconForResource($folder, Icon::SIZE_SMALL);
314
315 $lines[] = '
316 <tr>
317 <th class="col-title" nowrap="nowrap">' . $folderIcon . ' ' . htmlspecialchars(GeneralUtility::fixed_lgd_cs($folder->getIdentifier(), $titleLen)) . '</th>
318 <th class="col-control" nowrap="nowrap"></th>
319 <th class="col-clipboard" nowrap="nowrap">
320 <a href="#" class="btn btn-default" id="t3js-importSelection" title="' . htmlspecialchars($lang->getLL('importSelection')) . '">' . $this->iconFactory->getIcon('actions-document-import-t3d', Icon::SIZE_SMALL) . '</a>
321 <a href="#" class="btn btn-default" id="t3js-toggleSelection" title="' . htmlspecialchars($lang->getLL('toggleSelection')) . '">' . $this->iconFactory->getIcon('actions-document-select', Icon::SIZE_SMALL) . '</a>
322 </th>
323 <th nowrap="nowrap">&nbsp;</th>
324 </tr>';
325
326 if ($filesCount === 0) {
327 $lines[] = '
328 <tr>
329 <td colspan="4">No files found.</td>
330 </tr>';
331 }
332
333 foreach ($files as $fileObject) {
334 $fileExtension = $fileObject->getExtension();
335 // Thumbnail/size generation:
336 $imgInfo = [];
337 if (!$noThumbs && GeneralUtility::inList(strtolower($GLOBALS['TYPO3_CONF_VARS']['GFX']['imagefile_ext'] . ',' . $GLOBALS['TYPO3_CONF_VARS']['SYS']['mediafile_ext']), strtolower($fileExtension))) {
338 $processedFile = $fileObject->process(
339 ProcessedFile::CONTEXT_IMAGEPREVIEW,
340 ['width' => 64, 'height' => 64]
341 );
342 $imageUrl = $processedFile->getPublicUrl(true);
343 $imgInfo = [
344 $fileObject->getProperty('width'),
345 $fileObject->getProperty('height')
346 ];
347 $pDim = $imgInfo[0] . 'x' . $imgInfo[1] . ' pixels';
348 $clickIcon = '<img src="' . $imageUrl . '"'
349 . ' width="' . $processedFile->getProperty('width') . '"'
350 . ' height="' . $processedFile->getProperty('height') . '"'
351 . ' hspace="5" vspace="5" border="1" />';
352 } else {
353 $clickIcon = '';
354 $pDim = '';
355 }
356 // Create file icon:
357 $size = ' (' . GeneralUtility::formatSize($fileObject->getSize()) . 'bytes' . ($pDim ? ', ' . $pDim : '') . ')';
358 $icon = '<span title="' . htmlspecialchars($fileObject->getName() . $size) . '">' . $this->iconFactory->getIconForResource($fileObject, Icon::SIZE_SMALL) . '</span>';
359 // Create links for adding the file:
360 $filesIndex = count($this->elements);
361 $this->elements['file_' . $filesIndex] = [
362 'type' => 'file',
363 'table' => 'sys_file',
364 'uid' => $fileObject->getUid(),
365 'fileName' => $fileObject->getName(),
366 'filePath' => $fileObject->getUid(),
367 'fileExt' => $fileExtension,
368 'fileIcon' => $icon
369 ];
370 if ($this->fileIsSelectableInFileList($fileObject, $imgInfo)) {
371 $ATag = '<a href="#" class="btn btn-default" title="' . htmlspecialchars($fileObject->getName()) . '" data-file-index="' . htmlspecialchars($filesIndex) . '" data-close="0">';
372 $ATag_alt = '<a href="#" title="' . htmlspecialchars($fileObject->getName()) . '" data-file-index="' . htmlspecialchars($filesIndex) . '" data-close="1">';
373 $ATag_e = '</a>';
374 $bulkCheckBox = '<label class="btn btn-default btn-checkbox"><input type="checkbox" class="typo3-bulk-item" name="file_' . $filesIndex . '" value="0" /><span class="t3-icon fa"></span></label>';
375 } else {
376 $ATag = '';
377 $ATag_alt = '';
378 $ATag_e = '';
379 $bulkCheckBox = '';
380 }
381 // Create link to showing details about the file in a window:
382 $Ahref = BackendUtility::getModuleUrl('show_item', [
383 'type' => 'file',
384 'table' => '_FILE',
385 'uid' => $fileObject->getCombinedIdentifier(),
386 'returnUrl' => GeneralUtility::getIndpEnv('REQUEST_URI')
387 ]);
388
389 // Combine the stuff:
390 $filenameAndIcon = $ATag_alt . $icon . htmlspecialchars(GeneralUtility::fixed_lgd_cs($fileObject->getName(), $titleLen)) . $ATag_e;
391 // Show element:
392 $lines[] = '
393 <tr class="file_list_normal">
394 <td class="col-title" nowrap="nowrap">' . $filenameAndIcon . '&nbsp;</td>
395 <td class="col-control">
396 <div class="btn-group">' . $ATag . '<span title="' . htmlspecialchars($lang->getLL('addToList')) . '">' . $this->iconFactory->getIcon('actions-edit-add', Icon::SIZE_SMALL)->render() . '</span>' . $ATag_e . '
397 <a href="' . htmlspecialchars($Ahref) . '" class="btn btn-default" title="' . htmlspecialchars($lang->getLL('info')) . '">' . $this->iconFactory->getIcon('actions-document-info', Icon::SIZE_SMALL) . '</a>
398 </td>
399 <td class="col-clipboard" valign="top">' . $bulkCheckBox . '</td>
400 <td nowrap="nowrap">&nbsp;' . $pDim . '</td>
401 </tr>';
402 if ($pDim) {
403 $lines[] = '
404 <tr>
405 <td class="filelistThumbnail" colspan="4">' . $ATag_alt . $clickIcon . $ATag_e . '</td>
406 </tr>';
407 }
408 }
409
410 $out = '<h3>' . htmlspecialchars($lang->getLL('files')) . ' ' . $filesCount . ':</h3>';
411 $out .= GeneralUtility::makeInstance(FolderUtilityRenderer::class, $this)->getFileSearchField($this->searchWord);
412 $out .= '<div id="filelist">';
413 $out .= $this->getBulkSelector($filesCount);
414
415 // Wrap all the rows in table tags:
416 $out .= '
417
418 <!--
419 Filelisting
420 -->
421 <table class="table table-striped table-hover" id="typo3-filelist">
422 ' . implode('', $lines) . '
423 </table>';
424 // Return accumulated content for filelisting:
425 $out .= '</div>';
426 return $out;
427 }
428
429 /**
430 * Get a list of Files in a folder filtered by extension
431 *
432 * @param Folder $folder
433 * @param array $extensionList
434 * @return File[]
435 */
436 protected function getFilesInFolder(Folder $folder, array $extensionList)
437 {
438 if (!empty($extensionList)) {
439 /** @var FileExtensionFilter $filter */
440 $filter = GeneralUtility::makeInstance(FileExtensionFilter::class);
441 $filter->setAllowedFileExtensions($extensionList);
442 $folder->setFileAndFolderNameFilters([[$filter, 'filterFileList']]);
443 }
444 return $folder->getFiles();
445 }
446
447 /**
448 * Get the HTML data required for a bulk selection of files of the TYPO3 Element Browser.
449 *
450 * @param int $filesCount Number of files currently displayed
451 * @return string HTML data required for a bulk selection of files - if $filesCount is 0, nothing is returned
452 */
453 protected function getBulkSelector($filesCount)
454 {
455 if (!$filesCount) {
456 return '';
457 }
458
459 $lang = $this->getLanguageService();
460 $out = '';
461
462 // Getting flag for showing/not showing thumbnails:
463 $noThumbsInEB = $this->getBackendUser()->getTSConfigVal('options.noThumbsInEB');
464 if (!$noThumbsInEB && $this->selectedFolder) {
465 // MENU-ITEMS, fetching the setting for thumbnails from File>List module:
466 $_MOD_MENU = ['displayThumbs' => ''];
467 $_MCONF['name'] = 'file_list';
468 $_MOD_SETTINGS = BackendUtility::getModuleData($_MOD_MENU, GeneralUtility::_GP('SET'), $_MCONF['name']);
469 $addParams = GeneralUtility::implodeArrayForUrl('', $this->getUrlParameters(['identifier' => $this->selectedFolder->getCombinedIdentifier()]));
470 $thumbNailCheck = '<div class="checkbox" style="padding:5px 0 15px 0"><label for="checkDisplayThumbs">'
471 . BackendUtility::getFuncCheck(
472 '',
473 'SET[displayThumbs]',
474 $_MOD_SETTINGS['displayThumbs'],
475 $this->thisScript,
476 $addParams,
477 'id="checkDisplayThumbs"'
478 )
479 . htmlspecialchars($lang->sL('LLL:EXT:lang/Resources/Private/Language/locallang_mod_file_list.xlf:displayThumbs')) . '</label></div>';
480 $out .= $thumbNailCheck;
481 } else {
482 $out .= '<div style="padding-top: 15px;"></div>';
483 }
484 return $out;
485 }
486
487 /**
488 * Checks if the given file is selectable in the filelist.
489 *
490 * In "plain" RTE mode only image files with a maximum width and height are selectable.
491 *
492 * @param FileInterface $file
493 * @param array $imgInfo Image dimensions from \TYPO3\CMS\Core\Imaging\GraphicalFunctions::getImageDimensions()
494 * @return bool TRUE if file is selectable.
495 */
496 protected function fileIsSelectableInFileList(FileInterface $file, array $imgInfo)
497 {
498 return $this->mode !== 'plain'
499 || (GeneralUtility::inList(SelectImageController::PLAIN_MODE_IMAGE_FILE_EXTENSIONS, strtolower($file->getExtension()))
500 && $imgInfo[0] <= $this->plainMaxWidth && $imgInfo[1] <= $this->plainMaxHeight);
501 }
502
503 /**
504 * @return string[] Array of body-tag attributes
505 */
506 public function getBodyTagAttributes()
507 {
508 return [
509 'data-elements' => json_encode($this->elements)
510 ];
511 }
512
513 /**
514 * Returns the URL of the current script
515 *
516 * @return string
517 */
518 public function getScriptUrl()
519 {
520 return $this->selectImageController->getScriptUrl();
521 }
522
523 /**
524 * Provides an array or GET parameters for URL generation
525 *
526 * @param array $values Array of values to include into the parameters or which might influence the parameters
527 *
528 * @return string[] Array of parameters which have to be added to URLs
529 */
530 public function getUrlParameters(array $values)
531 {
532 $parameters = [
533 'expandFolder' => isset($values['identifier']) ? $values['identifier'] : (string)$this->expandFolder
534 ];
535 return array_merge($this->selectImageController->getUrlParameters($values), $parameters);
536 }
537
538 /**
539 * Return TRUE if the handler supports to update a link.
540 *
541 * This is useful for file or page links, when only attributes are changed.
542 *
543 * @return bool
544 */
545 public function isUpdateSupported()
546 {
547 return false;
548 }
549
550 /**
551 * @return array
552 */
553 public function getLinkAttributes()
554 {
555 return [];
556 }
557
558 /**
559 * @param string[] $fieldDefinitions Array of link attribute field definitions
560 * @return string[]
561 */
562 public function modifyLinkAttributes(array $fieldDefinitions)
563 {
564 return $fieldDefinitions;
565 }
566
567 /**
568 * Check if given value is currently the selected item
569 *
570 * This method is only used in the page tree.
571 *
572 * @param array $values Values to be checked
573 *
574 * @return bool Returns TRUE if the given values match the currently selected item
575 */
576 public function isCurrentlySelectedItem(array $values)
577 {
578 return false;
579 }
580
581 /**
582 * Checks if this is the handler for the given link
583 *
584 * The handler may store this information locally for later usage.
585 *
586 * @param array $linkParts Link parts as returned from TypoLinkCodecService
587 *
588 * @return bool
589 */
590 public function canHandleLink(array $linkParts)
591 {
592 return false;
593 }
594
595 /**
596 * Format the current link for HTML output
597 *
598 * @return string
599 */
600 public function formatCurrentUrl()
601 {
602 return '';
603 }
604
605 /**
606 * @return LanguageService
607 */
608 protected function getLanguageService()
609 {
610 return $GLOBALS['LANG'];
611 }
612
613 /**
614 * @return BackendUserAuthentication
615 */
616 protected function getBackendUser()
617 {
618 return $GLOBALS['BE_USER'];
619 }
620 }