TYPO3 v15 dev-main snapshot ()
This commit is contained in:
@@ -0,0 +1,165 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* 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!
|
||||
*/
|
||||
|
||||
namespace TYPO3\CMS\Backend\Controller;
|
||||
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use TYPO3\CMS\Backend\Attribute\AsController;
|
||||
use TYPO3\CMS\Backend\Utility\BackendUtility;
|
||||
use TYPO3\CMS\Core\Crypto\HashService;
|
||||
use TYPO3\CMS\Core\Http\JsonResponse;
|
||||
use TYPO3\CMS\Core\LinkHandling\Exception\UnknownLinkHandlerException;
|
||||
use TYPO3\CMS\Core\LinkHandling\LinkService;
|
||||
use TYPO3\CMS\Core\LinkHandling\TypoLinkCodecService;
|
||||
use TYPO3\CMS\Core\Messaging\FlashMessage;
|
||||
use TYPO3\CMS\Core\Messaging\FlashMessageService;
|
||||
use TYPO3\CMS\Core\Page\JavaScriptModuleInstruction;
|
||||
use TYPO3\CMS\Core\Type\ContextualFeedbackSeverity;
|
||||
|
||||
/**
|
||||
* Extended controller for link browser
|
||||
*/
|
||||
#[AsController]
|
||||
class LinkBrowserController extends AbstractLinkBrowserController
|
||||
{
|
||||
public function __construct(
|
||||
protected readonly LinkService $linkService,
|
||||
protected readonly TypoLinkCodecService $typoLinkCodecService,
|
||||
protected readonly FlashMessageService $flashMessageService,
|
||||
private readonly HashService $hashService,
|
||||
) {}
|
||||
|
||||
public function getConfiguration(): array
|
||||
{
|
||||
$tsConfig = BackendUtility::getPagesTSconfig($this->getCurrentPageId());
|
||||
return $tsConfig['TCEMAIN.']['linkHandler.']['page.']['configuration.'] ?? [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode a typolink via ajax.
|
||||
* This avoids implementing the encoding functionality again in JS for the browser.
|
||||
*/
|
||||
public function encodeTypoLink(ServerRequestInterface $request): ResponseInterface
|
||||
{
|
||||
$typoLinkParts = $request->getQueryParams();
|
||||
if (isset($typoLinkParts['params'])) {
|
||||
$typoLinkParts['additionalParams'] = $typoLinkParts['params'];
|
||||
unset($typoLinkParts['params']);
|
||||
}
|
||||
$typoLink = $this->typoLinkCodecService->encode($typoLinkParts);
|
||||
return new JsonResponse(['typoLink' => $typoLink]);
|
||||
}
|
||||
|
||||
protected function initDocumentTemplate(): void
|
||||
{
|
||||
if (!$this->areFieldChangeFunctionsValid() && !$this->areFieldChangeFunctionsValid(true)) {
|
||||
$this->parameters['fieldChangeFunc'] = [];
|
||||
}
|
||||
$this->pageRenderer->getJavaScriptRenderer()->addJavaScriptModuleInstruction(
|
||||
JavaScriptModuleInstruction::create('@typo3/backend/form-engine-link-browser-adapter.js')
|
||||
// @todo use a proper constructor when migrating to TypeScript
|
||||
->invoke('setOnFieldChangeItems', $this->parameters['fieldChangeFunc'])
|
||||
);
|
||||
}
|
||||
|
||||
protected function getCurrentPageId(): int
|
||||
{
|
||||
$pageId = 0;
|
||||
$browserParameters = $this->parameters;
|
||||
if (isset($browserParameters['pid'])) {
|
||||
$pageId = $browserParameters['pid'];
|
||||
} elseif (isset($browserParameters['itemName'])) {
|
||||
// parse data[<table>][<uid>]
|
||||
if (preg_match('~data\[([^]]*)\]\[([^]]*)\]~', $browserParameters['itemName'], $matches)) {
|
||||
$recordArray = BackendUtility::getRecord($matches['1'], $matches['2']);
|
||||
if (is_array($recordArray)) {
|
||||
$pageId = $recordArray['pid'];
|
||||
}
|
||||
}
|
||||
}
|
||||
return (int)BackendUtility::getRealPageId((string)$browserParameters['table'], (int)$browserParameters['uid'], (int)$pageId);
|
||||
}
|
||||
|
||||
protected function initCurrentUrl(): void
|
||||
{
|
||||
$currentLink = isset($this->parameters['currentValue']) ? trim($this->parameters['currentValue']) : '';
|
||||
/** @var array<string, string> $currentLinkParts */
|
||||
$currentLinkParts = $this->typoLinkCodecService->decode($currentLink);
|
||||
$currentLinkParts['params'] = $currentLinkParts['additionalParams'];
|
||||
unset($currentLinkParts['additionalParams']);
|
||||
|
||||
if (!empty($currentLinkParts['url'])) {
|
||||
try {
|
||||
$data = $this->linkService->resolve($currentLinkParts['url']);
|
||||
$currentLinkParts['type'] = $data['type'];
|
||||
unset($data['type']);
|
||||
$currentLinkParts['url'] = $data;
|
||||
} catch (UnknownLinkHandlerException $e) {
|
||||
$this->flashMessageService->getMessageQueueByIdentifier()->enqueue(
|
||||
new FlashMessage(message: $e->getMessage(), severity: ContextualFeedbackSeverity::ERROR)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$this->currentLinkParts = $currentLinkParts;
|
||||
|
||||
parent::initCurrentUrl();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether submitted field change functions are valid
|
||||
* and are coming from the system and not from an external abuse.
|
||||
*
|
||||
* @param bool $handleFlexformSections Whether to handle flexform sections differently
|
||||
* @return bool Whether the submitted field change functions are valid
|
||||
*/
|
||||
protected function areFieldChangeFunctionsValid(bool $handleFlexformSections = false): bool
|
||||
{
|
||||
$result = false;
|
||||
if (isset($this->parameters['fieldChangeFunc']) && is_array($this->parameters['fieldChangeFunc']) && isset($this->parameters['fieldChangeFuncHash'])) {
|
||||
$matches = [];
|
||||
$pattern = '#\\[el\\]\\[(([^]-]+-[^]-]+-)(idx\\d+-)([^]]+))\\]#i';
|
||||
$fieldChangeFunctions = $this->parameters['fieldChangeFunc'];
|
||||
// Special handling of flexform sections:
|
||||
// Field change functions are modified in JavaScript, thus the hash is always invalid
|
||||
if ($handleFlexformSections && preg_match($pattern, $this->parameters['itemName'], $matches)) {
|
||||
$originalName = $matches[1];
|
||||
$cleanedName = $matches[2] . $matches[4];
|
||||
$fieldChangeFunctions = $this->strReplaceRecursively(
|
||||
$originalName,
|
||||
$cleanedName,
|
||||
$fieldChangeFunctions
|
||||
);
|
||||
}
|
||||
$result = hash_equals($this->hashService->hmac(serialize($fieldChangeFunctions), 'backend-link-browser'), $this->parameters['fieldChangeFuncHash']);
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
protected function strReplaceRecursively(string $search, string $replace, array $array): array
|
||||
{
|
||||
foreach ($array as &$item) {
|
||||
if (is_array($item)) {
|
||||
$item = $this->strReplaceRecursively($search, $replace, $item);
|
||||
} else {
|
||||
$item = str_replace($search, $replace, $item);
|
||||
}
|
||||
}
|
||||
return $array;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user