[TASK] Send uid of sys_redirect in Response Header
[Packages/TYPO3.CMS.git] / typo3 / sysext / redirects / Classes / Http / Middleware / RedirectHandler.php
1 <?php
2 declare(strict_types = 1);
3 namespace TYPO3\CMS\Redirects\Http\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\Message\UriInterface;
21 use Psr\Http\Server\MiddlewareInterface;
22 use Psr\Http\Server\RequestHandlerInterface;
23 use Psr\Log\LoggerAwareInterface;
24 use Psr\Log\LoggerAwareTrait;
25 use TYPO3\CMS\Core\Configuration\Features;
26 use TYPO3\CMS\Core\Database\ConnectionPool;
27 use TYPO3\CMS\Core\Http\RedirectResponse;
28 use TYPO3\CMS\Core\Utility\GeneralUtility;
29 use TYPO3\CMS\Redirects\Service\RedirectService;
30
31 /**
32 * Hooks into the frontend request, and checks if a redirect should apply,
33 * If so, a redirect response is triggered.
34 *
35 * @internal
36 */
37 class RedirectHandler implements MiddlewareInterface, LoggerAwareInterface
38 {
39 use LoggerAwareTrait;
40
41 /**
42 * First hook within the Frontend Request handling
43 *
44 * @param ServerRequestInterface $request
45 * @param RequestHandlerInterface $handler
46 * @return ResponseInterface
47 */
48 public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
49 {
50 $redirectService = GeneralUtility::makeInstance(RedirectService::class);
51 $port = $request->getUri()->getPort();
52 $matchedRedirect = $redirectService->matchRedirect(
53 $request->getUri()->getHost() . ($port ? ':' . $port : ''),
54 $request->getUri()->getPath()
55 );
56
57 // If the matched redirect is found, resolve it, and check further
58 if (is_array($matchedRedirect)) {
59 $url = $redirectService->getTargetUrl($matchedRedirect, $request->getQueryParams());
60 if ($url instanceof UriInterface) {
61 $this->logger->debug('Redirecting', ['record' => $matchedRedirect, 'uri' => $url]);
62 $response = $this->buildRedirectResponse($url, $matchedRedirect);
63 $this->incrementHitCount($matchedRedirect);
64
65 return $response;
66 }
67 }
68
69 return $handler->handle($request);
70 }
71
72 /**
73 * Creates a PSR-7 compatible Response object
74 *
75 * @param UriInterface $uri
76 * @param array $redirectRecord
77 * @return ResponseInterface
78 */
79 protected function buildRedirectResponse(UriInterface $uri, array $redirectRecord): ResponseInterface
80 {
81 return new RedirectResponse(
82 $uri,
83 (int)$redirectRecord['target_statuscode'],
84 ['X-Redirect-By' => 'TYPO3 Redirect ' . $redirectRecord['uid']]
85 );
86 }
87
88 /**
89 * Updates the sys_record's hit counter by one
90 *
91 * @param array $redirectRecord
92 */
93 protected function incrementHitCount(array $redirectRecord)
94 {
95 // Track the hit if not disabled
96 if (!GeneralUtility::makeInstance(Features::class)->isFeatureEnabled('redirects.hitCount') || $redirectRecord['disable_hitcount']) {
97 return;
98 }
99 $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
100 ->getQueryBuilderForTable('sys_redirect');
101 $queryBuilder
102 ->update('sys_redirect')
103 ->where(
104 $queryBuilder->expr()->eq('uid', $queryBuilder->createNamedParameter($redirectRecord['uid'], \PDO::PARAM_INT))
105 )
106 ->set('hitcount', $queryBuilder->quoteIdentifier('hitcount') . '+1', false)
107 ->set('lasthiton', $GLOBALS['EXEC_TIME'])
108 ->execute();
109 }
110 }