20b632b8df1d9d187dd59c7e6761c2d86129dd12
[Packages/TYPO3.CMS.git] / typo3 / sysext / felogin / Classes / Controller / FrontendLoginController.php
1 <?php
2 namespace TYPO3\CMS\Felogin\Controller;
3
4 /***************************************************************
5 * Copyright notice
6 *
7 * (c) 2007-2013 Steffen Kamper <info@sk-typo3.de>
8 * Based on Newloginbox (c) 2002-2004 Kasper Skårhøj <kasper@typo3.com>
9 *
10 * All rights reserved
11 *
12 * This script is part of the TYPO3 project. The TYPO3 project is
13 * free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or
16 * (at your option) any later version.
17 *
18 * The GNU General Public License can be found at
19 * http://www.gnu.org/copyleft/gpl.html.
20 *
21 * This script is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 * GNU General Public License for more details.
25 *
26 * This copyright notice MUST APPEAR in all copies of the script!
27 *
28 * The code was adapted from newloginbox, see manual for detailed description
29 ***************************************************************/
30
31 /**
32 * Plugin 'Website User Login' for the 'felogin' extension.
33 *
34 * @author Steffen Kamper <info@sk-typo3.de>
35 */
36 class FrontendLoginController extends \TYPO3\CMS\Frontend\Plugin\AbstractPlugin {
37
38 /**
39 * Same as class name
40 *
41 * @todo Define visibility
42 */
43 public $prefixId = 'tx_felogin_pi1';
44
45 /**
46 * Path to this script relative to the extension dir.
47 *
48 * @todo Define visibility
49 */
50 public $scriptRelPath = 'pi1/class.tx_felogin_pi1.php';
51
52 /**
53 * The extension key.
54 *
55 * @todo Define visibility
56 */
57 public $extKey = 'felogin';
58
59 /**
60 * @var boolean
61 */
62 public $pi_checkCHash = FALSE;
63
64 /**
65 * @var boolean
66 */
67 public $pi_USER_INT_obj = TRUE;
68
69 /**
70 * Is user logged in?
71 *
72 * @var boolean
73 */
74 protected $userIsLoggedIn;
75
76 /**
77 * Holds the template for FE rendering
78 *
79 * @var string
80 */
81 protected $template;
82
83 /**
84 * Upload directory, used for flexform template files
85 *
86 * @var string
87 */
88 protected $uploadDir;
89
90 /**
91 * URL for the redirect
92 *
93 * @var string
94 */
95 protected $redirectUrl;
96
97 /**
98 * Flag for disable the redirect
99 *
100 * @var boolean
101 */
102 protected $noRedirect = FALSE;
103
104 /**
105 * Logintype (given as GPvar), possible: login, logout
106 *
107 * @var string
108 */
109 protected $logintype;
110
111 /**
112 * The main method of the plugin
113 *
114 * @param string $content The PlugIn content
115 * @param array $conf The PlugIn configuration
116 * @return string The content that is displayed on the website
117 */
118 public function main($content, $conf) {
119 // Loading TypoScript array into object variable:
120 $this->conf = $conf;
121 $this->uploadDir = 'uploads/tx_felogin/';
122 // Loading default pivars
123 $this->pi_setPiVarDefaults();
124 // Loading language-labels
125 $this->pi_loadLL();
126 // Init FlexForm configuration for plugin:
127 $this->pi_initPIflexForm();
128 $this->mergeflexFormValuesIntoConf();
129 // Get storage PIDs:
130 if ($this->conf['storagePid']) {
131 if (intval($this->conf['recursive'])) {
132 $this->spid = $this->pi_getPidList($this->conf['storagePid'], intval($this->conf['recursive']));
133 } else {
134 $this->spid = $this->conf['storagePid'];
135 }
136 } else {
137 $pids = $GLOBALS['TSFE']->getStorageSiterootPids();
138 $this->spid = $pids['_STORAGE_PID'];
139 }
140 // GPvars:
141 $this->logintype = \TYPO3\CMS\Core\Utility\GeneralUtility::_GP('logintype');
142 $this->referer = $this->validateRedirectUrl(\TYPO3\CMS\Core\Utility\GeneralUtility::_GP('referer'));
143 $this->noRedirect = $this->piVars['noredirect'] || $this->conf['redirectDisable'];
144 // If config.typolinkLinkAccessRestrictedPages is set, the var is return_url
145 $returnUrl = \TYPO3\CMS\Core\Utility\GeneralUtility::_GP('return_url');
146 if ($returnUrl) {
147 $this->redirectUrl = $returnUrl;
148 } else {
149 $this->redirectUrl = \TYPO3\CMS\Core\Utility\GeneralUtility::_GP('redirect_url');
150 }
151 $this->redirectUrl = $this->validateRedirectUrl($this->redirectUrl);
152 // Get Template
153 $templateFile = $this->conf['templateFile'] ? $this->conf['templateFile'] : 'EXT:felogin/template.html';
154 $this->template = $this->cObj->fileResource($templateFile);
155 // Is user logged in?
156 $this->userIsLoggedIn = $GLOBALS['TSFE']->loginUser;
157 // Redirect
158 if ($this->conf['redirectMode'] && !$this->conf['redirectDisable'] && !$this->noRedirect) {
159 $redirectUrl = $this->processRedirect();
160 if (count($redirectUrl)) {
161 $this->redirectUrl = $this->conf['redirectFirstMethod'] ? array_shift($redirectUrl) : array_pop($redirectUrl);
162 } else {
163 $this->redirectUrl = '';
164 }
165 }
166 // What to display
167 $content = '';
168 if ($this->piVars['forgot']) {
169 $content .= $this->showForgot();
170 } elseif ($this->piVars['forgothash']) {
171 $content .= $this->changePassword();
172 } else {
173 if ($this->userIsLoggedIn && !$this->logintype) {
174 $content .= $this->showLogout();
175 } else {
176 $content .= $this->showLogin();
177 }
178 }
179 // Process the redirect
180 if (($this->logintype === 'login' || $this->logintype === 'logout') && $this->redirectUrl && !$this->noRedirect) {
181 if (!$GLOBALS['TSFE']->fe_user->cookieId) {
182 $content .= $this->cObj->stdWrap($this->pi_getLL('cookie_warning', '', 1), $this->conf['cookieWarning_stdWrap.']);
183 } else {
184 // Add hook for extra processing before redirect
185 if (isset($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['felogin']['beforeRedirect']) && is_array($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['felogin']['beforeRedirect'])) {
186 $_params = array(
187 'loginType' => $this->logintype,
188 'redirectUrl' => &$this->redirectUrl
189 );
190 foreach ($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['felogin']['beforeRedirect'] as $_funcRef) {
191 if ($_funcRef) {
192 \TYPO3\CMS\Core\Utility\GeneralUtility::callUserFunction($_funcRef, $_params, $this);
193 }
194 }
195 }
196 \TYPO3\CMS\Core\Utility\HttpUtility::redirect($this->redirectUrl);
197 }
198 }
199 // Adds hook for processing of extra item markers / special
200 if (isset($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['felogin']['postProcContent']) && is_array($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['felogin']['postProcContent'])) {
201 $_params = array(
202 'content' => $content
203 );
204 foreach ($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['felogin']['postProcContent'] as $_funcRef) {
205 $content = \TYPO3\CMS\Core\Utility\GeneralUtility::callUserFunction($_funcRef, $_params, $this);
206 }
207 }
208 return $this->conf['wrapContentInBaseClass'] ? $this->pi_wrapInBaseClass($content) : $content;
209 }
210
211 /**
212 * Shows the forgot password form
213 *
214 * @return string Content
215 */
216 protected function showForgot() {
217 $subpart = $this->cObj->getSubpart($this->template, '###TEMPLATE_FORGOT###');
218 $subpartArray = ($linkpartArray = array());
219 $postData = \TYPO3\CMS\Core\Utility\GeneralUtility::_POST($this->prefixId);
220 if ($postData['forgot_email']) {
221 // Get hashes for compare
222 $postedHash = $postData['forgot_hash'];
223 $hashData = $GLOBALS['TSFE']->fe_user->getKey('ses', 'forgot_hash');
224 if ($postedHash === $hashData['forgot_hash']) {
225 $row = FALSE;
226 // Look for user record
227 $data = $GLOBALS['TYPO3_DB']->fullQuoteStr($this->piVars['forgot_email'], 'fe_users');
228 $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
229 'uid, username, password, email',
230 'fe_users',
231 '(email=' . $data . ' OR username=' . $data . ') AND pid IN (' . $GLOBALS['TYPO3_DB']->cleanIntList($this->spid) . ') ' . $this->cObj->enableFields('fe_users')
232 );
233 if ($GLOBALS['TYPO3_DB']->sql_num_rows($res)) {
234 $row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res);
235 }
236 $error = NULL;
237 if ($row) {
238 // Generate an email with the hashed link
239 $error = $this->generateAndSendHash($row);
240 } elseif ($this->conf['exposeNonexistentUserInForgotPasswordDialog']) {
241 $error = $this->pi_getLL('ll_forgot_reset_message_error');
242 }
243 // Generate message
244 if ($error) {
245 $markerArray['###STATUS_MESSAGE###'] = $this->cObj->stdWrap($error, $this->conf['forgotErrorMessage_stdWrap.']);
246 } else {
247 $markerArray['###STATUS_MESSAGE###'] = $this->cObj->stdWrap(
248 $this->pi_getLL('ll_forgot_reset_message_emailSent', '', 1),
249 $this->conf['forgotResetMessageEmailSentMessage_stdWrap.']
250 );
251 }
252 $subpartArray['###FORGOT_FORM###'] = '';
253 } else {
254 // Wrong email
255 $markerArray['###STATUS_MESSAGE###'] = $this->getDisplayText('forgot_reset_message', $this->conf['forgotMessage_stdWrap.']);
256 $markerArray['###BACKLINK_LOGIN###'] = '';
257 }
258 } else {
259 $markerArray['###STATUS_MESSAGE###'] = $this->getDisplayText('forgot_reset_message', $this->conf['forgotMessage_stdWrap.']);
260 $markerArray['###BACKLINK_LOGIN###'] = '';
261 }
262 $markerArray['###BACKLINK_LOGIN###'] = $this->getPageLink($this->pi_getLL('ll_forgot_header_backToLogin', '', 1), array());
263 $markerArray['###STATUS_HEADER###'] = $this->getDisplayText('forgot_header', $this->conf['forgotHeader_stdWrap.']);
264 $markerArray['###LEGEND###'] = $this->pi_getLL('legend', $this->pi_getLL('reset_password', '', 1), 1);
265 $markerArray['###ACTION_URI###'] = $this->getPageLink('', array($this->prefixId . '[forgot]' => 1), TRUE);
266 $markerArray['###EMAIL_LABEL###'] = $this->pi_getLL('your_email', '', 1);
267 $markerArray['###FORGOT_PASSWORD_ENTEREMAIL###'] = $this->pi_getLL('forgot_password_enterEmail', '', 1);
268 $markerArray['###FORGOT_EMAIL###'] = $this->prefixId . '[forgot_email]';
269 $markerArray['###SEND_PASSWORD###'] = $this->pi_getLL('reset_password', '', 1);
270 $markerArray['###DATA_LABEL###'] = $this->pi_getLL('ll_enter_your_data', '', 1);
271 $markerArray = array_merge($markerArray, $this->getUserFieldMarkers());
272 // Generate hash
273 $hash = md5($this->generatePassword(3));
274 $markerArray['###FORGOTHASH###'] = $hash;
275 // Set hash in feuser session
276 $GLOBALS['TSFE']->fe_user->setKey('ses', 'forgot_hash', array('forgot_hash' => $hash));
277 return $this->cObj->substituteMarkerArrayCached($subpart, $markerArray, $subpartArray, $linkpartArray);
278 }
279
280 /**
281 * This function checks the hash from link and checks the validity. If it's valid it shows the form for
282 * changing the password and process the change of password after submit, if not valid it returns the error message
283 *
284 * @return string The content.
285 */
286 protected function changePassword() {
287 $subpartArray = ($linkpartArray = array());
288 $done = FALSE;
289 $minLength = intval($this->conf['newPasswordMinLength']) ? intval($this->conf['newPasswordMinLength']) : 6;
290 $subpart = $this->cObj->getSubpart($this->template, '###TEMPLATE_CHANGEPASSWORD###');
291 $markerArray['###STATUS_HEADER###'] = $this->getDisplayText('change_password_header', $this->conf['changePasswordHeader_stdWrap.']);
292 $markerArray['###STATUS_MESSAGE###'] = sprintf($this->getDisplayText('change_password_message', $this->conf['changePasswordMessage_stdWrap.']), $minLength);
293 $markerArray['###BACKLINK_LOGIN###'] = '';
294 $uid = $this->piVars['user'];
295 $piHash = $this->piVars['forgothash'];
296 $hash = explode('|', $piHash);
297 if (intval($uid) == 0) {
298 $markerArray['###STATUS_MESSAGE###'] = $this->getDisplayText('change_password_notvalid_message', $this->conf['changePasswordNotValidMessage_stdWrap.']);
299 $subpartArray['###CHANGEPASSWORD_FORM###'] = '';
300 } else {
301 $user = $this->pi_getRecord('fe_users', intval($uid));
302 $userHash = $user['felogin_forgotHash'];
303 $compareHash = explode('|', $userHash);
304 if (!$compareHash || !$compareHash[1] || $compareHash[0] < time() || $hash[0] != $compareHash[0] || md5($hash[1]) != $compareHash[1]) {
305 $markerArray['###STATUS_MESSAGE###'] = $this->getDisplayText('change_password_notvalid_message', $this->conf['changePasswordNotValidMessage_stdWrap.']);
306 $subpartArray['###CHANGEPASSWORD_FORM###'] = '';
307 } else {
308 // All is fine, continue with new password
309 $postData = \TYPO3\CMS\Core\Utility\GeneralUtility::_POST($this->prefixId);
310 if (isset($postData['changepasswordsubmit'])) {
311 if (strlen($postData['password1']) < $minLength) {
312 $markerArray['###STATUS_MESSAGE###'] = sprintf($this->getDisplayText(
313 'change_password_tooshort_message',
314 $this->conf['changePasswordTooShortMessage_stdWrap.']),
315 $minLength
316 );
317 } elseif ($postData['password1'] != $postData['password2']) {
318 $markerArray['###STATUS_MESSAGE###'] = sprintf($this->getDisplayText(
319 'change_password_notequal_message',
320 $this->conf['changePasswordNotEqualMessage_stdWrap.']),
321 $minLength
322 );
323 } else {
324 $newPass = $postData['password1'];
325 if ($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['felogin']['password_changed']) {
326 $_params = array(
327 'user' => $user,
328 'newPassword' => $newPass
329 );
330 foreach ($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['felogin']['password_changed'] as $_funcRef) {
331 if ($_funcRef) {
332 \TYPO3\CMS\Core\Utility\GeneralUtility::callUserFunction($_funcRef, $_params, $this);
333 }
334 }
335 $newPass = $_params['newPassword'];
336 }
337 // Save new password and clear DB-hash
338 $res = $GLOBALS['TYPO3_DB']->exec_UPDATEquery('fe_users', 'uid=' . $user['uid'], array('password' => $newPass, 'felogin_forgotHash' => ''));
339 $markerArray['###STATUS_MESSAGE###'] = $this->getDisplayText('change_password_done_message', $this->conf['changePasswordDoneMessage_stdWrap.']);
340 $done = TRUE;
341 $subpartArray['###CHANGEPASSWORD_FORM###'] = '';
342 $markerArray['###BACKLINK_LOGIN###'] = $this->getPageLink(
343 $this->pi_getLL('ll_forgot_header_backToLogin', '', 1),
344 array($this->prefixId . '[redirectReferrer]' => 'off')
345 );
346 }
347 }
348 if (!$done) {
349 // Change password form
350 $markerArray['###ACTION_URI###'] = $this->pi_getPageLink($GLOBALS['TSFE']->id, '', array(
351 $this->prefixId . '[user]' => $user['uid'],
352 $this->prefixId . '[forgothash]' => $piHash
353 ));
354 $markerArray['###LEGEND###'] = $this->pi_getLL('change_password', '', 1);
355 $markerArray['###NEWPASSWORD1_LABEL###'] = $this->pi_getLL('newpassword_label1', '', 1);
356 $markerArray['###NEWPASSWORD2_LABEL###'] = $this->pi_getLL('newpassword_label2', '', 1);
357 $markerArray['###NEWPASSWORD1###'] = $this->prefixId . '[password1]';
358 $markerArray['###NEWPASSWORD2###'] = $this->prefixId . '[password2]';
359 $markerArray['###STORAGE_PID###'] = $this->spid;
360 $markerArray['###SEND_PASSWORD###'] = $this->pi_getLL('change_password', '', 1);
361 $markerArray['###FORGOTHASH###'] = $piHash;
362 }
363 }
364 }
365 return $this->cObj->substituteMarkerArrayCached($subpart, $markerArray, $subpartArray, $linkpartArray);
366 }
367
368 /**
369 * Generates a hashed link and send it with email
370 *
371 * @param array $user Contains user data
372 * @return string Empty string with success, error message with no success
373 */
374 protected function generateAndSendHash($user) {
375 $hours = intval($this->conf['forgotLinkHashValidTime']) > 0 ? intval($this->conf['forgotLinkHashValidTime']) : 24;
376 $validEnd = time() + 3600 * $hours;
377 $validEndString = date($this->conf['dateFormat'], $validEnd);
378 $hash = md5(\TYPO3\CMS\Core\Utility\GeneralUtility::generateRandomBytes(64));
379 $randHash = $validEnd . '|' . $hash;
380 $randHashDB = $validEnd . '|' . md5($hash);
381 // Write hash to DB
382 $res = $GLOBALS['TYPO3_DB']->exec_UPDATEquery('fe_users', 'uid=' . $user['uid'], array('felogin_forgotHash' => $randHashDB));
383 // Send hashlink to user
384 $this->conf['linkPrefix'] = -1;
385 $isAbsRelPrefix = !empty($GLOBALS['TSFE']->absRefPrefix);
386 $isBaseURL = !empty($GLOBALS['TSFE']->baseUrl);
387 $isFeloginBaseURL = !empty($this->conf['feloginBaseURL']);
388 $link = $this->pi_getPageLink($GLOBALS['TSFE']->id, '', array(
389 $this->prefixId . '[user]' => $user['uid'],
390 $this->prefixId . '[forgothash]' => $randHash
391 ));
392 // Prefix link if necessary
393 if ($isFeloginBaseURL) {
394 // First priority, use specific base URL
395 // "absRefPrefix" must be removed first, otherwise URL will be prepended twice
396 if (!empty($GLOBALS['TSFE']->absRefPrefix)) {
397 $link = substr($link, strlen($GLOBALS['TSFE']->absRefPrefix));
398 }
399 $link = $this->conf['feloginBaseURL'] . $link;
400 } elseif ($isAbsRelPrefix) {
401 // Second priority
402 // absRefPrefix must not necessarily contain a hostname and URL scheme, so add it if needed
403 $link = \TYPO3\CMS\Core\Utility\GeneralUtility::locationHeaderUrl($link);
404 } elseif ($isBaseURL) {
405 // Third priority
406 // Add the global base URL to the link
407 $link = $GLOBALS['TSFE']->baseUrlWrap($link);
408 } else {
409 // No prefix is set, return the error
410 return $this->pi_getLL('ll_change_password_nolinkprefix_message');
411 }
412 $msg = sprintf($this->pi_getLL('ll_forgot_validate_reset_password', '', 0), $user['username'], $link, $validEndString);
413 // Add hook for extra processing of mail message
414 if (isset($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['felogin']['forgotPasswordMail']) && is_array($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['felogin']['forgotPasswordMail'])) {
415 $params = array(
416 'message' => &$msg,
417 'user' => &$user
418 );
419 foreach ($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['felogin']['forgotPasswordMail'] as $reference) {
420 if ($reference) {
421 \TYPO3\CMS\Core\Utility\GeneralUtility::callUserFunction($reference, $params, $this);
422 }
423 }
424 }
425 // no RDCT - Links for security reasons
426 $oldSetting = $GLOBALS['TSFE']->config['config']['notification_email_urlmode'];
427 $GLOBALS['TSFE']->config['config']['notification_email_urlmode'] = 0;
428 // Send the email
429 $this->cObj->sendNotifyEmail($msg, $user['email'], '', $this->conf['email_from'], $this->conf['email_fromName'], $this->conf['replyTo']);
430 // Restore settings
431 $GLOBALS['TSFE']->config['config']['notification_email_urlmode'] = $oldSetting;
432 return '';
433 }
434
435 /**
436 * Shows logout form
437 *
438 * @return string The content.
439 */
440 protected function showLogout() {
441 $subpart = $this->cObj->getSubpart($this->template, '###TEMPLATE_LOGOUT###');
442 $subpartArray = ($linkpartArray = array());
443 $markerArray['###STATUS_HEADER###'] = $this->getDisplayText('status_header', $this->conf['logoutHeader_stdWrap.']);
444 $markerArray['###STATUS_MESSAGE###'] = $this->getDisplayText('status_message', $this->conf['logoutMessage_stdWrap.']);
445 $this->cObj->stdWrap($this->flexFormValue('message', 's_status'), $this->conf['logoutMessage_stdWrap.']);
446 $markerArray['###LEGEND###'] = $this->pi_getLL('logout', '', 1);
447 $markerArray['###ACTION_URI###'] = $this->getPageLink('', array(), TRUE);
448 $markerArray['###LOGOUT_LABEL###'] = $this->pi_getLL('logout', '', 1);
449 $markerArray['###NAME###'] = htmlspecialchars($GLOBALS['TSFE']->fe_user->user['name']);
450 $markerArray['###STORAGE_PID###'] = $this->spid;
451 $markerArray['###USERNAME###'] = htmlspecialchars($GLOBALS['TSFE']->fe_user->user['username']);
452 $markerArray['###USERNAME_LABEL###'] = $this->pi_getLL('username', '', 1);
453 $markerArray['###NOREDIRECT###'] = $this->noRedirect ? '1' : '0';
454 $markerArray['###PREFIXID###'] = $this->prefixId;
455 $markerArray = array_merge($markerArray, $this->getUserFieldMarkers());
456 if ($this->redirectUrl) {
457 // Use redirectUrl for action tag because of possible access restricted pages
458 $markerArray['###ACTION_URI###'] = htmlspecialchars($this->redirectUrl);
459 $this->redirectUrl = '';
460 }
461 return $this->cObj->substituteMarkerArrayCached($subpart, $markerArray, $subpartArray, $linkpartArray);
462 }
463
464 /**
465 * Shows login form
466 *
467 * @return string Content
468 */
469 protected function showLogin() {
470 $subpart = $this->cObj->getSubpart($this->template, '###TEMPLATE_LOGIN###');
471 $subpartArray = ($linkpartArray = ($markerArray = array()));
472 $gpRedirectUrl = '';
473 $markerArray['###LEGEND###'] = $this->pi_getLL('oLabel_header_welcome', '', 1);
474 if ($this->logintype === 'login') {
475 if ($this->userIsLoggedIn) {
476 // login success
477 $markerArray['###STATUS_HEADER###'] = $this->getDisplayText('success_header', $this->conf['successHeader_stdWrap.']);
478 $markerArray['###STATUS_MESSAGE###'] = $this->getDisplayText('success_message', $this->conf['successMessage_stdWrap.']);
479 $markerArray = array_merge($markerArray, $this->getUserFieldMarkers());
480 $subpartArray['###LOGIN_FORM###'] = '';
481 // Hook for general actions after after login has been confirmed (by Thomas Danzl <thomas@danzl.org>)
482 if ($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['felogin']['login_confirmed']) {
483 $_params = array();
484 foreach ($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['felogin']['login_confirmed'] as $_funcRef) {
485 if ($_funcRef) {
486 \TYPO3\CMS\Core\Utility\GeneralUtility::callUserFunction($_funcRef, $_params, $this);
487 }
488 }
489 }
490 // show logout form directly
491 if ($this->conf['showLogoutFormAfterLogin']) {
492 $this->redirectUrl = '';
493 return $this->showLogout();
494 }
495 } else {
496 // Hook for general actions on login error
497 if (isset($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['felogin']['login_error']) && is_array($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['felogin']['login_error'])) {
498 $params = array();
499 foreach ($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['felogin']['login_error'] as $funcRef) {
500 if ($funcRef) {
501 \TYPO3\CMS\Core\Utility\GeneralUtility::callUserFunction($funcRef, $params, $this);
502 }
503 }
504 }
505 // login error
506 $markerArray['###STATUS_HEADER###'] = $this->getDisplayText('error_header', $this->conf['errorHeader_stdWrap.']);
507 $markerArray['###STATUS_MESSAGE###'] = $this->getDisplayText('error_message', $this->conf['errorMessage_stdWrap.']);
508 $gpRedirectUrl = \TYPO3\CMS\Core\Utility\GeneralUtility::_GP('redirect_url');
509 }
510 } else {
511 if ($this->logintype === 'logout') {
512 // login form after logout
513 $markerArray['###STATUS_HEADER###'] = $this->getDisplayText('logout_header', $this->conf['logoutHeader_stdWrap.']);
514 $markerArray['###STATUS_MESSAGE###'] = $this->getDisplayText('logout_message', $this->conf['logoutMessage_stdWrap.']);
515 } else {
516 // login form
517 $markerArray['###STATUS_HEADER###'] = $this->getDisplayText('welcome_header', $this->conf['welcomeHeader_stdWrap.']);
518 $markerArray['###STATUS_MESSAGE###'] = $this->getDisplayText('welcome_message', $this->conf['welcomeMessage_stdWrap.']);
519 }
520 }
521
522 // This hook allows to call User JS functions.
523 // The methods should also set the required JS functions to get included
524 $onSubmit = '';
525 $extraHidden = '';
526 $onSubmitAr = array();
527 $extraHiddenAr = array();
528 // Check for referer redirect method. if present, save referer in form field
529 if (\TYPO3\CMS\Core\Utility\GeneralUtility::inList($this->conf['redirectMode'], 'referer') || \TYPO3\CMS\Core\Utility\GeneralUtility::inList($this->conf['redirectMode'], 'refererDomains')) {
530 $referer = $this->referer ? $this->referer : \TYPO3\CMS\Core\Utility\GeneralUtility::getIndpEnv('HTTP_REFERER');
531 if ($referer) {
532 $extraHiddenAr[] = '<input type="hidden" name="referer" value="' . htmlspecialchars($referer) . '" />';
533 if ($this->piVars['redirectReferrer'] === 'off') {
534 $extraHiddenAr[] = '<input type="hidden" name="' . $this->prefixId . '[redirectReferrer]" value="off" />';
535 }
536 }
537 }
538 if (is_array($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['felogin']['loginFormOnSubmitFuncs'])) {
539 $_params = array();
540 foreach ($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['felogin']['loginFormOnSubmitFuncs'] as $funcRef) {
541 list($onSub, $hid) = \TYPO3\CMS\Core\Utility\GeneralUtility::callUserFunction($funcRef, $_params, $this);
542 $onSubmitAr[] = $onSub;
543 $extraHiddenAr[] = $hid;
544 }
545 }
546 if (count($onSubmitAr)) {
547 $onSubmit = implode('; ', $onSubmitAr) . '; return true;';
548 }
549 if (count($extraHiddenAr)) {
550 $extraHidden = implode(LF, $extraHiddenAr);
551 }
552 if (!$gpRedirectUrl && $this->redirectUrl) {
553 $gpRedirectUrl = $this->redirectUrl;
554 }
555 // Login form
556 $markerArray['###ACTION_URI###'] = $this->getPageLink('', array(), TRUE);
557 // Used by kb_md5fepw extension...
558 $markerArray['###EXTRA_HIDDEN###'] = $extraHidden;
559 $markerArray['###LEGEND###'] = $this->pi_getLL('login', '', 1);
560 $markerArray['###LOGIN_LABEL###'] = $this->pi_getLL('login', '', 1);
561 // Used by kb_md5fepw extension...
562 $markerArray['###ON_SUBMIT###'] = $onSubmit;
563 $markerArray['###PASSWORD_LABEL###'] = $this->pi_getLL('password', '', 1);
564 $markerArray['###STORAGE_PID###'] = $this->spid;
565 $markerArray['###USERNAME_LABEL###'] = $this->pi_getLL('username', '', 1);
566 $markerArray['###REDIRECT_URL###'] = htmlspecialchars($gpRedirectUrl);
567 $markerArray['###NOREDIRECT###'] = $this->noRedirect ? '1' : '0';
568 $markerArray['###PREFIXID###'] = $this->prefixId;
569 $markerArray = array_merge($markerArray, $this->getUserFieldMarkers());
570 if ($this->flexFormValue('showForgotPassword', 'sDEF') || $this->conf['showForgotPasswordLink']) {
571 $linkpartArray['###FORGOT_PASSWORD_LINK###'] = explode('|', $this->getPageLink('|', array($this->prefixId . '[forgot]' => 1)));
572 $markerArray['###FORGOT_PASSWORD###'] = $this->pi_getLL('ll_forgot_header', '', 1);
573 } else {
574 $subpartArray['###FORGOTP_VALID###'] = '';
575 }
576 // The permanent login checkbox should only be shown if permalogin is not deactivated (-1), not forced to be always active (2) and lifetime is greater than 0
577 if ($this->conf['showPermaLogin'] && \TYPO3\CMS\Core\Utility\GeneralUtility::inList('0,1', $GLOBALS['TYPO3_CONF_VARS']['FE']['permalogin']) && $GLOBALS['TYPO3_CONF_VARS']['FE']['lifetime'] > 0) {
578 $markerArray['###PERMALOGIN###'] = $this->pi_getLL('permalogin', '', 1);
579 if ($GLOBALS['TYPO3_CONF_VARS']['FE']['permalogin'] == 1) {
580 $markerArray['###PERMALOGIN_HIDDENFIELD_ATTRIBUTES###'] = 'disabled="disabled"';
581 $markerArray['###PERMALOGIN_CHECKBOX_ATTRIBUTES###'] = 'checked="checked"';
582 } else {
583 $markerArray['###PERMALOGIN_HIDDENFIELD_ATTRIBUTES###'] = '';
584 $markerArray['###PERMALOGIN_CHECKBOX_ATTRIBUTES###'] = '';
585 }
586 } else {
587 $subpartArray['###PERMALOGIN_VALID###'] = '';
588 }
589 return $this->cObj->substituteMarkerArrayCached($subpart, $markerArray, $subpartArray, $linkpartArray);
590 }
591
592 /**
593 * Process redirect methods. The function searches for a redirect url using all configured methods.
594 *
595 * @return string Redirect url
596 */
597 protected function processRedirect() {
598 $redirect_url = array();
599 if ($this->conf['redirectMode']) {
600 $redirectMethods = \TYPO3\CMS\Core\Utility\GeneralUtility::trimExplode(',', $this->conf['redirectMode'], TRUE);
601 foreach ($redirectMethods as $redirMethod) {
602 if ($GLOBALS['TSFE']->loginUser && $this->logintype === 'login') {
603 // Logintype is needed because the login-page wouldn't be accessible anymore after a login (would always redirect)
604 switch ($redirMethod) {
605 case 'groupLogin':
606 // taken from dkd_redirect_at_login written by Ingmar Schlecht; database-field changed
607 $groupData = $GLOBALS['TSFE']->fe_user->groupData;
608 $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('felogin_redirectPid', $GLOBALS['TSFE']->fe_user->usergroup_table, 'felogin_redirectPid<>\'\' AND uid IN (' . implode(',', $groupData['uid']) . ')');
609 if ($row = $GLOBALS['TYPO3_DB']->sql_fetch_row($res)) {
610 // take the first group with a redirect page
611 $redirect_url[] = $this->pi_getPageLink($row[0]);
612 }
613 break;
614 case 'userLogin':
615 $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('felogin_redirectPid', $GLOBALS['TSFE']->fe_user->user_table, $GLOBALS['TSFE']->fe_user->userid_column . '=' . $GLOBALS['TSFE']->fe_user->user['uid'] . ' AND felogin_redirectPid<>\'\'');
616 if ($row = $GLOBALS['TYPO3_DB']->sql_fetch_row($res)) {
617 $redirect_url[] = $this->pi_getPageLink($row[0]);
618 }
619 break;
620 case 'login':
621 if ($this->conf['redirectPageLogin']) {
622 $redirect_url[] = $this->pi_getPageLink(intval($this->conf['redirectPageLogin']));
623 }
624 break;
625 case 'getpost':
626 $redirect_url[] = $this->redirectUrl;
627 break;
628 case 'referer':
629 // Avoid redirect when logging in after changing password
630 if ($this->piVars['redirectReferrer'] !== 'off') {
631 // Avoid forced logout, when trying to login immediately after a logout
632 $redirect_url[] = preg_replace('/[&?]logintype=[a-z]+/', '', $this->referer);
633 }
634 break;
635 case 'refererDomains':
636 // Auto redirect.
637 // Feature to redirect to the page where the user came from (HTTP_REFERER).
638 // Allowed domains to redirect to, can be configured with plugin.tx_felogin_pi1.domains
639 // Thanks to plan2.net / Martin Kutschker for implementing this feature.
640 // also avoid redirect when logging in after changing password
641 if ($this->conf['domains'] && $this->piVars['redirectReferrer'] !== 'off') {
642 $url = $this->referer;
643 // Is referring url allowed to redirect?
644 $match = array();
645 if (preg_match('/^http://([[:alnum:]._-]+)//', $url, $match)) {
646 $redirect_domain = $match[1];
647 $found = FALSE;
648 foreach (\TYPO3\CMS\Core\Utility\GeneralUtility::trimExplode(',', $this->conf['domains'], TRUE) as $d) {
649 if (preg_match('/(^|\\.)/' . $d . '$', $redirect_domain)) {
650 $found = TRUE;
651 break;
652 }
653 }
654 if (!$found) {
655 $url = '';
656 }
657 }
658 // Avoid forced logout, when trying to login immediately after a logout
659 if ($url) {
660 $redirect_url[] = preg_replace('/[&?]logintype=[a-z]+/', '', $url);
661 }
662 }
663 break;
664 }
665 } elseif ($this->logintype === 'login') {
666 // after login-error
667 switch ($redirMethod) {
668 case 'loginError':
669 if ($this->conf['redirectPageLoginError']) {
670 $redirect_url[] = $this->pi_getPageLink(intval($this->conf['redirectPageLoginError']));
671 }
672 break;
673 }
674 } elseif ($this->logintype == '' && $redirMethod == 'login' && $this->conf['redirectPageLogin']) {
675 // If login and page not accessible
676 $this->cObj->typolink('', array(
677 'parameter' => $this->conf['redirectPageLogin'],
678 'linkAccessRestrictedPages' => TRUE
679 ));
680 $redirect_url[] = $this->cObj->lastTypoLinkUrl;
681 } elseif ($this->logintype == '' && $redirMethod == 'logout' && $this->conf['redirectPageLogout'] && $GLOBALS['TSFE']->loginUser) {
682 // If logout and page not accessible
683 $redirect_url[] = $this->pi_getPageLink(intval($this->conf['redirectPageLogout']));
684 } elseif ($this->logintype === 'logout') {
685 // after logout
686 // Hook for general actions after after logout has been confirmed
687 if ($this->logintype === 'logout' && $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['felogin']['logout_confirmed']) {
688 $_params = array();
689 foreach ($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['felogin']['logout_confirmed'] as $_funcRef) {
690 if ($_funcRef) {
691 \TYPO3\CMS\Core\Utility\GeneralUtility::callUserFunction($_funcRef, $_params, $this);
692 }
693 }
694 }
695 switch ($redirMethod) {
696 case 'logout':
697 if ($this->conf['redirectPageLogout']) {
698 $redirect_url[] = $this->pi_getPageLink(intval($this->conf['redirectPageLogout']));
699 }
700 break;
701 }
702 } else {
703 // not logged in
704 // Placeholder for maybe future options
705 switch ($redirMethod) {
706 case 'getpost':
707 // Preserve the get/post value
708 $redirect_url[] = $this->redirectUrl;
709 break;
710 }
711 }
712 }
713 }
714 // Remove empty values
715 if (count($redirect_url)) {
716 return \TYPO3\CMS\Core\Utility\GeneralUtility::trimExplode(',', implode(',', $redirect_url), TRUE);
717 } else {
718 return array();
719 }
720 }
721
722 /**
723 * Reads flexform configuration and merge it with $this->conf
724 *
725 * @return void
726 */
727 protected function mergeflexFormValuesIntoConf() {
728 $flex = array();
729 if ($this->flexFormValue('showForgotPassword', 'sDEF')) {
730 $flex['showForgotPassword'] = $this->flexFormValue('showForgotPassword', 'sDEF');
731 }
732 if ($this->flexFormValue('showPermaLogin', 'sDEF')) {
733 $flex['showPermaLogin'] = $this->flexFormValue('showPermaLogin', 'sDEF');
734 }
735 if ($this->flexFormValue('showLogoutFormAfterLogin', 'sDEF')) {
736 $flex['showLogoutFormAfterLogin'] = $this->flexFormValue('showLogoutFormAfterLogin', 'sDEF');
737 }
738 if ($this->flexFormValue('pages', 'sDEF')) {
739 $flex['pages'] = $this->flexFormValue('pages', 'sDEF');
740 }
741 if ($this->flexFormValue('recursive', 'sDEF')) {
742 $flex['recursive'] = $this->flexFormValue('recursive', 'sDEF');
743 }
744 if ($this->flexFormValue('templateFile', 'sDEF')) {
745 $flex['templateFile'] = $this->uploadDir . $this->flexFormValue('templateFile', 'sDEF');
746 }
747 if ($this->flexFormValue('redirectMode', 's_redirect')) {
748 $flex['redirectMode'] = $this->flexFormValue('redirectMode', 's_redirect');
749 }
750 if ($this->flexFormValue('redirectFirstMethod', 's_redirect')) {
751 $flex['redirectFirstMethod'] = $this->flexFormValue('redirectFirstMethod', 's_redirect');
752 }
753 if ($this->flexFormValue('redirectDisable', 's_redirect')) {
754 $flex['redirectDisable'] = $this->flexFormValue('redirectDisable', 's_redirect');
755 }
756 if ($this->flexFormValue('redirectPageLogin', 's_redirect')) {
757 $flex['redirectPageLogin'] = $this->flexFormValue('redirectPageLogin', 's_redirect');
758 }
759 if ($this->flexFormValue('redirectPageLoginError', 's_redirect')) {
760 $flex['redirectPageLoginError'] = $this->flexFormValue('redirectPageLoginError', 's_redirect');
761 }
762 if ($this->flexFormValue('redirectPageLogout', 's_redirect')) {
763 $flex['redirectPageLogout'] = $this->flexFormValue('redirectPageLogout', 's_redirect');
764 }
765 $pid = $flex['pages'] ? $this->pi_getPidList($flex['pages'], $flex['recursive']) : 0;
766 if ($pid > 0) {
767 $flex['storagePid'] = $pid;
768 }
769 $this->conf = array_merge($this->conf, $flex);
770 }
771
772 /**
773 * Loads a variable from the flexform
774 *
775 * @param string $var Name of variable
776 * @param string $sheet Name of sheet
777 * @return string Value of var
778 */
779 protected function flexFormValue($var, $sheet) {
780 return $this->pi_getFFvalue($this->cObj->data['pi_flexform'], $var, $sheet);
781 }
782
783 /**
784 * Generate link with typolink function
785 *
786 * @param string $label Linktext
787 * @param array $piVars Link vars
788 * @param boolean $returnUrl TRUE: returns only url FALSE (default) returns the link)
789 * @return string Link or url
790 */
791 protected function getPageLink($label, $piVars, $returnUrl = FALSE) {
792 $additionalParams = '';
793 if (count($piVars)) {
794 foreach ($piVars as $key => $val) {
795 $additionalParams .= '&' . $key . '=' . $val;
796 }
797 }
798 // Should GETvars be preserved?
799 if ($this->conf['preserveGETvars']) {
800 $additionalParams .= $this->getPreserveGetVars();
801 }
802 $this->conf['linkConfig.']['parameter'] = $GLOBALS['TSFE']->id;
803 if ($additionalParams) {
804 $this->conf['linkConfig.']['additionalParams'] = $additionalParams;
805 }
806 if ($returnUrl) {
807 return htmlspecialchars($this->cObj->typolink_url($this->conf['linkConfig.']));
808 } else {
809 return $this->cObj->typolink($label, $this->conf['linkConfig.']);
810 }
811 }
812
813 /**
814 * Add additional parameters for links according to TS setting preserveGETvars.
815 * Possible values are "all" or a comma separated list of allowed GET-vars.
816 * Supports multi-dimensional GET-vars.
817 * Some hardcoded values are dropped.
818 *
819 * @return string additionalParams-string
820 */
821 protected function getPreserveGetVars() {
822 $getVars = \TYPO3\CMS\Core\Utility\GeneralUtility::_GET();
823 unset(
824 $getVars['id'],
825 $getVars['no_cache'],
826 $getVars['logintype'],
827 $getVars['redirect_url'],
828 $getVars['cHash']
829 );
830 if ($this->conf['preserveGETvars'] === 'all') {
831 $preserveQueryParts = $getVars;
832 } else {
833 $preserveQueryParts = \TYPO3\CMS\Core\Utility\GeneralUtility::trimExplode(',', $this->conf['preserveGETvars']);
834 $preserveQueryParts = \TYPO3\CMS\Core\Utility\GeneralUtility::explodeUrl2Array(implode('=1&', $preserveQueryParts) . '=1', TRUE);
835 $preserveQueryParts = \TYPO3\CMS\Core\Utility\ArrayUtility::intersectRecursive($getVars, $preserveQueryParts);
836 }
837 $parameters = \TYPO3\CMS\Core\Utility\GeneralUtility::implodeArrayForUrl('', $preserveQueryParts);
838 return $parameters;
839 }
840
841 /**
842 * Is used by forgot password - function with md5 option.
843 *
844 * @author Bernhard Kraft
845 * @param integer $len Length of new password
846 * @return string New password
847 */
848 protected function generatePassword($len) {
849 $pass = '';
850 while ($len--) {
851 $char = rand(0, 35);
852 if ($char < 10) {
853 $pass .= '' . $char;
854 } else {
855 $pass .= chr($char - 10 + 97);
856 }
857 }
858 return $pass;
859 }
860
861 /**
862 * Returns the header / message value from flexform if present, else from locallang.xml
863 *
864 * @param string $label label name
865 * @param string $stdWrapArray TS stdWrap array
866 * @return string label text
867 */
868 protected function getDisplayText($label, $stdWrapArray = array()) {
869 $text = $this->flexFormValue($label, 's_messages') ? $this->cObj->stdWrap($this->flexFormValue($label, 's_messages'), $stdWrapArray) : $this->cObj->stdWrap($this->pi_getLL('ll_' . $label, '', 1), $stdWrapArray);
870 $replace = $this->getUserFieldMarkers();
871 return strtr($text, $replace);
872 }
873
874 /**
875 * Returns Array of markers filled with user fields
876 *
877 * @return array Marker array
878 */
879 protected function getUserFieldMarkers() {
880 $marker = array();
881 // replace markers with fe_user data
882 if ($GLOBALS['TSFE']->fe_user->user) {
883 // All fields of fe_user will be replaced, scheme is ###FEUSER_FIELDNAME###
884 foreach ($GLOBALS['TSFE']->fe_user->user as $field => $value) {
885 $marker['###FEUSER_' . \TYPO3\CMS\Core\Utility\GeneralUtility::strtoupper($field) . '###'] = $this->cObj->stdWrap($value, $this->conf['userfields.'][$field . '.']);
886 }
887 // Add ###USER### for compatibility
888 $marker['###USER###'] = $marker['###FEUSER_USERNAME###'];
889 }
890 return $marker;
891 }
892
893 /**
894 * Returns a valid and XSS cleaned url for redirect, checked against configuration "allowedRedirectHosts"
895 *
896 * @param string $url
897 * @return string cleaned referer or empty string if not valid
898 */
899 protected function validateRedirectUrl($url) {
900 $url = strval($url);
901 if ($url === '') {
902 return '';
903 }
904 $decodedUrl = rawurldecode($url);
905 $sanitizedUrl = \TYPO3\CMS\Core\Utility\GeneralUtility::removeXSS($decodedUrl);
906 if ($decodedUrl !== $sanitizedUrl || preg_match('#["<>\\\\]+#', $url)) {
907 \TYPO3\CMS\Core\Utility\GeneralUtility::sysLog(sprintf($this->pi_getLL('xssAttackDetected'), $url), 'felogin', \TYPO3\CMS\Core\Utility\GeneralUtility::SYSLOG_SEVERITY_WARNING);
908 return '';
909 }
910 // Validate the URL:
911 if ($this->isRelativeUrl($url) || $this->isInCurrentDomain($url) || $this->isInLocalDomain($url)) {
912 return $url;
913 }
914 // URL is not allowed
915 \TYPO3\CMS\Core\Utility\GeneralUtility::sysLog(sprintf($this->pi_getLL('noValidRedirectUrl'), $url), 'felogin', \TYPO3\CMS\Core\Utility\GeneralUtility::SYSLOG_SEVERITY_WARNING);
916 return '';
917 }
918
919 /**
920 * Determines whether the URL is on the current host
921 * and belongs to the current TYPO3 installation.
922 *
923 * @param string $url URL to be checked
924 * @return boolean Whether the URL belongs to the current TYPO3 installation
925 */
926 protected function isInCurrentDomain($url) {
927 return \TYPO3\CMS\Core\Utility\GeneralUtility::isOnCurrentHost($url) && \TYPO3\CMS\Core\Utility\GeneralUtility::isFirstPartOfStr($url, \TYPO3\CMS\Core\Utility\GeneralUtility::getIndpEnv('TYPO3_SITE_URL'));
928 }
929
930 /**
931 * Determines whether the URL matches a domain
932 * in the sys_domain database table.
933 *
934 * @param string $url Absolute URL which needs to be checked
935 * @return boolean Whether the URL is considered to be local
936 */
937 protected function isInLocalDomain($url) {
938 $result = FALSE;
939 if (\TYPO3\CMS\Core\Utility\GeneralUtility::isValidUrl($url)) {
940 $parsedUrl = parse_url($url);
941 if ($parsedUrl['scheme'] === 'http' || $parsedUrl['scheme'] === 'https') {
942 $host = $parsedUrl['host'];
943 // Removes the last path segment and slash sequences like /// (if given):
944 $path = preg_replace('#/+[^/]*$#', '', $parsedUrl['path']);
945 $localDomains = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows('domainName', 'sys_domain', '1=1' . $this->cObj->enableFields('sys_domain'));
946 if (is_array($localDomains)) {
947 foreach ($localDomains as $localDomain) {
948 // strip trailing slashes (if given)
949 $domainName = rtrim($localDomain['domainName'], '/');
950 if (\TYPO3\CMS\Core\Utility\GeneralUtility::isFirstPartOfStr($host . $path . '/', $domainName . '/')) {
951 $result = TRUE;
952 break;
953 }
954 }
955 }
956 }
957 }
958 return $result;
959 }
960
961 /**
962 * Determines whether the URL is relative to the
963 * current TYPO3 installation.
964 *
965 * @param string $url URL which needs to be checked
966 * @return boolean Whether the URL is considered to be relative
967 */
968 protected function isRelativeUrl($url) {
969 $parsedUrl = @parse_url($url);
970 if ($parsedUrl !== FALSE && !isset($parsedUrl['scheme']) && !isset($parsedUrl['host'])) {
971 // If the relative URL starts with a slash, we need to check if it's within the current site path
972 return !\TYPO3\CMS\Core\Utility\GeneralUtility::isFirstPartOfStr($parsedUrl['path'], '/') || \TYPO3\CMS\Core\Utility\GeneralUtility::isFirstPartOfStr($parsedUrl['path'], \TYPO3\CMS\Core\Utility\GeneralUtility::getIndpEnv('TYPO3_SITE_PATH'));
973 }
974 return FALSE;
975 }
976
977 }
978
979 ?>