first commit
This commit is contained in:
commit
1218dd1517
12716 files changed
+989233
No files matched your search
@@ -0,0 +1,315 @@
|
||||
<?php
|
||||
declare(strict_types = 1);
|
||||
namespace TYPO3\CMS\Backend\Controller\File;
|
||||
|
||||
/*
|
||||
* This file is part of the TYPO3 CMS project.
|
||||
*
|
||||
* It is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, either version 2
|
||||
* of the License, or any later version.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*
|
||||
* The TYPO3 project - inspiring people to share!
|
||||
*/
|
||||
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use TYPO3\CMS\Backend\Routing\UriBuilder;
|
||||
use TYPO3\CMS\Backend\Template\ModuleTemplate;
|
||||
use TYPO3\CMS\Backend\Utility\BackendUtility;
|
||||
use TYPO3\CMS\Core\Compatibility\PublicMethodDeprecationTrait;
|
||||
use TYPO3\CMS\Core\Compatibility\PublicPropertyDeprecationTrait;
|
||||
use TYPO3\CMS\Core\Http\HtmlResponse;
|
||||
use TYPO3\CMS\Core\Imaging\Icon;
|
||||
use TYPO3\CMS\Core\Localization\LanguageService;
|
||||
use TYPO3\CMS\Core\Resource\Exception\InsufficientFolderAccessPermissionsException;
|
||||
use TYPO3\CMS\Core\Resource\OnlineMedia\Helpers\OnlineMediaHelperRegistry;
|
||||
use TYPO3\CMS\Core\Resource\ResourceFactory;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3\CMS\Core\Utility\MathUtility;
|
||||
use TYPO3\CMS\Fluid\View\StandaloneView;
|
||||
|
||||
/**
|
||||
* Script class for the create-new script
|
||||
*
|
||||
* Displays forms for creating folders (1 to 10), a media asset or a new file.
|
||||
* @internal This class is a specific Backend controller implementation and is not considered part of the Public TYPO3 API.
|
||||
*/
|
||||
class CreateFolderController
|
||||
{
|
||||
use PublicMethodDeprecationTrait;
|
||||
use PublicPropertyDeprecationTrait;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $deprecatedPublicMethods = [
|
||||
'main' => 'Using CreateFolderController::main() is deprecated and will not be possible anymore in TYPO3 v10.0.',
|
||||
];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $deprecatedPublicProperties = [
|
||||
'number' => 'Using $number of class CreateFolderController from outside is discouraged, as this variable is only used for internal storage.',
|
||||
'folderNumber' => 'Using $folderNumber of class CreateFolderController from outside is discouraged, as this variable is only used for internal storage.',
|
||||
'target' => 'Using $target of class CreateFolderController from outside is discouraged, as this variable is only used for internal storage.',
|
||||
'content' => 'Using $content of class CreateFolderController from outside is discouraged, as this variable is only used for internal storage.',
|
||||
'returnUrl' => 'Using $content of class CreateFolderController from outside is discouraged, as this variable is only used for internal storage.',
|
||||
'title' => 'Using $content of class CreateFolderController from outside is discouraged, as this variable is only used for internal storage.',
|
||||
];
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
protected $folderNumber = 10;
|
||||
|
||||
/**
|
||||
* Name of the filemount
|
||||
*
|
||||
* @var string
|
||||
* @deprecated since TYPO3 v9, will be removed in TYPO3 v10.0, unused
|
||||
*/
|
||||
protected $title;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
protected $number;
|
||||
|
||||
/**
|
||||
* Set with the target path inputted in &target
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $target;
|
||||
|
||||
/**
|
||||
* The folder object which is the target directory
|
||||
*
|
||||
* @var \TYPO3\CMS\Core\Resource\Folder $folderObject
|
||||
*/
|
||||
protected $folderObject;
|
||||
|
||||
/**
|
||||
* Return URL of list module.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $returnUrl;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $pathInfo;
|
||||
|
||||
/**
|
||||
* Accumulating content
|
||||
*
|
||||
* @var string
|
||||
* @deprecated since TYPO3 v9, will be removed in TYPO3 v10.0, unused
|
||||
*/
|
||||
protected $content;
|
||||
|
||||
/**
|
||||
* ModuleTemplate object
|
||||
*
|
||||
* @var ModuleTemplate
|
||||
*/
|
||||
protected $moduleTemplate;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->moduleTemplate = GeneralUtility::makeInstance(ModuleTemplate::class);
|
||||
// @deprecated since TYPO3 v9, will be moved out of __construct() in TYPO3 v10.0
|
||||
$this->init($GLOBALS['TYPO3_REQUEST']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes the request, currently everything is handled and put together via "main()"
|
||||
*
|
||||
* @param ServerRequestInterface $request the current request
|
||||
* @return ResponseInterface the response with the content
|
||||
*/
|
||||
public function mainAction(ServerRequestInterface $request): ResponseInterface
|
||||
{
|
||||
$this->main();
|
||||
return new HtmlResponse($this->moduleTemplate->renderContent());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ServerRequestInterface|null $request
|
||||
*
|
||||
* @throws InsufficientFolderAccessPermissionsException
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
protected function init(ServerRequestInterface $request): void
|
||||
{
|
||||
$parsedBody = $request->getParsedBody();
|
||||
$queryParams = $request->getQueryParams();
|
||||
|
||||
$this->number = $parsedBody['number'] ?? $queryParams['number'] ?? 0;
|
||||
$this->target = ($combinedIdentifier = $parsedBody['target'] ?? $queryParams['target'] ?? '');
|
||||
$this->returnUrl = GeneralUtility::sanitizeLocalUrl($parsedBody['returnUrl'] ?? $queryParams['returnUrl'] ?? '');
|
||||
// create the folder object
|
||||
if ($combinedIdentifier) {
|
||||
$this->folderObject = ResourceFactory::getInstance()
|
||||
->getFolderObjectFromCombinedIdentifier($combinedIdentifier);
|
||||
}
|
||||
// Cleaning and checking target directory
|
||||
if (!$this->folderObject) {
|
||||
$title = $this->getLanguageService()->sL('LLL:EXT:filelist/Resources/Private/Language/locallang_mod_file_list.xlf:paramError');
|
||||
$message = $this->getLanguageService()->sL('LLL:EXT:filelist/Resources/Private/Language/locallang_mod_file_list.xlf:targetNoDir');
|
||||
throw new \RuntimeException($title . ': ' . $message, 1294586845);
|
||||
}
|
||||
if ($this->folderObject->getStorage()->getUid() === 0) {
|
||||
throw new InsufficientFolderAccessPermissionsException(
|
||||
'You are not allowed to access folders outside your storages',
|
||||
1375889838
|
||||
);
|
||||
}
|
||||
|
||||
$pathInfo = [
|
||||
'combined_identifier' => $this->folderObject->getCombinedIdentifier(),
|
||||
];
|
||||
$uriBuilder = GeneralUtility::makeInstance(UriBuilder::class);
|
||||
|
||||
$this->moduleTemplate->getDocHeaderComponent()->setMetaInformation($pathInfo);
|
||||
$this->moduleTemplate->getPageRenderer()->loadRequireJsModule('TYPO3/CMS/Backend/ContextMenu');
|
||||
$this->moduleTemplate->addJavaScriptCode(
|
||||
'CreateFolderInlineJavaScript',
|
||||
'var path = "' . $this->target . '";
|
||||
var confirmTitle = '
|
||||
. GeneralUtility::quoteJSvalue(
|
||||
$this->getLanguageService()->sL('LLL:EXT:core/Resources/Private/Language/locallang_common.xlf:pleaseConfirm')
|
||||
)
|
||||
. ';
|
||||
var confirmText = '
|
||||
. GeneralUtility::quoteJSvalue(
|
||||
$this->getLanguageService()->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:mess.redraw')
|
||||
)
|
||||
. ';
|
||||
function reload(a) {
|
||||
var params = "&target="+encodeURIComponent(path)+"&number="+a+"&returnUrl=' . rawurlencode($this->returnUrl) . '";
|
||||
var url = \'' . (string)$uriBuilder->buildUriFromRoute('file_newfolder') . '\';
|
||||
if (!changed) {
|
||||
window.location.href = url + params;
|
||||
} else {
|
||||
var modal = top.TYPO3.Modal.confirm(confirmTitle, confirmText);
|
||||
modal.on(\'confirm.button.cancel\', function(e) {
|
||||
top.TYPO3.Modal.currentModal.trigger(\'modal-dismiss\');
|
||||
});
|
||||
modal.on(\'confirm.button.ok\', function(e) {
|
||||
top.TYPO3.Modal.currentModal.trigger(\'modal-dismiss\');
|
||||
window.location.href = url + params;
|
||||
});
|
||||
}
|
||||
}
|
||||
function backToList() {
|
||||
top.goToModule("file_FilelistList");
|
||||
}
|
||||
var changed = 0;'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Main function, rendering the main module content
|
||||
*/
|
||||
protected function main()
|
||||
{
|
||||
$lang = $this->getLanguageService();
|
||||
$assigns = [];
|
||||
$assigns['target'] = $this->target;
|
||||
if ($this->folderObject->checkActionPermission('add')) {
|
||||
$uriBuilder = GeneralUtility::makeInstance(UriBuilder::class);
|
||||
$assigns['moduleUrlTceFile'] = (string)$uriBuilder->buildUriFromRoute('tce_file');
|
||||
$assigns['cshFileNewFolder'] = BackendUtility::cshItem('xMOD_csh_corebe', 'file_newfolder');
|
||||
// Making the selector box for the number of concurrent folder-creations
|
||||
$this->number = MathUtility::forceIntegerInRange($this->number, 1, 10);
|
||||
for ($a = 1; $a <= $this->folderNumber; $a++) {
|
||||
$options = [];
|
||||
$options['value'] = $a;
|
||||
$options['selected'] = ($this->number == $a ? ' selected="selected"' : '');
|
||||
$assigns['options'][] = $options;
|
||||
}
|
||||
// Making the number of new-folder boxes needed:
|
||||
for ($a = 0; $a < $this->number; $a++) {
|
||||
$folder = [];
|
||||
$folder['this'] = $a;
|
||||
$folder['next'] = $a + 1;
|
||||
$assigns['folders'][] = $folder;
|
||||
}
|
||||
// Making submit button for folder creation:
|
||||
$assigns['returnUrl'] = $this->returnUrl;
|
||||
}
|
||||
|
||||
if ($this->folderObject->getStorage()->checkUserActionPermission('add', 'File')) {
|
||||
$uriBuilder = GeneralUtility::makeInstance(UriBuilder::class);
|
||||
$assigns['moduleUrlOnlineMedia'] = (string)$uriBuilder->buildUriFromRoute('online_media');
|
||||
$assigns['cshFileNewMedia'] = BackendUtility::cshItem('xMOD_csh_corebe', 'file_newMedia');
|
||||
// Create a list of allowed file extensions with the readable format "youtube, vimeo" etc.
|
||||
$fileExtList = [];
|
||||
$onlineMediaFileExt = OnlineMediaHelperRegistry::getInstance()->getSupportedFileExtensions();
|
||||
foreach ($onlineMediaFileExt as $fileExt) {
|
||||
if (GeneralUtility::verifyFilenameAgainstDenyPattern('.' . $fileExt)) {
|
||||
$fileExtList[] = strtoupper(htmlspecialchars($fileExt));
|
||||
}
|
||||
}
|
||||
$assigns['fileExtList'] = $fileExtList;
|
||||
|
||||
$assigns['moduleUrlTceFile'] = (string)$uriBuilder->buildUriFromRoute('tce_file');
|
||||
$assigns['cshFileNewFile'] = BackendUtility::cshItem('xMOD_csh_corebe', 'file_newfile');
|
||||
// Create a list of allowed file extensions with a text format "*.txt, *.css" etc.
|
||||
$fileExtList = [];
|
||||
$textFileExt = GeneralUtility::trimExplode(',', $GLOBALS['TYPO3_CONF_VARS']['SYS']['textfile_ext'], true);
|
||||
foreach ($textFileExt as $fileExt) {
|
||||
if (GeneralUtility::verifyFilenameAgainstDenyPattern('.' . $fileExt)) {
|
||||
$fileExtList[] = strtoupper(htmlspecialchars($fileExt));
|
||||
}
|
||||
}
|
||||
$assigns['txtFileExtList'] = $fileExtList;
|
||||
}
|
||||
|
||||
$buttonBar = $this->moduleTemplate->getDocHeaderComponent()->getButtonBar();
|
||||
// CSH button
|
||||
$helpButton = $buttonBar->makeHelpButton()
|
||||
->setFieldName('file_new')
|
||||
->setModuleName('xMOD_csh_corebe');
|
||||
$buttonBar->addButton($helpButton);
|
||||
|
||||
// Back
|
||||
if ($this->returnUrl) {
|
||||
$backButton = $buttonBar->makeLinkButton()
|
||||
->setHref($this->returnUrl)
|
||||
->setTitle($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.goBack'))
|
||||
->setIcon($this->moduleTemplate->getIconFactory()->getIcon('actions-view-go-back', Icon::SIZE_SMALL));
|
||||
$buttonBar->addButton($backButton);
|
||||
}
|
||||
|
||||
// Rendering of the output via fluid
|
||||
$view = GeneralUtility::makeInstance(StandaloneView::class);
|
||||
$view->setTemplateRootPaths([GeneralUtility::getFileAbsFileName('EXT:backend/Resources/Private/Templates')]);
|
||||
$view->setPartialRootPaths([GeneralUtility::getFileAbsFileName('EXT:backend/Resources/Private/Partials')]);
|
||||
$view->setTemplatePathAndFilename(GeneralUtility::getFileAbsFileName(
|
||||
'EXT:backend/Resources/Private/Templates/File/CreateFolder.html'
|
||||
));
|
||||
$view->assignMultiple($assigns);
|
||||
$this->moduleTemplate->setContent($view->render());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns LanguageService
|
||||
*
|
||||
* @return LanguageService
|
||||
*/
|
||||
protected function getLanguageService(): LanguageService
|
||||
{
|
||||
return $GLOBALS['LANG'];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,425 @@
|
||||
<?php
|
||||
declare(strict_types = 1);
|
||||
namespace TYPO3\CMS\Backend\Controller\File;
|
||||
|
||||
/*
|
||||
* This file is part of the TYPO3 CMS project.
|
||||
*
|
||||
* It is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, either version 2
|
||||
* of the License, or any later version.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*
|
||||
* The TYPO3 project - inspiring people to share!
|
||||
*/
|
||||
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use TYPO3\CMS\Backend\Form\FormResultCompiler;
|
||||
use TYPO3\CMS\Backend\Form\NodeFactory;
|
||||
use TYPO3\CMS\Backend\Routing\UriBuilder;
|
||||
use TYPO3\CMS\Backend\Template\Components\ButtonBar;
|
||||
use TYPO3\CMS\Backend\Template\DocumentTemplate;
|
||||
use TYPO3\CMS\Backend\Template\ModuleTemplate;
|
||||
use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
|
||||
use TYPO3\CMS\Core\Compatibility\PublicMethodDeprecationTrait;
|
||||
use TYPO3\CMS\Core\Compatibility\PublicPropertyDeprecationTrait;
|
||||
use TYPO3\CMS\Core\Http\HtmlResponse;
|
||||
use TYPO3\CMS\Core\Http\RedirectResponse;
|
||||
use TYPO3\CMS\Core\Imaging\Icon;
|
||||
use TYPO3\CMS\Core\Localization\LanguageService;
|
||||
use TYPO3\CMS\Core\Messaging\FlashMessage;
|
||||
use TYPO3\CMS\Core\Messaging\FlashMessageService;
|
||||
use TYPO3\CMS\Core\Resource\Exception\InsufficientFileAccessPermissionsException;
|
||||
use TYPO3\CMS\Core\Resource\ResourceFactory;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3\CMS\Core\Utility\HttpUtility;
|
||||
use TYPO3\CMS\Fluid\View\StandaloneView;
|
||||
|
||||
/**
|
||||
* Script Class for rendering the file editing screen
|
||||
* @internal This class is a specific Backend controller implementation and is not considered part of the Public TYPO3 API.
|
||||
*/
|
||||
class EditFileController
|
||||
{
|
||||
use PublicMethodDeprecationTrait;
|
||||
use PublicPropertyDeprecationTrait;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $deprecatedPublicMethods = [
|
||||
'main' => 'Using EditFileController::main() is deprecated and will not be possible anymore in TYPO3 v10.0.',
|
||||
];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $deprecatedPublicProperties = [
|
||||
'origTarget' => 'Using $origTarget of class EditFileController from outside is discouraged, as this variable is only used for internal storage.',
|
||||
'target' => 'Using $target of class EditFileController from outside is discouraged, as this variable is only used for internal storage.',
|
||||
'returnUrl' => 'Using $returnUrl of class EditFileController from outside is discouraged, as this variable is only used for internal storage.',
|
||||
'content' => 'Using $content of class EditFileController from outside is discouraged, as this variable is only used for internal storage.',
|
||||
'title' => 'Using $title of class EditFileController from outside is discouraged, as this variable is only used for internal storage.',
|
||||
'doc' => 'Using $doc of class EditFileController from outside is discouraged, as this variable is only used for internal storage.',
|
||||
];
|
||||
/**
|
||||
* Module content accumulated.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $content;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $title;
|
||||
|
||||
/**
|
||||
* Document template object
|
||||
*
|
||||
* @var DocumentTemplate
|
||||
* @deprecated since TYPO3 v9, will be removed in TYPO3 v10.0, unused
|
||||
*/
|
||||
protected $doc;
|
||||
|
||||
/**
|
||||
* Original input target
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $origTarget;
|
||||
|
||||
/**
|
||||
* The original target, but validated.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $target;
|
||||
|
||||
/**
|
||||
* Return URL of list module.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $returnUrl;
|
||||
|
||||
/**
|
||||
* the file that is being edited on
|
||||
*
|
||||
* @var \TYPO3\CMS\Core\Resource\AbstractFile
|
||||
*/
|
||||
protected $fileObject;
|
||||
|
||||
/**
|
||||
* ModuleTemplate object
|
||||
*
|
||||
* @var ModuleTemplate
|
||||
*/
|
||||
protected $moduleTemplate;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->moduleTemplate = GeneralUtility::makeInstance(ModuleTemplate::class);
|
||||
// @deprecated since TYPO3 v9, will be moved out of __construct() in TYPO3 v10.0
|
||||
$this->init($GLOBALS['TYPO3_REQUEST']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes the request, currently everything is handled and put together via "main()"
|
||||
*
|
||||
* @param ServerRequestInterface $request the current request
|
||||
* @return ResponseInterface the response with the content
|
||||
*/
|
||||
public function mainAction(ServerRequestInterface $request): ResponseInterface
|
||||
{
|
||||
if ($response = $this->process()) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
return new HtmlResponse($this->moduleTemplate->renderContent());
|
||||
}
|
||||
|
||||
/**
|
||||
* Main function, rendering the actual content of the editing page
|
||||
*/
|
||||
protected function main()
|
||||
{
|
||||
$response = $this->process();
|
||||
|
||||
if ($response instanceof RedirectResponse) {
|
||||
HttpUtility::redirect($response->getHeaderLine('location'), $response->getStatusCode());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize script class
|
||||
*
|
||||
* @param ServerRequestInterface $request
|
||||
*
|
||||
* @throws InsufficientFileAccessPermissionsException
|
||||
*/
|
||||
protected function init(ServerRequestInterface $request): void
|
||||
{
|
||||
$parsedBody = $request->getParsedBody();
|
||||
$queryParams = $request->getQueryParams();
|
||||
|
||||
// Setting target, which must be a file reference to a file within the mounts.
|
||||
$this->target = $this->origTarget = $parsedBody['target'] ?? $queryParams['target'] ?? '';
|
||||
$this->returnUrl = GeneralUtility::sanitizeLocalUrl($parsedBody['returnUrl'] ?? $queryParams['returnUrl'] ?? '');
|
||||
// create the file object
|
||||
if ($this->target) {
|
||||
$this->fileObject = ResourceFactory::getInstance()
|
||||
->retrieveFileOrFolderObject($this->target);
|
||||
}
|
||||
// Cleaning and checking target directory
|
||||
if (!$this->fileObject) {
|
||||
$title = $this->getLanguageService()->sL('LLL:EXT:filelist/Resources/Private/Language/locallang_mod_file_list.xlf:paramError');
|
||||
$message = $this->getLanguageService()->sL('LLL:EXT:filelist/Resources/Private/Language/locallang_mod_file_list.xlf:targetNoDir');
|
||||
throw new \RuntimeException($title . ': ' . $message, 1294586841);
|
||||
}
|
||||
if ($this->fileObject->getStorage()->getUid() === 0) {
|
||||
throw new InsufficientFileAccessPermissionsException(
|
||||
'You are not allowed to access files outside your storages',
|
||||
1375889832
|
||||
);
|
||||
}
|
||||
|
||||
// Setting the title and the icon
|
||||
$icon = $this->moduleTemplate->getIconFactory()->getIcon('apps-filetree-root', Icon::SIZE_SMALL)->render();
|
||||
$this->title = $icon
|
||||
. htmlspecialchars(
|
||||
$this->fileObject->getStorage()->getName()
|
||||
) . ': ' . htmlspecialchars(
|
||||
$this->fileObject->getIdentifier()
|
||||
);
|
||||
|
||||
// Setting template object
|
||||
$this->moduleTemplate->addJavaScriptCode(
|
||||
'FileEditBackToList',
|
||||
'function backToList() {
|
||||
top.goToModule("file_FilelistList");
|
||||
}'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Main function, rendering the actual content of the editing page
|
||||
*
|
||||
* @return ResponseInterface|null Possible redirect response
|
||||
*/
|
||||
protected function process(): ?ResponseInterface
|
||||
{
|
||||
$dataColumnDefinition = [
|
||||
'label' => htmlspecialchars($this->getLanguageService()->sL('LLL:EXT:core/Resources/Private/Language/locallang_common.xlf:file'))
|
||||
. ' ' . htmlspecialchars($this->target),
|
||||
'config' => [
|
||||
'type' => 'text',
|
||||
'cols' => 48,
|
||||
'wrap' => 'OFF',
|
||||
],
|
||||
'defaultExtras' => 'fixed-font: enable-tab'
|
||||
];
|
||||
|
||||
$this->getButtonsInternal();
|
||||
// Hook: before compiling the output
|
||||
foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/file_edit.php']['preOutputProcessingHook'] ?? [] as $hookFunction) {
|
||||
$hookParameters = [
|
||||
'content' => &$this->content,
|
||||
'target' => &$this->target,
|
||||
'dataColumnDefinition' => &$dataColumnDefinition,
|
||||
];
|
||||
GeneralUtility::callUserFunction($hookFunction, $hookParameters, $this);
|
||||
}
|
||||
|
||||
$assigns = [];
|
||||
$uriBuilder = GeneralUtility::makeInstance(UriBuilder::class);
|
||||
$assigns['moduleUrlTceFile'] = (string)$uriBuilder->buildUriFromRoute('tce_file');
|
||||
$assigns['fileName'] = $this->fileObject->getName();
|
||||
|
||||
$extList = $GLOBALS['TYPO3_CONF_VARS']['SYS']['textfile_ext'];
|
||||
try {
|
||||
if (!$extList || !GeneralUtility::inList($extList, $this->fileObject->getExtension())) {
|
||||
// @todo throw a minor exception here, not the global one
|
||||
throw new \Exception('Files with that extension are not editable. Allowed extensions are: ' . $extList, 1476050135);
|
||||
}
|
||||
|
||||
// Making the formfields
|
||||
$hValue = (string)$uriBuilder->buildUriFromRoute('file_edit', [
|
||||
'target' => $this->origTarget,
|
||||
'returnUrl' => $this->returnUrl
|
||||
]);
|
||||
|
||||
$formData = [
|
||||
'databaseRow' => [
|
||||
'uid' => 0,
|
||||
'data' => $this->fileObject->getContents(),
|
||||
'target' => $this->fileObject->getUid(),
|
||||
'redirect' => $hValue,
|
||||
],
|
||||
'tableName' => 'editfile',
|
||||
'processedTca' => [
|
||||
'columns' => [
|
||||
'data' => $dataColumnDefinition,
|
||||
'target' => [
|
||||
'config' => [
|
||||
'type' => 'input',
|
||||
'renderType' => 'hidden',
|
||||
],
|
||||
],
|
||||
'redirect' => [
|
||||
'config' => [
|
||||
'type' => 'input',
|
||||
'renderType' => 'hidden',
|
||||
],
|
||||
],
|
||||
],
|
||||
'types' => [
|
||||
1 => [
|
||||
'showitem' => 'data,target,redirect',
|
||||
],
|
||||
],
|
||||
],
|
||||
'recordTypeValue' => 1,
|
||||
'inlineStructure' => [],
|
||||
'renderType' => 'fullRecordContainer',
|
||||
];
|
||||
|
||||
$resultArray = GeneralUtility::makeInstance(NodeFactory::class)->create($formData)->render();
|
||||
$formResultCompiler = GeneralUtility::makeInstance(FormResultCompiler::class);
|
||||
$formResultCompiler->mergeResult($resultArray);
|
||||
|
||||
$form = $formResultCompiler->addCssFiles()
|
||||
. $resultArray['html']
|
||||
. $formResultCompiler->printNeededJSFunctions();
|
||||
|
||||
$assigns['form'] = $form;
|
||||
} catch (\Exception $e) {
|
||||
// @todo catch dedicated exceptions, not the global one, if possible
|
||||
$flashMessage = GeneralUtility::makeInstance(FlashMessage::class, $e->getMessage(), '', FlashMessage::ERROR, true);
|
||||
|
||||
$flashMessageService = GeneralUtility::makeInstance(FlashMessageService::class);
|
||||
$defaultFlashMessageQueue = $flashMessageService->getMessageQueueByIdentifier();
|
||||
$defaultFlashMessageQueue->enqueue($flashMessage);
|
||||
|
||||
return new RedirectResponse($this->returnUrl, 500);
|
||||
}
|
||||
|
||||
// Rendering of the output via fluid
|
||||
$view = GeneralUtility::makeInstance(StandaloneView::class);
|
||||
$view->setTemplateRootPaths([GeneralUtility::getFileAbsFileName('EXT:backend/Resources/Private/Templates')]);
|
||||
$view->setPartialRootPaths([GeneralUtility::getFileAbsFileName('EXT:backend/Resources/Private/Partials')]);
|
||||
$view->setTemplatePathAndFilename(GeneralUtility::getFileAbsFileName(
|
||||
'EXT:backend/Resources/Private/Templates/File/EditFile.html'
|
||||
));
|
||||
$view->assignMultiple($assigns);
|
||||
$pageContent = $view->render();
|
||||
|
||||
// Hook: after compiling the output
|
||||
foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/file_edit.php']['postOutputProcessingHook'] ?? [] as $hookFunction) {
|
||||
$hookParameters = [
|
||||
'pageContent' => &$pageContent,
|
||||
'target' => &$this->target
|
||||
];
|
||||
GeneralUtility::callUserFunction($hookFunction, $hookParameters, $this);
|
||||
}
|
||||
|
||||
$this->content .= $pageContent;
|
||||
$this->moduleTemplate->setContent($this->content);
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the buttons for the docheader and returns them as an
|
||||
*
|
||||
* @deprecated since TYPO3 v9, will be set protected in TYPO3 v10.0
|
||||
*/
|
||||
public function getButtons()
|
||||
{
|
||||
trigger_error('EditFileController->getButtons() will be replaced by protected method getButtonsInternal() in TYPO3 v10.0. Do not call from other extension.', E_USER_DEPRECATED);
|
||||
$this->getButtonsInternal();
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the buttons for the docheader
|
||||
*/
|
||||
protected function getButtonsInternal(): void
|
||||
{
|
||||
$buttonBar = $this->moduleTemplate->getDocHeaderComponent()->getButtonBar();
|
||||
|
||||
$lang = $this->getLanguageService();
|
||||
// CSH button
|
||||
$helpButton = $buttonBar->makeHelpButton()
|
||||
->setFieldName('file_edit')
|
||||
->setModuleName('xMOD_csh_corebe');
|
||||
$buttonBar->addButton($helpButton);
|
||||
|
||||
// Save button
|
||||
$saveButton = $buttonBar->makeInputButton()
|
||||
->setName('_save')
|
||||
->setValue('1')
|
||||
->setForm('EditFileController')
|
||||
->setTitle($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:file_edit.php.submit'))
|
||||
->setIcon($this->moduleTemplate->getIconFactory()->getIcon('actions-document-save', Icon::SIZE_SMALL));
|
||||
|
||||
// Save and Close button
|
||||
$saveAndCloseButton = $buttonBar->makeInputButton()
|
||||
->setName('_saveandclosedok')
|
||||
->setValue('1')
|
||||
->setForm('EditFileController')
|
||||
->setOnClick(
|
||||
'document.editform.elements.namedItem("data[editfile][0][redirect]").value='
|
||||
. GeneralUtility::quoteJSvalue($this->returnUrl)
|
||||
. ';'
|
||||
)
|
||||
->setTitle($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:file_edit.php.saveAndClose'))
|
||||
->setIcon($this->moduleTemplate->getIconFactory()->getIcon(
|
||||
'actions-document-save-close',
|
||||
Icon::SIZE_SMALL
|
||||
));
|
||||
|
||||
$splitButton = $buttonBar->makeSplitButton()
|
||||
->addItem($saveButton)
|
||||
->addItem($saveAndCloseButton);
|
||||
$buttonBar->addButton($splitButton, ButtonBar::BUTTON_POSITION_LEFT, 20);
|
||||
|
||||
// Cancel button
|
||||
$closeButton = $buttonBar->makeLinkButton()
|
||||
->setHref('#')
|
||||
->setOnClick('backToList(); return false;')
|
||||
->setTitle($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.cancel'))
|
||||
->setIcon($this->moduleTemplate->getIconFactory()->getIcon('actions-close', Icon::SIZE_SMALL));
|
||||
$buttonBar->addButton($closeButton, ButtonBar::BUTTON_POSITION_LEFT, 10);
|
||||
|
||||
// Make shortcut:
|
||||
$shortButton = $buttonBar->makeShortcutButton()
|
||||
->setModuleName('file_edit')
|
||||
->setGetVariables(['target']);
|
||||
$buttonBar->addButton($shortButton);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns LanguageService
|
||||
*
|
||||
* @return LanguageService
|
||||
*/
|
||||
protected function getLanguageService(): LanguageService
|
||||
{
|
||||
return $GLOBALS['LANG'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current BE user.
|
||||
*
|
||||
* @return BackendUserAuthentication
|
||||
*/
|
||||
protected function getBackendUser(): BackendUserAuthentication
|
||||
{
|
||||
return $GLOBALS['BE_USER'];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,341 @@
|
||||
<?php
|
||||
declare(strict_types = 1);
|
||||
namespace TYPO3\CMS\Backend\Controller\File;
|
||||
|
||||
/*
|
||||
* This file is part of the TYPO3 CMS project.
|
||||
*
|
||||
* It is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, either version 2
|
||||
* of the License, or any later version.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*
|
||||
* The TYPO3 project - inspiring people to share!
|
||||
*/
|
||||
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use TYPO3\CMS\Backend\Clipboard\Clipboard;
|
||||
use TYPO3\CMS\Backend\Routing\UriBuilder;
|
||||
use TYPO3\CMS\Backend\Utility\BackendUtility;
|
||||
use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
|
||||
use TYPO3\CMS\Core\Compatibility\PublicMethodDeprecationTrait;
|
||||
use TYPO3\CMS\Core\Http\HtmlResponse;
|
||||
use TYPO3\CMS\Core\Http\JsonResponse;
|
||||
use TYPO3\CMS\Core\Http\RedirectResponse;
|
||||
use TYPO3\CMS\Core\Imaging\Icon;
|
||||
use TYPO3\CMS\Core\Imaging\IconFactory;
|
||||
use TYPO3\CMS\Core\Resource\DuplicationBehavior;
|
||||
use TYPO3\CMS\Core\Resource\File;
|
||||
use TYPO3\CMS\Core\Resource\Folder;
|
||||
use TYPO3\CMS\Core\Resource\ProcessedFile;
|
||||
use TYPO3\CMS\Core\Resource\ResourceFactory;
|
||||
use TYPO3\CMS\Core\Utility\File\ExtendedFileUtility;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3\CMS\Core\Utility\HttpUtility;
|
||||
|
||||
/**
|
||||
* Gateway for TCE (TYPO3 Core Engine) file-handling through POST forms.
|
||||
* This script serves as the file administration part of the TYPO3 Core Engine.
|
||||
* Basically it includes two libraries which are used to manipulate files on the server.
|
||||
* @internal This class is a specific Backend controller implementation and is not considered part of the Public TYPO3 API.
|
||||
*/
|
||||
class FileController
|
||||
{
|
||||
use PublicMethodDeprecationTrait;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $deprecatedPublicMethods = [
|
||||
'initClipboard' => 'Using FileController::initClipboard() is deprecated and will not be possible anymore in TYPO3 v10.0.',
|
||||
'main' => 'Using FileController::main() is deprecated and will not be possible anymore in TYPO3 v10.0.',
|
||||
];
|
||||
|
||||
/**
|
||||
* Array of file-operations.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $file;
|
||||
|
||||
/**
|
||||
* Clipboard operations array
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $CB;
|
||||
|
||||
/**
|
||||
* Defines behaviour when uploading files with names that already exist; possible values are
|
||||
* the values of the \TYPO3\CMS\Core\Resource\DuplicationBehavior enumeration
|
||||
*
|
||||
* @var \TYPO3\CMS\Core\Resource\DuplicationBehavior
|
||||
*/
|
||||
protected $overwriteExistingFiles;
|
||||
|
||||
/**
|
||||
* The page where the user should be redirected after everything is done
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $redirect;
|
||||
|
||||
/**
|
||||
* Internal, dynamic:
|
||||
* File processor object
|
||||
*
|
||||
* @var ExtendedFileUtility
|
||||
*/
|
||||
protected $fileProcessor;
|
||||
|
||||
/**
|
||||
* The result array from the file processor
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $fileData;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
// @deprecated since TYPO3 v9, will be moved out of __construct() in TYPO3 v10.0
|
||||
$this->init($GLOBALS['TYPO3_REQUEST']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Injects the request object for the current request or subrequest
|
||||
* As this controller goes only through the main() method, it just redirects to the given URL afterwards.
|
||||
*
|
||||
* @param ServerRequestInterface $request the current request
|
||||
* @return ResponseInterface the response with the content
|
||||
*/
|
||||
public function mainAction(ServerRequestInterface $request): ResponseInterface
|
||||
{
|
||||
$this->main();
|
||||
|
||||
BackendUtility::setUpdateSignal('updateFolderTree');
|
||||
|
||||
// go and edit the new created file
|
||||
if ($request->getParsedBody()['edit'] ?? '') {
|
||||
/** @var File $file */
|
||||
$file = $this->fileData['newfile'][0];
|
||||
if ($file !== null) {
|
||||
$this->redirect = $this->getFileEditRedirect($file) ?? $this->redirect;
|
||||
}
|
||||
}
|
||||
if ($this->redirect) {
|
||||
return new RedirectResponse(
|
||||
GeneralUtility::locationHeaderUrl($this->redirect),
|
||||
303
|
||||
);
|
||||
}
|
||||
// empty response
|
||||
return new HtmlResponse('');
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the actual process from within the ajaxExec function
|
||||
* therefore, it does exactly the same as the real typo3/tce_file.php
|
||||
* but without calling the "finish" method, thus makes it simpler to deal with the
|
||||
* actual return value
|
||||
*
|
||||
* @param ServerRequestInterface $request
|
||||
* @return ResponseInterface
|
||||
*/
|
||||
public function processAjaxRequest(ServerRequestInterface $request): ResponseInterface
|
||||
{
|
||||
$this->main();
|
||||
$errors = $this->fileProcessor->getErrorMessages();
|
||||
if (!empty($errors)) {
|
||||
return (new HtmlResponse('<t3err>' . implode(',', $errors) . '</t3err>'))->withStatus(500, '(AJAX)');
|
||||
}
|
||||
$flatResult = [];
|
||||
foreach ($this->fileData as $action => $results) {
|
||||
foreach ($results as $result) {
|
||||
if (is_array($result)) {
|
||||
foreach ($result as $subResult) {
|
||||
$flatResult[$action][] = $this->flattenResultDataValue($subResult);
|
||||
}
|
||||
} else {
|
||||
$flatResult[$action][] = $this->flattenResultDataValue($result);
|
||||
}
|
||||
}
|
||||
}
|
||||
return (new JsonResponse())->setPayload($flatResult);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ajax entry point to check if a file exists in a folder
|
||||
*
|
||||
* @param ServerRequestInterface $request
|
||||
* @return ResponseInterface
|
||||
*/
|
||||
public function fileExistsInFolderAction(ServerRequestInterface $request): ResponseInterface
|
||||
{
|
||||
$fileName = $request->getParsedBody()['fileName'] ?? $request->getQueryParams()['fileName'] ?? null;
|
||||
$fileTarget = $request->getParsedBody()['fileTarget'] ?? $request->getQueryParams()['fileTarget'] ?? null;
|
||||
|
||||
$fileFactory = GeneralUtility::makeInstance(ResourceFactory::class);
|
||||
$fileTargetObject = $fileFactory->retrieveFileOrFolderObject($fileTarget);
|
||||
$processedFileName = $fileTargetObject->getStorage()->sanitizeFileName($fileName, $fileTargetObject);
|
||||
|
||||
$result = [];
|
||||
if ($fileTargetObject->hasFile($processedFileName)) {
|
||||
$result = $this->flattenResultDataValue($fileTargetObject->getStorage()->getFileInFolder($processedFileName, $fileTargetObject));
|
||||
}
|
||||
return (new JsonResponse())->setPayload($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registering incoming data
|
||||
*
|
||||
* @param ServerRequestInterface $request
|
||||
*/
|
||||
protected function init(ServerRequestInterface $request): void
|
||||
{
|
||||
// Set the GPvars from outside
|
||||
$parsedBody = $request->getParsedBody();
|
||||
$queryParams = $request->getQueryParams();
|
||||
$this->file = $parsedBody['data'] ?? $queryParams['data'] ?? null;
|
||||
if ($this->file === null) {
|
||||
// This happens in clipboard mode only
|
||||
$this->redirect = GeneralUtility::sanitizeLocalUrl($parsedBody['redirect'] ?? $queryParams['redirect'] ?? '');
|
||||
} else {
|
||||
$mode = key($this->file);
|
||||
$elementKey = key($this->file[$mode]);
|
||||
$this->redirect = GeneralUtility::sanitizeLocalUrl($this->file[$mode][$elementKey]['redirect']);
|
||||
}
|
||||
$this->CB = $parsedBody['CB'] ?? $queryParams['CB'] ?? null;
|
||||
|
||||
if (isset($this->file['rename'][0]['conflictMode'])) {
|
||||
$conflictMode = $this->file['rename'][0]['conflictMode'];
|
||||
unset($this->file['rename'][0]['conflictMode']);
|
||||
$this->overwriteExistingFiles = DuplicationBehavior::cast($conflictMode);
|
||||
} else {
|
||||
$this->overwriteExistingFiles = DuplicationBehavior::cast($parsedBody['overwriteExistingFiles'] ?? $queryParams['overwriteExistingFiles'] ?? null);
|
||||
}
|
||||
$this->initClipboard();
|
||||
$this->fileProcessor = GeneralUtility::makeInstance(ExtendedFileUtility::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the Clipboard. This will fetch the data about files to paste/delete if such an action has been sent.
|
||||
*/
|
||||
protected function initClipboard(): void
|
||||
{
|
||||
if (is_array($this->CB)) {
|
||||
$clipObj = GeneralUtility::makeInstance(Clipboard::class);
|
||||
$clipObj->initializeClipboard();
|
||||
if ($this->CB['paste']) {
|
||||
$clipObj->setCurrentPad($this->CB['pad']);
|
||||
$this->file = $clipObj->makePasteCmdArray_file($this->CB['paste'], $this->file);
|
||||
}
|
||||
if ($this->CB['delete']) {
|
||||
$clipObj->setCurrentPad($this->CB['pad']);
|
||||
$this->file = $clipObj->makeDeleteCmdArray_file($this->file);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Performing the file admin action:
|
||||
* Initializes the objects, setting permissions, sending data to object.
|
||||
*/
|
||||
protected function main(): void
|
||||
{
|
||||
// Initializing:
|
||||
$this->fileProcessor->setActionPermissions();
|
||||
$this->fileProcessor->setExistingFilesConflictMode($this->overwriteExistingFiles);
|
||||
$this->fileProcessor->start($this->file);
|
||||
$this->fileData = $this->fileProcessor->processData();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets URI to be used for editing given file (if file extension is defined in textfile_ext)
|
||||
*
|
||||
* @param File $file to be edited
|
||||
* @return string|null URI to be redirected to
|
||||
* @throws \TYPO3\CMS\Backend\Routing\Exception\RouteNotFoundException
|
||||
*/
|
||||
protected function getFileEditRedirect(File $file): ?string
|
||||
{
|
||||
$textFileExtensionList = $GLOBALS['TYPO3_CONF_VARS']['SYS']['textfile_ext'] ?? '';
|
||||
if (!GeneralUtility::inList($textFileExtensionList, $file->getExtension())) {
|
||||
return null;
|
||||
}
|
||||
$properties = $file->getProperties();
|
||||
$urlParameters = [
|
||||
'target' => $properties['storage'] . ':' . $properties['identifier']
|
||||
];
|
||||
if ($this->redirect) {
|
||||
$urlParameters['returnUrl'] = $this->redirect;
|
||||
}
|
||||
$uriBuilder = GeneralUtility::makeInstance(UriBuilder::class);
|
||||
return (string)$uriBuilder->buildUriFromRoute('file_edit', $urlParameters);
|
||||
}
|
||||
|
||||
/**
|
||||
* Redirecting the user after the processing has been done.
|
||||
* Might also display error messages directly, if any.
|
||||
*
|
||||
* @deprecated since TYPO3 v9. Will be removed in TYPO3 v10.0.
|
||||
*/
|
||||
public function finish()
|
||||
{
|
||||
trigger_error('FileController->finish() will be removed in TYPO3 v10.0. Do not call from other extension.', E_USER_DEPRECATED);
|
||||
BackendUtility::setUpdateSignal('updateFolderTree');
|
||||
if ($this->redirect) {
|
||||
HttpUtility::redirect($this->redirect);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Flatten result value from FileProcessor
|
||||
*
|
||||
* The value can be a File, Folder or boolean
|
||||
*
|
||||
* @param bool|File|Folder $result
|
||||
*
|
||||
* @return bool|string|array
|
||||
*/
|
||||
protected function flattenResultDataValue($result)
|
||||
{
|
||||
if ($result instanceof File) {
|
||||
$thumbUrl = '';
|
||||
if (GeneralUtility::inList($GLOBALS['TYPO3_CONF_VARS']['GFX']['imagefile_ext'], $result->getExtension())) {
|
||||
$processedFile = $result->process(ProcessedFile::CONTEXT_IMAGEPREVIEW, []);
|
||||
if ($processedFile) {
|
||||
$thumbUrl = $processedFile->getPublicUrl(true);
|
||||
}
|
||||
}
|
||||
$iconFactory = GeneralUtility::makeInstance(IconFactory::class);
|
||||
$result = array_merge(
|
||||
$result->toArray(),
|
||||
[
|
||||
'date' => BackendUtility::date($result->getModificationTime()),
|
||||
'icon' => $iconFactory->getIconForFileExtension($result->getExtension(), Icon::SIZE_SMALL)->render(),
|
||||
'thumbUrl' => $thumbUrl
|
||||
]
|
||||
);
|
||||
} elseif ($result instanceof Folder) {
|
||||
$result = $result->getIdentifier();
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current BE user.
|
||||
*
|
||||
* @return BackendUserAuthentication
|
||||
*/
|
||||
protected function getBackendUser(): BackendUserAuthentication
|
||||
{
|
||||
return $GLOBALS['BE_USER'];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,264 @@
|
||||
<?php
|
||||
declare(strict_types = 1);
|
||||
namespace TYPO3\CMS\Backend\Controller\File;
|
||||
|
||||
/*
|
||||
* This file is part of the TYPO3 CMS project.
|
||||
*
|
||||
* It is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, either version 2
|
||||
* of the License, or any later version.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*
|
||||
* The TYPO3 project - inspiring people to share!
|
||||
*/
|
||||
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use TYPO3\CMS\Backend\Template\ModuleTemplate;
|
||||
use TYPO3\CMS\Core\Compatibility\PublicPropertyDeprecationTrait;
|
||||
use TYPO3\CMS\Core\Http\HtmlResponse;
|
||||
use TYPO3\CMS\Core\Imaging\Icon;
|
||||
use TYPO3\CMS\Core\Localization\LanguageService;
|
||||
use TYPO3\CMS\Core\Resource\Exception\InsufficientFolderAccessPermissionsException;
|
||||
use TYPO3\CMS\Core\Resource\ResourceFactory;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
|
||||
/**
|
||||
* Script Class for display up to 10 upload fields
|
||||
* @internal This class is a specific Backend controller implementation and is not considered part of the Public TYPO3 API.
|
||||
*/
|
||||
class FileUploadController
|
||||
{
|
||||
use PublicPropertyDeprecationTrait;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $deprecatedPublicProperties = [
|
||||
'title' => 'Using $title of class FileUploadController from outside is discouraged as this variable is only used for internal storage.',
|
||||
'target' => 'Using $target of class FileUploadController from outside is discouraged as this variable is only used for internal storage.',
|
||||
'returnUrl' => 'Using $returnUrl of class FileUploadController from outside is discouraged as this variable is only used for internal storage.',
|
||||
'content' => 'Using $content of class FileUploadController from outside is discouraged as this variable is only used for internal storage.',
|
||||
];
|
||||
|
||||
/**
|
||||
* Name of the filemount
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $title;
|
||||
|
||||
/**
|
||||
* Set with the target path inputted in &target
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $target;
|
||||
|
||||
/**
|
||||
* Return URL of list module.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $returnUrl;
|
||||
|
||||
/**
|
||||
* Accumulating content
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $content;
|
||||
|
||||
/**
|
||||
* The folder object which is the target directory for the upload
|
||||
*
|
||||
* @var \TYPO3\CMS\Core\Resource\Folder $folderObject
|
||||
*/
|
||||
protected $folderObject;
|
||||
|
||||
/**
|
||||
* ModuleTemplate object
|
||||
*
|
||||
* @var ModuleTemplate
|
||||
*/
|
||||
protected $moduleTemplate;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->moduleTemplate = GeneralUtility::makeInstance(ModuleTemplate::class);
|
||||
$this->getLanguageService()->includeLLFile('EXT:core/Resources/Private/Language/locallang_misc.xlf');
|
||||
|
||||
// @deprecated since TYPO3 v9, will be moved out of __construct() in TYPO3 v10.0
|
||||
$this->init($GLOBALS['TYPO3_REQUEST']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes the request, currently everything is handled and put together via "renderContent()"
|
||||
*
|
||||
* @param ServerRequestInterface $request the current request
|
||||
* @return ResponseInterface the response with the content
|
||||
*/
|
||||
public function mainAction(ServerRequestInterface $request): ResponseInterface
|
||||
{
|
||||
$this->renderContent();
|
||||
return new HtmlResponse($this->moduleTemplate->renderContent());
|
||||
}
|
||||
|
||||
/**
|
||||
* Main function, rendering the upload file form fields
|
||||
*
|
||||
* @deprecated since TYPO3 v9, will be removed in TYPO3 v10.0
|
||||
*/
|
||||
public function main()
|
||||
{
|
||||
trigger_error('FileUploadController->main() will be replaced by protected method renderContent() in TYPO3 v10.0. Do not call from other extension.', E_USER_DEPRECATED);
|
||||
$this->renderContent();
|
||||
}
|
||||
|
||||
/**
|
||||
* This function renders the upload form
|
||||
*
|
||||
* @return string The HTML form as a string, ready for outputting
|
||||
* @deprecated since TYPO3 v9, will be removed in TYPO3 v10.0
|
||||
*/
|
||||
public function renderUploadForm()
|
||||
{
|
||||
trigger_error('FileUploadController->renderUploadForm() will be replaced by protected method renderUploadFormInternal() in TYPO3 v10.0. Do not call from other extension.', E_USER_DEPRECATED);
|
||||
return $this->renderUploadFormInternal();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize
|
||||
*
|
||||
* @param ServerRequestInterface $request
|
||||
* @throws InsufficientFolderAccessPermissionsException
|
||||
*/
|
||||
protected function init(ServerRequestInterface $request): void
|
||||
{
|
||||
$parsedBody = $request->getParsedBody();
|
||||
$queryParams = $request->getQueryParams();
|
||||
|
||||
/** @var \TYPO3\CMS\Backend\Routing\UriBuilder $uriBuilder */
|
||||
$uriBuilder = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Routing\UriBuilder::class);
|
||||
// Initialize GPvars:
|
||||
$this->target = $parsedBody['target'] ?? $queryParams['target'] ?? null;
|
||||
$this->returnUrl = GeneralUtility::sanitizeLocalUrl($parsedBody['returnUrl'] ?? $queryParams['returnUrl'] ?? '');
|
||||
if (!$this->returnUrl) {
|
||||
$this->returnUrl = (string)$uriBuilder->buildUriFromRoute('file_list', [
|
||||
'id' => rawurlencode($this->target)
|
||||
]);
|
||||
}
|
||||
// Create the folder object
|
||||
if ($this->target) {
|
||||
$this->folderObject = ResourceFactory::getInstance()
|
||||
->retrieveFileOrFolderObject($this->target);
|
||||
}
|
||||
if ($this->folderObject->getStorage()->getUid() === 0) {
|
||||
throw new InsufficientFolderAccessPermissionsException(
|
||||
'You are not allowed to access folders outside your storages',
|
||||
1375889834
|
||||
);
|
||||
}
|
||||
|
||||
// Cleaning and checking target directory
|
||||
if (!$this->folderObject) {
|
||||
$title = $this->getLanguageService()->sL('LLL:EXT:filelist/Resources/Private/Language/locallang_mod_file_list.xlf:paramError');
|
||||
$message = $this->getLanguageService()->sL('LLL:EXT:filelist/Resources/Private/Language/locallang_mod_file_list.xlf:targetNoDir');
|
||||
throw new \RuntimeException($title . ': ' . $message, 1294586843);
|
||||
}
|
||||
|
||||
// Setting up the context sensitive menu
|
||||
$this->moduleTemplate->getPageRenderer()->loadRequireJsModule('TYPO3/CMS/Backend/ContextMenu');
|
||||
|
||||
// building pathInfo for metaInformation
|
||||
$pathInfo = [
|
||||
'combined_identifier' => $this->folderObject->getCombinedIdentifier(),
|
||||
];
|
||||
$this->moduleTemplate->getDocHeaderComponent()->setMetaInformation($pathInfo);
|
||||
}
|
||||
|
||||
/**
|
||||
* Render module content
|
||||
*/
|
||||
protected function renderContent(): void
|
||||
{
|
||||
$lang = $this->getLanguageService();
|
||||
/** @var \TYPO3\CMS\Backend\Routing\UriBuilder $uriBuilder */
|
||||
$uriBuilder = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Routing\UriBuilder::class);
|
||||
|
||||
// set page title
|
||||
$this->moduleTemplate->setTitle($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:file_upload.php.pagetitle'));
|
||||
|
||||
$pageContent = '<form action="'
|
||||
. htmlspecialchars((string)$uriBuilder->buildUriFromRoute('tce_file'))
|
||||
. '" method="post" id="FileUploadController" name="editform" enctype="multipart/form-data">';
|
||||
// Make page header:
|
||||
$pageContent .= '<h1>' . $lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:file_upload.php.pagetitle') . '</h1>';
|
||||
$pageContent .= $this->renderUploadFormInternal();
|
||||
|
||||
// Header Buttons
|
||||
$buttonBar = $this->moduleTemplate->getDocHeaderComponent()->getButtonBar();
|
||||
|
||||
// csh button
|
||||
$cshButton = $buttonBar->makeHelpButton()
|
||||
->setModuleName('xMOD_csh_corebe')
|
||||
->setFieldName('file_upload');
|
||||
$buttonBar->addButton($cshButton);
|
||||
|
||||
// back button
|
||||
if ($this->returnUrl) {
|
||||
$backButton = $buttonBar->makeLinkButton()
|
||||
->setHref($this->returnUrl)
|
||||
->setTitle($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.goBack'))
|
||||
->setIcon($this->moduleTemplate->getIconFactory()->getIcon('actions-view-go-back', Icon::SIZE_SMALL));
|
||||
$buttonBar->addButton($backButton);
|
||||
}
|
||||
|
||||
$pageContent .= '</form>';
|
||||
$this->content .= '<div>' . $pageContent . '</div>';
|
||||
$this->moduleTemplate->setContent($this->content);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function renders the upload form
|
||||
*
|
||||
* @return string The HTML form as a string, ready for outputting
|
||||
*/
|
||||
protected function renderUploadFormInternal(): string
|
||||
{
|
||||
$content = '
|
||||
<div class="form-group">
|
||||
<input type="file" multiple="multiple" class="form-control" name="upload_1[]" />
|
||||
<input type="hidden" name="data[upload][1][target]" value="' . htmlspecialchars($this->folderObject->getCombinedIdentifier()) . '" />
|
||||
<input type="hidden" name="data[upload][1][data]" value="1" />
|
||||
</div>
|
||||
<div class="checkbox">
|
||||
<label for="overwriteExistingFiles">
|
||||
<input type="checkbox" name="overwriteExistingFiles" id="overwriteExistingFiles" value="replace" /> ' . htmlspecialchars($this->getLanguageService()->getLL('overwriteExistingFiles')) . '</label>
|
||||
</div>
|
||||
<div>
|
||||
<input type="hidden" name="data[upload][1][redirect]" value="' . $this->returnUrl . '" />
|
||||
<input class="btn btn-primary" type="submit" value="' . htmlspecialchars($this->getLanguageService()->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:file_upload.php.submit')) . '" />
|
||||
</div>
|
||||
<div class="callout callout-warning">
|
||||
' . htmlspecialchars($this->getLanguageService()->getLL('uploadMultipleFilesInfo')) . '
|
||||
</div>
|
||||
';
|
||||
|
||||
return $content;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return LanguageService
|
||||
*/
|
||||
protected function getLanguageService(): LanguageService
|
||||
{
|
||||
return $GLOBALS['LANG'];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,281 @@
|
||||
<?php
|
||||
declare(strict_types = 1);
|
||||
namespace TYPO3\CMS\Backend\Controller\File;
|
||||
|
||||
/*
|
||||
* This file is part of the TYPO3 CMS project.
|
||||
*
|
||||
* It is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, either version 2
|
||||
* of the License, or any later version.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*
|
||||
* The TYPO3 project - inspiring people to share!
|
||||
*/
|
||||
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use TYPO3\CMS\Backend\Template\Components\ButtonBar;
|
||||
use TYPO3\CMS\Backend\Template\DocumentTemplate;
|
||||
use TYPO3\CMS\Backend\Template\ModuleTemplate;
|
||||
use TYPO3\CMS\Core\Compatibility\PublicPropertyDeprecationTrait;
|
||||
use TYPO3\CMS\Core\Http\HtmlResponse;
|
||||
use TYPO3\CMS\Core\Imaging\Icon;
|
||||
use TYPO3\CMS\Core\Localization\LanguageService;
|
||||
use TYPO3\CMS\Core\Resource\DuplicationBehavior;
|
||||
use TYPO3\CMS\Core\Resource\Exception\InsufficientFileAccessPermissionsException;
|
||||
use TYPO3\CMS\Core\Resource\File;
|
||||
use TYPO3\CMS\Core\Resource\Folder;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3\CMS\Fluid\View\StandaloneView;
|
||||
|
||||
/**
|
||||
* Script Class for the rename-file form.
|
||||
* @internal This class is a specific Backend controller implementation and is not considered part of the Public TYPO3 API.
|
||||
*/
|
||||
class RenameFileController
|
||||
{
|
||||
use PublicPropertyDeprecationTrait;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $deprecatedPublicProperties = [
|
||||
'title' => 'Using $title of class RenameFileController from outside is discouraged as this variable is only used for internal storage.',
|
||||
'target' => 'Using $target of class RenameFileController from outside is discouraged as this variable is only used for internal storage.',
|
||||
'returnUrl' => 'Using $returnUrl of class RenameFileController from outside is discouraged as this variable is only used for internal storage.',
|
||||
'content' => 'Using $content of class RenameFileController from outside is discouraged as this variable is only used for internal storage.',
|
||||
];
|
||||
|
||||
/**
|
||||
* Name of the filemount
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $title;
|
||||
|
||||
/**
|
||||
* Target path
|
||||
*
|
||||
* @var string
|
||||
* @internal
|
||||
*/
|
||||
protected $target;
|
||||
|
||||
/**
|
||||
* The file or folder object that should be renamed
|
||||
*
|
||||
* @var File|Folder $fileOrFolderObject
|
||||
*/
|
||||
protected $fileOrFolderObject;
|
||||
|
||||
/**
|
||||
* Return URL of list module.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $returnUrl;
|
||||
|
||||
/**
|
||||
* Accumulating content
|
||||
*
|
||||
* @var string
|
||||
* @internal
|
||||
*/
|
||||
protected $content;
|
||||
|
||||
/**
|
||||
* ModuleTemplate object
|
||||
*
|
||||
* @var ModuleTemplate
|
||||
*/
|
||||
protected $moduleTemplate;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->moduleTemplate = GeneralUtility::makeInstance(ModuleTemplate::class);
|
||||
|
||||
// @deprecated since TYPO3 v9, will be moved out of __construct() in TYPO3 v10.0
|
||||
$this->init($GLOBALS['TYPO3_REQUEST']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes the request, currently everything is handled and put together via "renderContent()"
|
||||
*
|
||||
* @param ServerRequestInterface $request
|
||||
* @return ResponseInterface the response with the content
|
||||
*/
|
||||
public function mainAction(ServerRequestInterface $request): ResponseInterface
|
||||
{
|
||||
$this->renderContent();
|
||||
|
||||
return new HtmlResponse($this->moduleTemplate->renderContent());
|
||||
}
|
||||
|
||||
/**
|
||||
* Main function, rendering the content of the rename form
|
||||
*
|
||||
* @deprecated since TYPO3 v9, will be removed in TYPO3 v10.0
|
||||
*/
|
||||
public function main()
|
||||
{
|
||||
trigger_error('RenameFileController->main() will be replaced by protected method renderContent() in TYPO3 v10.0. Do not call from other extension.', E_USER_DEPRECATED);
|
||||
$this->renderContent();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize
|
||||
*
|
||||
* @param ServerRequestInterface $request
|
||||
* @throws InsufficientFileAccessPermissionsException
|
||||
*/
|
||||
protected function init(ServerRequestInterface $request): void
|
||||
{
|
||||
$parsedBody = $request->getParsedBody();
|
||||
$queryParams = $request->getQueryParams();
|
||||
|
||||
// Initialize GPvars:
|
||||
$this->target = $parsedBody['target'] ?? $queryParams['target'] ?? null;
|
||||
$this->returnUrl = GeneralUtility::sanitizeLocalUrl($parsedBody['returnUrl'] ?? $queryParams['returnUrl'] ?? '');
|
||||
// Cleaning and checking target
|
||||
if ($this->target) {
|
||||
$this->fileOrFolderObject = \TYPO3\CMS\Core\Resource\ResourceFactory::getInstance()->retrieveFileOrFolderObject($this->target);
|
||||
}
|
||||
if (!$this->fileOrFolderObject) {
|
||||
$title = $this->getLanguageService()->sL('LLL:EXT:filelist/Resources/Private/Language/locallang_mod_file_list.xlf:paramError');
|
||||
$message = $this->getLanguageService()->sL('LLL:EXT:filelist/Resources/Private/Language/locallang_mod_file_list.xlf:targetNoDir');
|
||||
throw new \RuntimeException($title . ': ' . $message, 1294586844);
|
||||
}
|
||||
if ($this->fileOrFolderObject->getStorage()->getUid() === 0) {
|
||||
throw new InsufficientFileAccessPermissionsException('You are not allowed to access files outside your storages', 1375889840);
|
||||
}
|
||||
|
||||
// If a folder should be renamed, AND the returnURL should go to the old directory name, the redirect is forced
|
||||
// so the redirect will NOT end in an error message
|
||||
// this case only happens if you select the folder itself in the foldertree and then use the clickmenu to
|
||||
// rename the folder
|
||||
if ($this->fileOrFolderObject instanceof Folder) {
|
||||
$parsedUrl = parse_url($this->returnUrl);
|
||||
$queryParts = GeneralUtility::explodeUrl2Array(urldecode($parsedUrl['query']));
|
||||
if ($queryParts['id'] === $this->fileOrFolderObject->getCombinedIdentifier()) {
|
||||
$this->returnUrl = str_replace(
|
||||
urlencode($queryParts['id']),
|
||||
urlencode($this->fileOrFolderObject->getStorage()->getRootLevelFolder()->getCombinedIdentifier()),
|
||||
$this->returnUrl
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// building pathInfo for metaInformation
|
||||
$pathInfo = [
|
||||
'combined_identifier' => $this->fileOrFolderObject->getCombinedIdentifier(),
|
||||
];
|
||||
$this->moduleTemplate->getDocHeaderComponent()->setMetaInformation($pathInfo);
|
||||
|
||||
// Setting up the context sensitive menu
|
||||
$this->moduleTemplate->getPageRenderer()->loadRequireJsModule('TYPO3/CMS/Backend/ContextMenu');
|
||||
$this->moduleTemplate->getPageRenderer()->loadRequireJsModule('TYPO3/CMS/Backend/RenameFile');
|
||||
|
||||
// Add javaScript
|
||||
$this->moduleTemplate->addJavaScriptCode(
|
||||
'RenameFileInlineJavaScript',
|
||||
'function backToList() {top.goToModule("file_FilelistList");}'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Render module content
|
||||
*/
|
||||
protected function renderContent(): void
|
||||
{
|
||||
$assigns = [];
|
||||
/** @var \TYPO3\CMS\Backend\Routing\UriBuilder $uriBuilder */
|
||||
$uriBuilder = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Routing\UriBuilder::class);
|
||||
$assigns['moduleUrlTceFile'] = (string)$uriBuilder->buildUriFromRoute('tce_file');
|
||||
$assigns['returnUrl'] = $this->returnUrl;
|
||||
|
||||
if ($this->fileOrFolderObject instanceof Folder) {
|
||||
$fileIdentifier = $this->fileOrFolderObject->getCombinedIdentifier();
|
||||
$targetLabel = 'file_rename.php.label.target.folder';
|
||||
} else {
|
||||
$fileIdentifier = $this->fileOrFolderObject->getUid();
|
||||
$targetLabel = 'file_rename.php.label.target.file';
|
||||
$assigns['conflictMode'] = DuplicationBehavior::cast(DuplicationBehavior::RENAME);
|
||||
$assigns['destination'] = $this->fileOrFolderObject->getParentFolder()->getCombinedIdentifier();
|
||||
}
|
||||
|
||||
$assigns['fileName'] = $this->fileOrFolderObject->getName();
|
||||
$assigns['fileIdentifier'] = $fileIdentifier;
|
||||
$assigns['fieldLabel'] = $targetLabel;
|
||||
|
||||
// Create buttons
|
||||
$buttonBar = $this->moduleTemplate->getDocHeaderComponent()->getButtonBar();
|
||||
|
||||
// csh button
|
||||
$cshButton = $buttonBar->makeHelpButton()
|
||||
->setModuleName('xMOD_csh_corebe')
|
||||
->setFieldName('file_rename');
|
||||
$buttonBar->addButton($cshButton);
|
||||
|
||||
// back button
|
||||
if ($this->returnUrl) {
|
||||
$backButton = $buttonBar->makeLinkButton()
|
||||
->setHref($this->returnUrl)
|
||||
->setTitle($this->getLanguageService()->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.goBack'))
|
||||
->setIcon($this->moduleTemplate->getIconFactory()->getIcon('actions-close', Icon::SIZE_SMALL));
|
||||
$buttonBar->addButton($backButton);
|
||||
}
|
||||
|
||||
// Save and Close button
|
||||
$saveAndCloseButton = $buttonBar->makeInputButton()
|
||||
->setName('_saveandclose')
|
||||
->setValue('1')
|
||||
->setShowLabelText(true)
|
||||
->setClasses('t3js-submit-file-rename')
|
||||
->setForm('RenameFileController')
|
||||
->setTitle($this->getLanguageService()->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:file_edit.php.saveAndClose'))
|
||||
->setIcon($this->moduleTemplate->getIconFactory()->getIcon('actions-document-save-close', Icon::SIZE_SMALL));
|
||||
|
||||
$buttonBar->addButton($saveAndCloseButton, ButtonBar::BUTTON_POSITION_LEFT, 20);
|
||||
|
||||
$this->moduleTemplate->getPageRenderer()->addInlineLanguageLabelArray([
|
||||
'file_rename.actions.cancel' => $this->getLanguageService()->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:file_rename.actions.cancel'),
|
||||
'file_rename.actions.rename' => $this->getLanguageService()->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:file_rename.actions.rename'),
|
||||
'file_rename.actions.override' => $this->getLanguageService()->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:file_rename.actions.override'),
|
||||
'file_rename.exists.title' => $this->getLanguageService()->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:file_rename.exists.title'),
|
||||
'file_rename.exists.description' => $this->getLanguageService()->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:file_rename.exists.description'),
|
||||
]);
|
||||
|
||||
// Rendering of the output via fluid
|
||||
$view = GeneralUtility::makeInstance(StandaloneView::class);
|
||||
$view->setTemplateRootPaths([GeneralUtility::getFileAbsFileName('EXT:backend/Resources/Private/Templates')]);
|
||||
$view->setPartialRootPaths([GeneralUtility::getFileAbsFileName('EXT:backend/Resources/Private/Partials')]);
|
||||
$view->setTemplatePathAndFilename(GeneralUtility::getFileAbsFileName(
|
||||
'EXT:backend/Resources/Private/Templates/File/RenameFile.html'
|
||||
));
|
||||
$view->assignMultiple($assigns);
|
||||
$this->content = $view->render();
|
||||
$this->moduleTemplate->setContent($this->content);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return LanguageService
|
||||
*/
|
||||
protected function getLanguageService(): LanguageService
|
||||
{
|
||||
return $GLOBALS['LANG'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return DocumentTemplate
|
||||
*/
|
||||
protected function getDocumentTemplate(): DocumentTemplate
|
||||
{
|
||||
return $GLOBALS['TBE_TEMPLATE'];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,242 @@
|
||||
<?php
|
||||
declare(strict_types = 1);
|
||||
namespace TYPO3\CMS\Backend\Controller\File;
|
||||
|
||||
/*
|
||||
* This file is part of the TYPO3 CMS project.
|
||||
*
|
||||
* It is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, either version 2
|
||||
* of the License, or any later version.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*
|
||||
* The TYPO3 project - inspiring people to share!
|
||||
*/
|
||||
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use TYPO3\CMS\Backend\Routing\UriBuilder;
|
||||
use TYPO3\CMS\Backend\Template\ModuleTemplate;
|
||||
use TYPO3\CMS\Core\Compatibility\PublicPropertyDeprecationTrait;
|
||||
use TYPO3\CMS\Core\Http\HtmlResponse;
|
||||
use TYPO3\CMS\Core\Imaging\Icon;
|
||||
use TYPO3\CMS\Core\Localization\LanguageService;
|
||||
use TYPO3\CMS\Core\Resource\Exception\InsufficientFileAccessPermissionsException;
|
||||
use TYPO3\CMS\Core\Resource\Folder;
|
||||
use TYPO3\CMS\Core\Resource\ResourceFactory;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3\CMS\Fluid\View\StandaloneView;
|
||||
|
||||
/**
|
||||
* Script Class for the replace-file form
|
||||
* @internal This class is a specific Backend controller implementation and is not considered part of the Public TYPO3 API.
|
||||
*/
|
||||
class ReplaceFileController
|
||||
{
|
||||
use PublicPropertyDeprecationTrait;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $deprecatedPublicProperties = [
|
||||
'doc' => 'Using $doc of class ReplaceFileController from outside is discouraged as this variable is only used for internal storage.',
|
||||
'title' => 'Using $title of class ReplaceFileController from outside is discouraged as this variable is only used for internal storage.',
|
||||
'uid' => 'Using $uid of class ReplaceFileController from outside is discouraged as this variable is only used for internal storage.',
|
||||
'returnUrl' => 'Using $returnUrl of class ReplaceFileController from outside is discouraged as this variable is only used for internal storage.',
|
||||
'content' => 'Using $content of class ReplaceFileController from outside is discouraged as this variable is only used for internal storage.',
|
||||
];
|
||||
|
||||
/**
|
||||
* Document template object
|
||||
*
|
||||
* @var \TYPO3\CMS\Backend\Template\DocumentTemplate
|
||||
*/
|
||||
protected $doc;
|
||||
|
||||
/**
|
||||
* Name of the filemount
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $title;
|
||||
|
||||
/**
|
||||
* sys_file uid
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $uid;
|
||||
|
||||
/**
|
||||
* The file or folder object that should be renamed
|
||||
*
|
||||
* @var \TYPO3\CMS\Core\Resource\ResourceInterface $fileOrFolderObject
|
||||
*/
|
||||
protected $fileOrFolderObject;
|
||||
|
||||
/**
|
||||
* Return URL of list module.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $returnUrl;
|
||||
|
||||
/**
|
||||
* Accumulating content
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $content;
|
||||
|
||||
/**
|
||||
* ModuleTemplate object
|
||||
*
|
||||
* @var ModuleTemplate
|
||||
*/
|
||||
protected $moduleTemplate;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->moduleTemplate = GeneralUtility::makeInstance(ModuleTemplate::class);
|
||||
|
||||
// @deprecated since TYPO3 v9, will be moved out of __construct() in TYPO3 v10.0
|
||||
$this->init($GLOBALS['TYPO3_REQUEST']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes the request, currently everything is handled and put together via "main()"
|
||||
*
|
||||
* @param ServerRequestInterface $request the current request
|
||||
* @return ResponseInterface the response with the content
|
||||
*/
|
||||
public function mainAction(ServerRequestInterface $request): ResponseInterface
|
||||
{
|
||||
$this->renderContent();
|
||||
return new HtmlResponse($this->moduleTemplate->renderContent());
|
||||
}
|
||||
|
||||
/**
|
||||
* Main function, rendering the content of the replace form
|
||||
*/
|
||||
public function main()
|
||||
{
|
||||
trigger_error('ReplaceFileController->main() will be replaced by protected method renderContent() in TYPO3 v10.0. Do not call from other extension.', E_USER_DEPRECATED);
|
||||
$this->renderContent();
|
||||
}
|
||||
|
||||
/**
|
||||
* Init
|
||||
*
|
||||
* @param ServerRequestInterface $request
|
||||
* @throws \RuntimeException
|
||||
* @throws InsufficientFileAccessPermissionsException
|
||||
*/
|
||||
protected function init(ServerRequestInterface $request): void
|
||||
{
|
||||
$parsedBody = $request->getParsedBody();
|
||||
$queryParams = $request->getQueryParams();
|
||||
$lang = $this->getLanguageService();
|
||||
|
||||
// Initialize GPvars:
|
||||
$this->uid = (int)($parsedBody['uid'] ?? $queryParams['uid'] ?? 0);
|
||||
$this->returnUrl = GeneralUtility::sanitizeLocalUrl($parsedBody['returnUrl'] ?? $queryParams['returnUrl'] ?? '');
|
||||
|
||||
// Cleaning and checking uid
|
||||
if ($this->uid > 0) {
|
||||
$this->fileOrFolderObject = ResourceFactory::getInstance()
|
||||
->retrieveFileOrFolderObject('file:' . $this->uid);
|
||||
}
|
||||
if (!$this->fileOrFolderObject) {
|
||||
$title = $lang->sL('LLL:EXT:filelist/Resources/Private/Language/locallang_mod_file_list.xlf:paramError');
|
||||
$message = $lang->sL('LLL:EXT:filelist/Resources/Private/Language/locallang_mod_file_list.xlf:targetNoDir');
|
||||
throw new \RuntimeException($title . ': ' . $message, 1436895930);
|
||||
}
|
||||
if ($this->fileOrFolderObject->getStorage()->getUid() === 0) {
|
||||
throw new InsufficientFileAccessPermissionsException(
|
||||
'You are not allowed to access files outside your storages',
|
||||
1436895931
|
||||
);
|
||||
}
|
||||
|
||||
// If a folder should be renamed, AND the returnURL should go to the old directory name, the redirect is forced
|
||||
// so the redirect will NOT end in an error message
|
||||
// this case only happens if you select the folder itself in the foldertree and then use the clickmenu to
|
||||
// rename the folder
|
||||
if ($this->fileOrFolderObject instanceof Folder) {
|
||||
$parsedUrl = parse_url($this->returnUrl);
|
||||
$queryParts = GeneralUtility::explodeUrl2Array(urldecode($parsedUrl['query']));
|
||||
if ($queryParts['id'] === $this->fileOrFolderObject->getCombinedIdentifier()) {
|
||||
$this->returnUrl = str_replace(
|
||||
urlencode($queryParts['id']),
|
||||
urlencode($this->fileOrFolderObject->getStorage()->getRootLevelFolder()->getCombinedIdentifier()),
|
||||
$this->returnUrl
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$pathInfo = [
|
||||
'combined_identifier' => $this->fileOrFolderObject->getCombinedIdentifier(),
|
||||
];
|
||||
$this->moduleTemplate->getDocHeaderComponent()->setMetaInformation($pathInfo);
|
||||
$this->moduleTemplate->getPageRenderer()->loadRequireJsModule('TYPO3/CMS/Backend/ContextMenu');
|
||||
$this->moduleTemplate->addJavaScriptCode(
|
||||
'ReplaceFileOnlineJavaScript',
|
||||
'function backToList() {top.goToModule("file_FilelistList");}'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Render module content
|
||||
*/
|
||||
protected function renderContent(): void
|
||||
{
|
||||
// Assign variables used by the fluid template
|
||||
$assigns = [];
|
||||
/** @var \TYPO3\CMS\Backend\Routing\UriBuilder $uriBuilder */
|
||||
$uriBuilder = GeneralUtility::makeInstance(UriBuilder::class);
|
||||
$assigns['moduleUrlTceFile'] = (string)$uriBuilder->buildUriFromRoute('tce_file');
|
||||
$assigns['uid'] = $this->uid;
|
||||
$assigns['returnUrl'] = $this->returnUrl;
|
||||
|
||||
$buttonBar = $this->moduleTemplate->getDocHeaderComponent()->getButtonBar();
|
||||
// csh button
|
||||
$cshButton = $buttonBar->makeHelpButton()
|
||||
->setModuleName('xMOD_csh_corebe')
|
||||
->setFieldName('file_rename');
|
||||
$buttonBar->addButton($cshButton);
|
||||
|
||||
// Back button
|
||||
if ($this->returnUrl) {
|
||||
$returnButton = $buttonBar->makeLinkButton()
|
||||
->setHref($this->returnUrl)
|
||||
->setTitle($this->getLanguageService()->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.goBack'))
|
||||
->setIcon($this->moduleTemplate->getIconFactory()->getIcon('actions-view-go-back', Icon::SIZE_SMALL));
|
||||
$buttonBar->addButton($returnButton);
|
||||
}
|
||||
|
||||
// Rendering of the output via fluid
|
||||
$view = GeneralUtility::makeInstance(StandaloneView::class);
|
||||
$view->setTemplateRootPaths([GeneralUtility::getFileAbsFileName('EXT:backend/Resources/Private/Templates')]);
|
||||
$view->setPartialRootPaths([GeneralUtility::getFileAbsFileName('EXT:backend/Resources/Private/Partials')]);
|
||||
$view->setTemplatePathAndFilename(GeneralUtility::getFileAbsFileName(
|
||||
'EXT:backend/Resources/Private/Templates/File/ReplaceFile.html'
|
||||
));
|
||||
$view->assignMultiple($assigns);
|
||||
$this->content = $view->render();
|
||||
|
||||
$this->moduleTemplate->setContent($this->content);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return LanguageService
|
||||
*/
|
||||
protected function getLanguageService(): LanguageService
|
||||
{
|
||||
return $GLOBALS['LANG'];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
<?php
|
||||
declare(strict_types = 1);
|
||||
namespace TYPO3\CMS\Backend\Controller\File;
|
||||
|
||||
/*
|
||||
* This file is part of the TYPO3 CMS project.
|
||||
*
|
||||
* It is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, either version 2
|
||||
* of the License, or any later version.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*
|
||||
* The TYPO3 project - inspiring people to share!
|
||||
*/
|
||||
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use TYPO3\CMS\Core\Http\Response;
|
||||
use TYPO3\CMS\Core\Resource\ProcessedFile;
|
||||
use TYPO3\CMS\Core\Resource\ResourceFactory;
|
||||
use TYPO3\CMS\Core\Utility\ArrayUtility;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
|
||||
/**
|
||||
* @internal This class is a specific Backend controller implementation and is not considered part of the Public TYPO3 API.
|
||||
*/
|
||||
class ThumbnailController
|
||||
{
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $defaultConfiguration = [
|
||||
'width' => 64,
|
||||
'height' => 64,
|
||||
'crop' => null,
|
||||
];
|
||||
|
||||
/**
|
||||
* @param ServerRequestInterface $request
|
||||
* @return ResponseInterface
|
||||
*/
|
||||
public function render(ServerRequestInterface $request): ResponseInterface
|
||||
{
|
||||
try {
|
||||
$parameters = $this->extractParameters($request->getQueryParams());
|
||||
$response = $this->generateThumbnail(
|
||||
$parameters['fileId'] ?? null,
|
||||
$parameters['configuration'] ?? []
|
||||
);
|
||||
} catch (\TYPO3\CMS\Core\Resource\Exception $exception) {
|
||||
// catch and handle only resource related exceptions
|
||||
$response = $this->generateNotFoundResponse();
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $queryParameters
|
||||
* @return array|null
|
||||
*/
|
||||
protected function extractParameters(array $queryParameters)
|
||||
{
|
||||
$expectedHash = GeneralUtility::hmac(
|
||||
$queryParameters['parameters'] ?? '',
|
||||
ThumbnailController::class
|
||||
);
|
||||
if (!hash_equals($expectedHash, $queryParameters['hmac'] ?? '')) {
|
||||
throw new \InvalidArgumentException(
|
||||
'HMAC could not be verified',
|
||||
1534484203
|
||||
);
|
||||
}
|
||||
|
||||
return json_decode($queryParameters['parameters'] ?? null, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed|int $fileId
|
||||
* @param array $configuration
|
||||
* @return Response
|
||||
* @throws \TYPO3\CMS\Core\Resource\Exception\FileDoesNotExistException
|
||||
*/
|
||||
protected function generateThumbnail($fileId, array $configuration): ResponseInterface
|
||||
{
|
||||
$file = ResourceFactory::getInstance()->getFileObject($fileId);
|
||||
if (empty($file) || $file->isMissing()) {
|
||||
return $this->generateNotFoundResponse();
|
||||
}
|
||||
|
||||
$processingConfiguration = $this->defaultConfiguration;
|
||||
ArrayUtility::mergeRecursiveWithOverrule(
|
||||
$processingConfiguration,
|
||||
$configuration
|
||||
);
|
||||
|
||||
$processedImage = $file->process(
|
||||
ProcessedFile::CONTEXT_IMAGECROPSCALEMASK,
|
||||
$processingConfiguration
|
||||
);
|
||||
$filePath = $processedImage->getForLocalProcessing(false);
|
||||
return new Response($filePath, 200, [
|
||||
'Content-Type' => $processedImage->getMimeType()
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ResponseInterface
|
||||
*/
|
||||
protected function generateNotFoundResponse(): ResponseInterface
|
||||
{
|
||||
return new Response('', 404);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user