2 declare(strict_types = 1);
18 use Psr\Http\Message\ResponseInterface;
19 use Psr\Http\Message\ServerRequestInterface;
20 use Psr\Http\Server\MiddlewareInterface;
21 use Psr\Http\Server\RequestHandlerInterface;
22 use Symfony\Component\HttpFoundation\Cookie;
69 public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
78 $this->
setCookie(
'', $request->getAttribute(
'normalizedParams'));
85 if (is_array($configuration) && $configuration[
'fullWorkspace'] > 0) {
87 (
int)$configuration[
'fullWorkspace'],
102 if ($request->getQueryParams()[
'ADMCMD_noBeUser']) {
107 $GLOBALS[
'TSFE']->set_no_cache(
'GET Parameter ADMCMD_noBeUser was given',
true);
110 $response = $handler->handle($request);
115 $body = $response->getBody();
117 $content = $body->getContents();
118 $content = str_ireplace(
'</body>', $previewInfo .
'</body>', $content);
119 $body =
new Stream(
'php://temp',
'rw');
120 $body->write($content);
121 $response = $response->withBody($body);
136 $returnUrl = GeneralUtility::sanitizeLocalUrl($returnUrl);
138 if (
$GLOBALS[
'TYPO3_CONF_VARS'][
'FE'][
'workspacePreviewLogoutTemplate']) {
139 $templateFile = GeneralUtility::getFileAbsFileName(
$GLOBALS[
'TYPO3_CONF_VARS'][
'FE'][
'workspacePreviewLogoutTemplate']);
140 if (@is_file($templateFile)) {
141 $message = file_get_contents($templateFile);
143 $message = $this->
getLanguageService()->
sL(
'LLL:EXT:workspaces/Resources/Private/Language/locallang_mod.xlf:previewLogoutError');
144 $message = htmlspecialchars($message);
145 $message = sprintf($message,
'<strong>',
'</strong><br>', $templateFile);
148 $message = $this->
getLanguageService()->
sL(
'LLL:EXT:workspaces/Resources/Private/Language/locallang_mod.xlf:previewLogoutSuccess');
149 $message = htmlspecialchars($message);
150 $message = sprintf($message,
'<a href="' . htmlspecialchars($returnUrl) .
'">',
'</a>');
152 return sprintf($message, htmlspecialchars($returnUrl));
174 if (!is_array($previewData)) {
178 if ($request->getMethod() ===
'POST') {
179 throw new \Exception(
'POST requests are incompatible with keyword preview.', 1294585191);
182 $previewConfig = json_decode($previewData[
'config'],
true);
183 if (!$previewConfig[
'fullWorkspace']) {
184 throw new \Exception(
'Preview configuration did not include a workspace preview', 1294585190);
187 if ($request->getQueryParams()[$this->previewKey] ??
false) {
188 $this->
setCookie($inputCode, $request->getAttribute(
'normalizedParams'));
190 return $previewConfig;
202 if ($workspaceUid > 0) {
203 $previewUser = GeneralUtility::makeInstance(PreviewUserAuthentication::class);
204 $previewUser->setWebmounts([$requestedPageId]);
205 if ($previewUser->setTemporaryWorkspace($workspaceUid)) {
220 $cookieSameSite = $this->sanitizeSameSiteCookieValue(
221 strtolower(
$GLOBALS[
'TYPO3_CONF_VARS'][
'BE'][
'cookieSameSite'] ?? Cookie::SAMESITE_STRICT)
224 $cookieSecure = $cookieSameSite === Cookie::SAMESITE_NONE || $normalizedParams->
isHttps();
226 $cookie =
new Cookie(
237 header(
'Set-Cookie: ' . $cookie->__toString(),
false);
260 $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
261 ->getQueryBuilderForTable(
'sys_preview');
264 ->from(
'sys_preview')
266 $queryBuilder->expr()->eq(
268 $queryBuilder->createNamedParameter($keyword)
270 $queryBuilder->expr()->gt(
272 $queryBuilder->createNamedParameter(
$GLOBALS[
'EXEC_TIME'], \PDO::PARAM_INT)
302 if (!isset($tsfe->config[
'config'][
'disablePreviewNotification']) || (
int)$tsfe->config[
'config'][
'disablePreviewNotification'] !== 1) {
306 $currentWorkspaceTitle = htmlspecialchars($currentWorkspaceTitle);
307 if ($tsfe->config[
'config'][
'message_preview_workspace']) {
309 $tsfe->config[
'config'][
'message_preview_workspace'],
310 $currentWorkspaceTitle,
311 $currentWorkspaceId ?? -99
314 $text = $this->
getLanguageService()->
sL(
'LLL:EXT:workspaces/Resources/Private/Language/locallang_mod.xlf:previewText');
315 $text = htmlspecialchars($text);
316 $text = sprintf($text, $currentWorkspaceTitle, $currentWorkspaceId ?? -99);
317 $stopPreviewText = $this->
getLanguageService()->
sL(
'LLL:EXT:workspaces/Resources/Private/Language/locallang_mod.xlf:stopPreview');
318 $stopPreviewText = htmlspecialchars($stopPreviewText);
321 $urlForStoppingPreview = $normalizedParams->
getSiteUrl() .
'index.php?returnUrl=' . rawurlencode($url) .
'&ADMCMD_prev=LOGOUT';
322 $text .=
'<br><a style="color: #000; pointer-events: visible;" href="' . htmlspecialchars($urlForStoppingPreview) .
'">' . $stopPreviewText .
'</a>';
325 $styles[] =
'position: fixed';
326 $styles[] =
'top: 15px';
327 $styles[] =
'right: 15px';
328 $styles[] =
'padding: 8px 18px';
329 $styles[] =
'background: #fff3cd';
330 $styles[] =
'border: 1px solid #ffeeba';
331 $styles[] =
'font-family: sans-serif';
332 $styles[] =
'font-size: 14px';
333 $styles[] =
'font-weight: bold';
334 $styles[] =
'color: #856404';
335 $styles[] =
'z-index: 20000';
336 $styles[] =
'user-select: none';
337 $styles[] =
'pointer-events: none';
338 $styles[] =
'text-align: center';
339 $styles[] =
'border-radius: 2px';
340 $content =
'<div id="typo3-preview-info" style="' . implode(
';', $styles) .
'">' . $text .
'</div>';
354 $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
355 ->getQueryBuilderForTable(
'sys_workspace');
356 $title = $queryBuilder
358 ->from(
'sys_workspace')
360 $queryBuilder->expr()->eq(
362 $queryBuilder->createNamedParameter($workspaceId, \PDO::PARAM_INT)
367 return (
string)($title !==
false ? $title :
'');
378 return (
string)preg_replace(
'/\\&?' . $this->previewKey .
'=[[:alnum:]]+/',
'', $url);
386 return $GLOBALS[
'LANG'] ?: GeneralUtility::makeInstance(LanguageService::class);
397 $context->
setAspect(
'backend.user', GeneralUtility::makeInstance(UserAspect::class, $user));
398 $context->
setAspect(
'workspace', GeneralUtility::makeInstance(WorkspaceAspect::class, $user ? $user->workspace : 0));