ErrorController.php 5.94 KB
Newer Older
1
<?php
2

3
declare(strict_types=1);
4
5
6
7
8
9
10
11
12
13
14
15
16
17

/*
 * 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!
 */

18
19
namespace TYPO3\CMS\Frontend\Controller;

20
use Psr\Http\Message\ResponseInterface;
21
use Psr\Http\Message\ServerRequestInterface;
22
23
24
use TYPO3\CMS\Core\Controller\ErrorPageController;
use TYPO3\CMS\Core\Error\Http\PageNotFoundException;
use TYPO3\CMS\Core\Error\Http\ServiceUnavailableException;
25
use TYPO3\CMS\Core\Error\PageErrorHandler\PageErrorHandlerInterface;
26
use TYPO3\CMS\Core\Error\PageErrorHandler\PageErrorHandlerNotConfiguredException;
27
use TYPO3\CMS\Core\Http\HtmlResponse;
28
use TYPO3\CMS\Core\Http\JsonResponse;
29
use TYPO3\CMS\Core\Site\Entity\Site;
30
31
32
33
34
35
36
37
38
39
40
41
use TYPO3\CMS\Core\Utility\GeneralUtility;

/**
 * Handles "Page Not Found" or "Page Unavailable" requests,
 * returns a response object.
 */
class ErrorController
{
    /**
     * Used for creating a 500 response ("Page unavailable"), usually due some misconfiguration
     * but if configured, a RedirectResponse could be returned as well.
     *
42
     * @param ServerRequestInterface $request
43
44
45
46
47
     * @param string $message
     * @param array $reasons
     * @return ResponseInterface
     * @throws ServiceUnavailableException
     */
48
    public function unavailableAction(ServerRequestInterface $request, string $message, array $reasons = []): ResponseInterface
49
50
51
52
    {
        if (!$this->isPageUnavailableHandlerConfigured()) {
            throw new ServiceUnavailableException($message, 1518472181);
        }
53
54
        $errorHandler = $this->getErrorHandlerFromSite($request, 500);
        if ($errorHandler instanceof PageErrorHandlerInterface) {
55
            return $errorHandler->handlePageError($request, $message, $reasons);
56
        }
57
        return $this->handleDefaultError($request, 500, $message ?: 'Page is unavailable');
58
59
60
61
62
63
    }

    /**
     * Used for creating a 404 response ("Page Not Found"),
     * but if configured, a RedirectResponse could be returned as well.
     *
64
     * @param ServerRequestInterface $request
65
66
67
68
69
     * @param string $message
     * @param array $reasons
     * @return ResponseInterface
     * @throws PageNotFoundException
     */
70
    public function pageNotFoundAction(ServerRequestInterface $request, string $message, array $reasons = []): ResponseInterface
71
    {
72
73
        $errorHandler = $this->getErrorHandlerFromSite($request, 404);
        if ($errorHandler instanceof PageErrorHandlerInterface) {
74
            return $errorHandler->handlePageError($request, $message, $reasons);
75
        }
76
77
78
        try {
            return $this->handleDefaultError($request, 404, $message);
        } catch (\RuntimeException $e) {
79
80
81
82
83
84
85
86
            throw new PageNotFoundException($message, 1518472189);
        }
    }

    /**
     * Used for creating a 403 response ("Access denied"),
     * but if configured, a RedirectResponse could be returned as well.
     *
87
     * @param ServerRequestInterface $request
88
89
90
     * @param string $message
     * @param array $reasons
     * @return ResponseInterface
91
     * @throws PageNotFoundException
92
     */
93
    public function accessDeniedAction(ServerRequestInterface $request, string $message, array $reasons = []): ResponseInterface
94
    {
95
96
        $errorHandler = $this->getErrorHandlerFromSite($request, 403);
        if ($errorHandler instanceof PageErrorHandlerInterface) {
97
            return $errorHandler->handlePageError($request, $message, $reasons);
98
        }
99
100
101
102
103
        try {
            return $this->handleDefaultError($request, 403, $message);
        } catch (\RuntimeException $e) {
            throw new PageNotFoundException($message, 1518472195);
        }
104
105
106
107
108
109
110
111
112
113
    }

    /**
     * Checks whether the pageUnavailableHandler should be used. To be used, pageUnavailable_handling must be set
     * and devIPMask must not match the current visitor's IP address.
     *
     * @return bool TRUE/FALSE whether the pageUnavailable_handler should be used.
     */
    protected function isPageUnavailableHandlerConfigured(): bool
    {
114
        return !GeneralUtility::cmpIP(GeneralUtility::getIndpEnv('REMOTE_ADDR'), $GLOBALS['TYPO3_CONF_VARS']['SYS']['devIPmask']);
115
    }
116
117
118
119
120
121
122
123
124
125
126

    /**
     * Checks if a site is configured, and an error handler is configured for this specific status code.
     *
     * @param ServerRequestInterface $request
     * @param int $statusCode
     * @return PageErrorHandlerInterface|null
     */
    protected function getErrorHandlerFromSite(ServerRequestInterface $request, int $statusCode): ?PageErrorHandlerInterface
    {
        $site = $request->getAttribute('site');
127
128
129
130
131
132
133
134
        if ($site instanceof Site) {
            try {
                return $site->getErrorHandler($statusCode);
            } catch (PageErrorHandlerNotConfiguredException $e) {
                // No error handler found, so fallback back to the generic TYPO3 error handler.
            }
        }
        return null;
135
    }
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155

    /**
     * Ensures that a response object is created as a "fallback" when no error handler is configured.
     *
     * @param ServerRequestInterface $request
     * @param int $statusCode
     * @param string $reason
     * @return ResponseInterface
     */
    protected function handleDefaultError(ServerRequestInterface $request, int $statusCode, string $reason = ''): ResponseInterface
    {
        if (strpos($request->getHeaderLine('Accept'), 'application/json') !== false) {
            return new JsonResponse(['reason' => $reason], $statusCode);
        }
        $content = GeneralUtility::makeInstance(ErrorPageController::class)->errorAction(
            'Page Not Found',
            'The page did not exist or was inaccessible.' . ($reason ? ' Reason: ' . $reason : '')
        );
        return new HtmlResponse($content, $statusCode);
    }
156
}