[!!!][TASK] Remove deprecated code related to TSFE
[Packages/TYPO3.CMS.git] / typo3 / sysext / frontend / Classes / Middleware / SiteBaseRedirectResolver.php
1 <?php
2 declare(strict_types = 1);
3 namespace TYPO3\CMS\Frontend\Middleware;
4
5 /*
6 * This file is part of the TYPO3 CMS project.
7 *
8 * It is free software; you can redistribute it and/or modify it under
9 * the terms of the GNU General Public License, either version 2
10 * of the License, or any later version.
11 *
12 * For the full copyright and license information, please read the
13 * LICENSE.txt file that was distributed with this source code.
14 *
15 * The TYPO3 project - inspiring people to share!
16 */
17
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 TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
23 use TYPO3\CMS\Core\Http\RedirectResponse;
24 use TYPO3\CMS\Core\Routing\SiteRouteResult;
25 use TYPO3\CMS\Core\Site\Entity\Site;
26 use TYPO3\CMS\Core\Site\Entity\SiteLanguage;
27 use TYPO3\CMS\Core\Utility\GeneralUtility;
28 use TYPO3\CMS\Frontend\Controller\ErrorController;
29 use TYPO3\CMS\Frontend\Page\PageAccessFailureReasons;
30
31 /**
32 * Resolves redirects of site if base is not /
33 * Can be replaced or extended by extensions if GeoIP-based or user-agent based language redirects need to happen.
34 */
35 class SiteBaseRedirectResolver implements MiddlewareInterface
36 {
37 /**
38 * Redirect to default language if required
39 *
40 * @param ServerRequestInterface $request
41 * @param RequestHandlerInterface $handler
42 * @return ResponseInterface
43 */
44 public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
45 {
46 $site = $request->getAttribute('site', null);
47 $language = $request->getAttribute('language', null);
48 $routeResult = $request->getAttribute('routing', null);
49
50 // Usually called when "https://www.example.com" was entered, but all sites have "https://www.example.com/lang-key/"
51 // So a redirect to the first possible language is done.
52 if ($site instanceof Site && !($language instanceof SiteLanguage)) {
53 $language = $site->getDefaultLanguage();
54 return new RedirectResponse($language->getBase(), 307);
55 }
56
57 // Language is found, and hidden but also not visible to the BE user, this needs to fail
58 if ($language instanceof SiteLanguage && !$this->isLanguageEnabled($language, $GLOBALS['BE_USER'] ?? null)) {
59 return GeneralUtility::makeInstance(ErrorController::class)->pageNotFoundAction(
60 $request,
61 'Page is not available in the requested language.',
62 ['code' => PageAccessFailureReasons::LANGUAGE_NOT_AVAILABLE]
63 );
64 }
65
66 if ($language instanceof SiteLanguage && $routeResult instanceof SiteRouteResult) {
67 $requestedUri = $request->getUri();
68 $tail = $routeResult->getTail();
69 // a URL was called via "/fr-FR/" but the page is actually called "/fr-FR", let's do a redirect
70 if ($tail === '/') {
71 $uri = $requestedUri->withPath(rtrim($requestedUri->getPath(), '/'));
72 return new RedirectResponse($uri, 307);
73 }
74 // Request was "/fr-FR" but the site is actually called "/fr-FR/", let's do a redirect
75 if ($tail === '' && $language->getBase()->getPath() !== $requestedUri->getPath()) {
76 $uri = $requestedUri->withPath($requestedUri->getPath() . '/');
77 return new RedirectResponse($uri, 307);
78 }
79 }
80 return $handler->handle($request);
81 }
82
83 /**
84 * Checks if the language is allowed in Frontend, if not, check if there is valid BE user
85 *
86 * @param SiteLanguage|null $language
87 * @param BackendUserAuthentication|null $user
88 * @return bool
89 */
90 protected function isLanguageEnabled(SiteLanguage $language, BackendUserAuthentication $user = null): bool
91 {
92 // language is hidden, check if a possible backend user is allowed to access the language
93 if ($language->enabled() || ($user instanceof BackendUserAuthentication && $user->checkLanguageAccess($language->getLanguageId()))) {
94 return true;
95 }
96 return false;
97 }
98 }