[!!!][TASK] Use request type constants everywhere
[Packages/TYPO3.CMS.git] / typo3 / sysext / core / Classes / FormProtection / FormProtectionFactory.php
1 <?php
2 namespace TYPO3\CMS\Core\FormProtection;
3
4 /*
5 * This file is part of the TYPO3 CMS project.
6 *
7 * It is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU General Public License, either version 2
9 * of the License, or any later version.
10 *
11 * For the full copyright and license information, please read the
12 * LICENSE.txt file that was distributed with this source code.
13 *
14 * The TYPO3 project - inspiring people to share!
15 */
16
17 use TYPO3\CMS\Core\Messaging\FlashMessageQueue;
18 use TYPO3\CMS\Core\Messaging\FlashMessageService;
19 use TYPO3\CMS\Core\Registry;
20 use TYPO3\CMS\Core\Utility\GeneralUtility;
21 use TYPO3\CMS\Lang\LanguageService;
22
23 /**
24 * This class creates and manages instances of the various form protection
25 * classes.
26 *
27 * This class provides only static methods. It can not be instantiated.
28 *
29 * Usage for the back-end form protection:
30 *
31 * <pre>
32 * $formProtection = \TYPO3\CMS\Core\FormProtection\FormProtectionFactory::get();
33 * </pre>
34 *
35 * Usage for the install tool form protection:
36 *
37 * <pre>
38 * $formProtection = \TYPO3\CMS\Core\FormProtection\FormProtectionFactory::get();
39 * </pre>
40 */
41 class FormProtectionFactory
42 {
43 /**
44 * created instances of form protections using the type as array key
45 *
46 * @var array<AbstracFormtProtection>
47 */
48 protected static $instances = array();
49
50 /**
51 * Private constructor to prevent instantiation.
52 */
53 private function __construct()
54 {
55 }
56
57 /**
58 * Gets a form protection instance for the requested class $className.
59 *
60 * If there already is an existing instance of the requested $className, the
61 * existing instance will be returned. If no $className is provided, the factory
62 * detects the scope and returns the appropriate form protection object.
63 *
64 * @param string $className
65 * @return \TYPO3\CMS\Core\FormProtection\AbstractFormProtection the requested instance
66 */
67 public static function get($className = 'default')
68 {
69 if (isset(self::$instances[$className])) {
70 return self::$instances[$className];
71 }
72 if ($className === 'default') {
73 $classNameAndConstructorArguments = self::getClassNameAndConstructorArgumentsByState();
74 } else {
75 $classNameAndConstructorArguments = func_get_args();
76 }
77 self::$instances[$className] = self::createInstance($classNameAndConstructorArguments);
78 return self::$instances[$className];
79 }
80
81 /**
82 * Returns the class name depending on TYPO3_MODE and
83 * active backend session.
84 *
85 * @return array
86 */
87 protected static function getClassNameAndConstructorArgumentsByState()
88 {
89 switch (true) {
90 case self::isInstallToolSession():
91 $classNameAndConstructorArguments = [
92 InstallToolFormProtection::class
93 ];
94 break;
95 case self::isFrontendSession():
96 $classNameAndConstructorArguments = [
97 FrontendFormProtection::class,
98 $GLOBALS['TSFE']->fe_user
99 ];
100 break;
101 case self::isBackendSession():
102 $classNameAndConstructorArguments = [
103 BackendFormProtection::class,
104 $GLOBALS['BE_USER'],
105 GeneralUtility::makeInstance(Registry::class),
106 self::getMessageClosure(
107 $GLOBALS['LANG'],
108 GeneralUtility::makeInstance(FlashMessageService::class)->getMessageQueueByIdentifier(),
109 (bool)(TYPO3_REQUESTTYPE & TYPO3_REQUESTTYPE_AJAX)
110 )
111 ];
112 break;
113 default:
114 $classNameAndConstructorArguments = [
115 DisabledFormProtection::class
116 ];
117 }
118 return $classNameAndConstructorArguments;
119 }
120
121 /**
122 * Check if we are in the install tool
123 *
124 * @return bool
125 */
126 protected static function isInstallToolSession()
127 {
128 return (TYPO3_REQUESTTYPE & TYPO3_REQUESTTYPE_INSTALL);
129 }
130
131 /**
132 * Checks if a user is logged in and the session is active.
133 *
134 * @return bool
135 */
136 protected static function isBackendSession()
137 {
138 return isset($GLOBALS['BE_USER']) && $GLOBALS['BE_USER'] instanceof \TYPO3\CMS\Core\Authentication\BackendUserAuthentication && isset($GLOBALS['BE_USER']->user['uid']);
139 }
140
141 /**
142 * Checks if a frontend user is logged in and the session is active.
143 *
144 * @return bool
145 */
146 protected static function isFrontendSession()
147 {
148 return TYPO3_MODE === 'FE' && is_object($GLOBALS['TSFE']) && $GLOBALS['TSFE']->fe_user instanceof \TYPO3\CMS\Frontend\Authentication\FrontendUserAuthentication && isset($GLOBALS['TSFE']->fe_user->user['uid']);
149 }
150
151 /**
152 * @param LanguageService $languageService
153 * @param FlashMessageQueue $messageQueue
154 * @param bool $isAjaxCall
155 * @internal Only public to be used in tests
156 * @return \Closure
157 */
158 public static function getMessageClosure(LanguageService $languageService, FlashMessageQueue $messageQueue, $isAjaxCall)
159 {
160 return function () use ($languageService, $messageQueue, $isAjaxCall) {
161 /** @var \TYPO3\CMS\Core\Messaging\FlashMessage $flashMessage */
162 $flashMessage = GeneralUtility::makeInstance(
163 \TYPO3\CMS\Core\Messaging\FlashMessage::class,
164 $languageService->sL('LLL:EXT:lang/locallang_core.xlf:error.formProtection.tokenInvalid'),
165 '',
166 \TYPO3\CMS\Core\Messaging\FlashMessage::ERROR,
167 !$isAjaxCall
168 );
169 $messageQueue->enqueue($flashMessage);
170 };
171 }
172
173 /**
174 * Creates an instance for the requested class $className
175 * and stores it internally.
176 *
177 * @param array $classNameAndConstructorArguments
178 * @throws \InvalidArgumentException
179 * @return AbstractFormProtection
180 */
181 protected static function createInstance(array $classNameAndConstructorArguments)
182 {
183 $className = $classNameAndConstructorArguments[0];
184 if (!class_exists($className)) {
185 throw new \InvalidArgumentException('$className must be the name of an existing class, but ' . 'actually was "' . $className . '".', 1285352962);
186 }
187 $instance = call_user_func_array([\TYPO3\CMS\Core\Utility\GeneralUtility::class, 'makeInstance'], $classNameAndConstructorArguments);
188 if (!$instance instanceof AbstractFormProtection) {
189 throw new \InvalidArgumentException('$className must be a subclass of ' . AbstractFormProtection::class . ', but actually was "' . $className . '".', 1285353026);
190 }
191 return $instance;
192 }
193
194 /**
195 * Sets the instance that will be returned by get() for a specific class
196 * name.
197 *
198 * Note: This function is intended for testing purposes only.
199 *
200 * @access private
201 * @param string $className
202 * @param AbstractFormProtection $instance
203 * @return void
204 */
205 public static function set($className, AbstractFormProtection $instance)
206 {
207 self::$instances[$className] = $instance;
208 }
209
210 /**
211 * Purges all existing instances.
212 *
213 * This function is particularly useful when cleaning up in unit testing.
214 *
215 * @return void
216 */
217 public static function purgeInstances()
218 {
219 foreach (self::$instances as $key => $instance) {
220 unset(self::$instances[$key]);
221 }
222 }
223 }