ErrorController.php 5.93 KB
Newer Older
1
<?php
2
declare(strict_types=1);
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
namespace TYPO3\CMS\Frontend\Controller;

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

use Psr\Http\Message\ResponseInterface;
19
use Psr\Http\Message\ServerRequestInterface;
20
21
22
use TYPO3\CMS\Core\Controller\ErrorPageController;
use TYPO3\CMS\Core\Error\Http\PageNotFoundException;
use TYPO3\CMS\Core\Error\Http\ServiceUnavailableException;
23
use TYPO3\CMS\Core\Error\PageErrorHandler\PageErrorHandlerInterface;
24
use TYPO3\CMS\Core\Error\PageErrorHandler\PageErrorHandlerNotConfiguredException;
25
use TYPO3\CMS\Core\Http\HtmlResponse;
26
use TYPO3\CMS\Core\Http\JsonResponse;
27
use TYPO3\CMS\Core\Site\Entity\Site;
28
29
30
31
32
33
34
35
36
37
38
39
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.
     *
40
     * @param ServerRequestInterface $request
41
42
43
44
45
     * @param string $message
     * @param array $reasons
     * @return ResponseInterface
     * @throws ServiceUnavailableException
     */
46
    public function unavailableAction(ServerRequestInterface $request, string $message, array $reasons = []): ResponseInterface
47
48
49
50
    {
        if (!$this->isPageUnavailableHandlerConfigured()) {
            throw new ServiceUnavailableException($message, 1518472181);
        }
51
52
        $errorHandler = $this->getErrorHandlerFromSite($request, 500);
        if ($errorHandler instanceof PageErrorHandlerInterface) {
53
            return $errorHandler->handlePageError($request, $message, $reasons);
54
        }
55
        return $this->handleDefaultError($request, 500, $message ?: 'Page is unavailable');
56
57
58
59
60
61
    }

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

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

    /**
     * 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
    {
112
        return !GeneralUtility::cmpIP(GeneralUtility::getIndpEnv('REMOTE_ADDR'), $GLOBALS['TYPO3_CONF_VARS']['SYS']['devIPmask']);
113
    }
114
115
116
117
118
119
120
121
122
123
124

    /**
     * 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');
125
126
127
128
129
130
131
132
        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;
133
    }
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153

    /**
     * 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);
    }
154
}