[TASK] Replace TYPO3_OS constant with Environment check
[Packages/TYPO3.CMS.git] / typo3 / sysext / install / Classes / SystemEnvironment / SetupCheck.php
1 <?php
2 namespace TYPO3\CMS\Install\SystemEnvironment;
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\Core\Environment;
18 use TYPO3\CMS\Core\Messaging\FlashMessage;
19 use TYPO3\CMS\Core\Messaging\FlashMessageQueue;
20 use TYPO3\CMS\Core\Service\OpcodeCacheService;
21 use TYPO3\CMS\Core\Utility\GeneralUtility;
22
23 /**
24 * Check TYPO3 setup status
25 *
26 * This class is a hardcoded requirement check for the TYPO3 setup.
27 *
28 * The status messages and title *must not* include HTML, use plain
29 * text only. The return values of this class are not bound to HTML
30 * and can be used in different scopes (eg. as json array).
31 */
32 class SetupCheck implements CheckInterface
33 {
34 /**
35 * @var FlashMessageQueue
36 */
37 protected $messageQueue;
38
39 /**
40 * Get all status information as array with status objects
41 *
42 * @return FlashMessageQueue
43 */
44 public function getStatus(): FlashMessageQueue
45 {
46 $this->messageQueue = new FlashMessageQueue('install');
47
48 $this->checkTrustedHostPattern();
49 $this->checkDownloadsPossible();
50 $this->checkSystemLocale();
51 $this->checkLocaleWithUTF8filesystem();
52 $this->checkSomePhpOpcodeCacheIsLoaded();
53 $this->isTrueTypeFontWorking();
54 $this->checkLibXmlBug();
55
56 return $this->messageQueue;
57 }
58
59 /**
60 * Checks the status of the trusted hosts pattern check
61 */
62 protected function checkTrustedHostPattern()
63 {
64 if ($GLOBALS['TYPO3_CONF_VARS']['SYS']['trustedHostsPattern'] === GeneralUtility::ENV_TRUSTED_HOSTS_PATTERN_ALLOW_ALL) {
65 $this->messageQueue->enqueue(new FlashMessage(
66 'Trusted hosts pattern is configured to allow all header values. Check the pattern defined in Install'
67 . ' Tool -> All configuration -> System -> trustedHostsPattern and adapt it to expected host value(s).',
68 'Trusted hosts pattern is insecure',
69 FlashMessage::WARNING
70 ));
71 } else {
72 if (GeneralUtility::hostHeaderValueMatchesTrustedHostsPattern($_SERVER['HTTP_HOST'])) {
73 $this->messageQueue->enqueue(new FlashMessage(
74 '',
75 'Trusted hosts pattern is configured to allow current host value.'
76 ));
77 } else {
78 $defaultPort = GeneralUtility::getIndpEnv('TYPO3_SSL') ? '443' : '80';
79 $this->messageQueue->enqueue(new FlashMessage(
80 'The trusted hosts pattern will be configured to allow all header values. This is because your $SERVER_NAME:[defaultPort]'
81 . ' is "' . $_SERVER['SERVER_NAME'] . ':' . $defaultPort . '" while your HTTP_HOST:SERVER_PORT is "'
82 . $_SERVER['HTTP_HOST'] . ':' . $_SERVER['SERVER_PORT'] . '". Check the pattern defined in Install Tool -> All'
83 . ' configuration -> System -> trustedHostsPattern and adapt it to expected host value(s).',
84 'Trusted hosts pattern mismatch',
85 FlashMessage::ERROR
86 ));
87 }
88 }
89 }
90
91 /**
92 * Check if it is possible to download external data (e.g. TER)
93 * Either allow_url_fopen must be enabled or curl must be used
94 */
95 protected function checkDownloadsPossible()
96 {
97 $allowUrlFopen = (bool)ini_get('allow_url_fopen');
98 $curlEnabled = function_exists('curl_version');
99 if ($allowUrlFopen || $curlEnabled) {
100 $this->messageQueue->enqueue(new FlashMessage(
101 '',
102 'Fetching external URLs is allowed'
103 ));
104 } else {
105 $this->messageQueue->enqueue(new FlashMessage(
106 'Either enable PHP runtime setting "allow_url_fopen"' . LF . 'or compile curl into your PHP with --with-curl.',
107 'Fetching external URLs is not allowed',
108 FlashMessage::WARNING
109 ));
110 }
111 }
112
113 /**
114 * Check if systemLocale setting is correct (locale exists in the OS)
115 */
116 protected function checkSystemLocale()
117 {
118 $currentLocale = setlocale(LC_CTYPE, 0);
119
120 // On Windows an empty locale value uses the regional settings from the Control Panel
121 if ($GLOBALS['TYPO3_CONF_VARS']['SYS']['systemLocale'] === '' && !Environment::isWindows()) {
122 $this->messageQueue->enqueue(new FlashMessage(
123 '$GLOBALS[TYPO3_CONF_VARS][SYS][systemLocale] is not set. This is fine as long as no UTF-8 file system is used.',
124 'Empty systemLocale setting',
125 FlashMessage::INFO
126 ));
127 } elseif (setlocale(LC_CTYPE, $GLOBALS['TYPO3_CONF_VARS']['SYS']['systemLocale']) === false) {
128 $this->messageQueue->enqueue(new FlashMessage(
129 'Current value of the $GLOBALS[TYPO3_CONF_VARS][SYS][systemLocale] is incorrect. A locale with'
130 . ' this name doesn\'t exist in the operating system.',
131 'Incorrect systemLocale setting',
132 FlashMessage::ERROR
133 ));
134 setlocale(LC_CTYPE, $currentLocale);
135 } else {
136 $this->messageQueue->enqueue(new FlashMessage(
137 '',
138 'System locale is correct'
139 ));
140 }
141 }
142
143 /**
144 * Checks whether we can use file names with UTF-8 characters.
145 * Configured system locale must support UTF-8 when UTF8filesystem is set
146 */
147 protected function checkLocaleWithUTF8filesystem()
148 {
149 if ($GLOBALS['TYPO3_CONF_VARS']['SYS']['UTF8filesystem']) {
150 // On Windows an empty local value uses the regional settings from the Control Panel
151 if ($GLOBALS['TYPO3_CONF_VARS']['SYS']['systemLocale'] === '' && !Environment::isWindows()) {
152 $this->messageQueue->enqueue(new FlashMessage(
153 '$GLOBALS[TYPO3_CONF_VARS][SYS][UTF8filesystem] is set, but $GLOBALS[TYPO3_CONF_VARS][SYS][systemLocale]'
154 . ' is empty. Make sure a valid locale which supports UTF-8 is set.',
155 'System locale not set on UTF-8 file system',
156 FlashMessage::ERROR
157 ));
158 } else {
159 $testString = 'ÖöĄĆŻĘĆćążąęó.jpg';
160 $currentLocale = setlocale(LC_CTYPE, 0);
161 $quote = Environment::isWindows() ? '"' : '\'';
162 setlocale(LC_CTYPE, $GLOBALS['TYPO3_CONF_VARS']['SYS']['systemLocale']);
163 if (escapeshellarg($testString) === $quote . $testString . $quote) {
164 $this->messageQueue->enqueue(new FlashMessage(
165 '',
166 'File names with UTF-8 characters can be used.'
167 ));
168 } else {
169 $this->messageQueue->enqueue(new FlashMessage(
170 'Please check your $GLOBALS[TYPO3_CONF_VARS][SYS][systemLocale] setting.',
171 'System locale setting doesn\'t support UTF-8 file names.',
172 FlashMessage::ERROR
173 ));
174 }
175 setlocale(LC_CTYPE, $currentLocale);
176 }
177 } else {
178 $this->messageQueue->enqueue(new FlashMessage(
179 '',
180 'Skipping test, as UTF8filesystem is not enabled.'
181 ));
182 }
183 }
184
185 /**
186 * Check if some opcode cache is loaded
187 */
188 protected function checkSomePhpOpcodeCacheIsLoaded()
189 {
190 // Link to our wiki page, so we can update opcode cache issue information independent of TYPO3 CMS releases.
191 $wikiLink = 'For more information take a look in our wiki ' . TYPO3_URL_WIKI_OPCODECACHE . '.';
192 $opcodeCaches = GeneralUtility::makeInstance(OpcodeCacheService::class)->getAllActive();
193 if (empty($opcodeCaches)) {
194 // Set status to notice. It needs to be notice so email won't be triggered.
195 $this->messageQueue->enqueue(new FlashMessage(
196 'PHP opcode caches hold a compiled version of executed PHP scripts in'
197 . ' memory and do not require to recompile a script each time it is accessed.'
198 . ' This can be a massive performance improvement and can reduce the load on a'
199 . ' server in general. A parse time reduction by factor three for fully cached'
200 . ' pages can be achieved easily if using an opcode cache.'
201 . LF . $wikiLink,
202 'No PHP opcode cache loaded',
203 FlashMessage::NOTICE
204 ));
205 } else {
206 $status = FlashMessage::OK;
207 $message = '';
208 foreach ($opcodeCaches as $opcodeCache => $properties) {
209 $message .= 'Name: ' . $opcodeCache . ' Version: ' . $properties['version'];
210 $message .= LF;
211 if ($properties['error']) {
212 $status = FlashMessage::ERROR;
213 $message .= ' This opcode cache is marked as malfunctioning by the TYPO3 CMS Team.';
214 } elseif ($properties['canInvalidate']) {
215 $message .= ' This opcode cache should work correctly and has good performance.';
216 } else {
217 // Set status to notice if not already error set. It needs to be notice so email won't be triggered.
218 if ($status !== FlashMessage::ERROR) {
219 $status = FlashMessage::NOTICE;
220 }
221 $message .= ' This opcode cache may work correctly but has medium performance.';
222 }
223 $message .= LF;
224 }
225 $message .= $wikiLink;
226 // Set title of status depending on serverity
227 switch ($status) {
228 case FlashMessage::ERROR:
229 $title = 'A possibly malfunctioning PHP opcode cache is loaded';
230 break;
231 case FlashMessage::OK:
232 default:
233 $title = 'A PHP opcode cache is loaded';
234 break;
235 }
236 $this->messageQueue->enqueue(new FlashMessage(
237 $message,
238 $title,
239 $status
240 ));
241 }
242 }
243
244 /**
245 * Create true type font test image
246 */
247 protected function isTrueTypeFontWorking()
248 {
249 if (function_exists('imageftbbox')) {
250 // 20 Pixels at 96 DPI
251 $fontSize = (20 / 96 * 72);
252 $textDimensions = @imageftbbox(
253 $fontSize,
254 0,
255 __DIR__ . '/../../Resources/Private/Font/vera.ttf',
256 'Testing true type support'
257 );
258 $fontBoxWidth = $textDimensions[2] - $textDimensions[0];
259 if ($fontBoxWidth < 300 && $fontBoxWidth > 200) {
260 $this->messageQueue->enqueue(new FlashMessage(
261 'Fonts are rendered by FreeType library. '
262 . 'We need to ensure that the final dimensions are as expected. '
263 . 'This server renderes fonts based on 96 DPI correctly',
264 'FreeType True Type Font DPI'
265 ));
266 } else {
267 $this->messageQueue->enqueue(new FlashMessage(
268 'Fonts are rendered by FreeType library. '
269 . 'This server does not render fonts as expected. '
270 . 'Please check your FreeType 2 module.',
271 'FreeType True Type Font DPI',
272 FlashMessage::NOTICE
273 ));
274 }
275 } else {
276 $this->messageQueue->enqueue(new FlashMessage(
277 'The core relies on GD library compiled into PHP with freetype2'
278 . ' support. This is missing on your system. Please install it.',
279 'PHP GD library freetype2 support missing',
280 FlashMessage::ERROR
281 ));
282 }
283 }
284
285 /**
286 * Check for bug in libxml
287 */
288 protected function checkLibXmlBug()
289 {
290 $sampleArray = ['Test>><<Data'];
291 $xmlContent = '<numIndex index="0">Test&gt;&gt;&lt;&lt;Data</numIndex>' . LF;
292 $xml = GeneralUtility::array2xml($sampleArray, '', -1);
293 if ($xmlContent !== $xml) {
294 $this->messageQueue->enqueue(new FlashMessage(
295 'Some hosts have problems saving ">><<" in a flexform.'
296 . ' To fix this, enable [BE][flexformForceCDATA] in'
297 . ' All Configuration.',
298 'PHP libxml bug present',
299 FlashMessage::ERROR
300 ));
301 } else {
302 $this->messageQueue->enqueue(new FlashMessage(
303 '',
304 'PHP libxml bug not present'
305 ));
306 }
307 }
308 }