TYPO3 CMS  TYPO3_6-2
FrontendLoginController.php
Go to the documentation of this file.
1 <?php
3 
19 
26 
32  public $prefixId = 'tx_felogin_pi1';
33 
39  public $scriptRelPath = 'pi1/class.tx_felogin_pi1.php';
40 
46  public $extKey = 'felogin';
47 
51  public $pi_checkCHash = FALSE;
52 
56  public $pi_USER_INT_obj = TRUE;
57 
63  protected $userIsLoggedIn;
64 
70  protected $template;
71 
77  protected $uploadDir;
78 
84  protected $redirectUrl;
85 
91  protected $noRedirect = FALSE;
92 
98  protected $logintype;
99 
107  public function main($content, $conf) {
108  // Loading TypoScript array into object variable:
109  $this->conf = $conf;
110  $this->uploadDir = 'uploads/tx_felogin/';
111  // Loading default pivars
112  $this->pi_setPiVarDefaults();
113  // Loading language-labels
114  $this->pi_loadLL();
115  // Init FlexForm configuration for plugin:
116  $this->pi_initPIflexForm();
118  // Get storage PIDs:
119  if ($this->conf['storagePid']) {
120  if ((int)$this->conf['recursive']) {
121  $this->spid = $this->pi_getPidList($this->conf['storagePid'], (int)$this->conf['recursive']);
122  } else {
123  $this->spid = $this->conf['storagePid'];
124  }
125  } else {
126  $pids = $GLOBALS['TSFE']->getStorageSiterootPids();
127  $this->spid = $pids['_STORAGE_PID'];
128  }
129  // GPvars:
130  $this->logintype = GeneralUtility::_GP('logintype');
131  $this->referer = $this->validateRedirectUrl(GeneralUtility::_GP('referer'));
132  $this->noRedirect = $this->piVars['noredirect'] || $this->conf['redirectDisable'];
133  // If config.typolinkLinkAccessRestrictedPages is set, the var is return_url
134  $returnUrl = GeneralUtility::_GP('return_url');
135  if ($returnUrl) {
136  $this->redirectUrl = $returnUrl;
137  } else {
138  $this->redirectUrl = GeneralUtility::_GP('redirect_url');
139  }
140  $this->redirectUrl = $this->validateRedirectUrl($this->redirectUrl);
141  // Get Template
142  $templateFile = $this->conf['templateFile'] ?: 'EXT:felogin/template.html';
143  $this->template = $this->cObj->fileResource($templateFile);
144  // Is user logged in?
145  $this->userIsLoggedIn = $GLOBALS['TSFE']->loginUser;
146  // Redirect
147  if ($this->conf['redirectMode'] && !$this->conf['redirectDisable'] && !$this->noRedirect) {
148  $redirectUrl = $this->processRedirect();
149  if (count($redirectUrl)) {
150  $this->redirectUrl = $this->conf['redirectFirstMethod'] ? array_shift($redirectUrl) : array_pop($redirectUrl);
151  } else {
152  $this->redirectUrl = '';
153  }
154  }
155  // What to display
156  $content = '';
157  if ($this->piVars['forgot'] && $this->conf['showForgotPasswordLink']) {
158  $content .= $this->showForgot();
159  } elseif ($this->piVars['forgothash']) {
160  $content .= $this->changePassword();
161  } else {
162  if ($this->userIsLoggedIn && !$this->logintype) {
163  $content .= $this->showLogout();
164  } else {
165  $content .= $this->showLogin();
166  }
167  }
168  // Process the redirect
169  if (($this->logintype === 'login' || $this->logintype === 'logout') && $this->redirectUrl && !$this->noRedirect) {
170  if (!$GLOBALS['TSFE']->fe_user->isCookieSet() && $this->userIsLoggedIn) {
171  $content .= $this->cObj->stdWrap($this->pi_getLL('cookie_warning'), $this->conf['cookieWarning_stdWrap.']);
172  } else {
173  // Add hook for extra processing before redirect
174  if (
175  isset($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['felogin']['beforeRedirect']) &&
176  is_array($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['felogin']['beforeRedirect'])
177  ) {
178  $_params = array(
179  'loginType' => $this->logintype,
180  'redirectUrl' => &$this->redirectUrl
181  );
182  foreach ($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['felogin']['beforeRedirect'] as $_funcRef) {
183  if ($_funcRef) {
184  GeneralUtility::callUserFunction($_funcRef, $_params, $this);
185  }
186  }
187  }
189  }
190  }
191  // Adds hook for processing of extra item markers / special
192  if (
193  isset($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['felogin']['postProcContent'])
194  && is_array($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['felogin']['postProcContent'])
195  ) {
196  $_params = array(
197  'content' => $content
198  );
199  foreach ($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['felogin']['postProcContent'] as $_funcRef) {
200  $content = GeneralUtility::callUserFunction($_funcRef, $_params, $this);
201  }
202  }
203  return $this->conf['wrapContentInBaseClass'] ? $this->pi_wrapInBaseClass($content) : $content;
204  }
205 
211  protected function showForgot() {
212  $subpart = $this->cObj->getSubpart($this->template, '###TEMPLATE_FORGOT###');
213  $subpartArray = ($linkpartArray = array());
214  $postData = GeneralUtility::_POST($this->prefixId);
215  if ($postData['forgot_email']) {
216  // Get hashes for compare
217  $postedHash = $postData['forgot_hash'];
218  $hashData = $GLOBALS['TSFE']->fe_user->getKey('ses', 'forgot_hash');
219  if ($postedHash === $hashData['forgot_hash']) {
220  $row = FALSE;
221  // Look for user record
222  $data = $GLOBALS['TYPO3_DB']->fullQuoteStr($this->piVars['forgot_email'], 'fe_users');
223  $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
224  'uid, username, password, email',
225  'fe_users',
226  '(email=' . $data . ' OR username=' . $data . ') AND pid IN (' . $GLOBALS['TYPO3_DB']->cleanIntList($this->spid) . ') ' . $this->cObj->enableFields('fe_users')
227  );
228  if ($GLOBALS['TYPO3_DB']->sql_num_rows($res)) {
229  $row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res);
230  }
231  $error = NULL;
232  if ($row) {
233  // Generate an email with the hashed link
234  $error = $this->generateAndSendHash($row);
235  } elseif ($this->conf['exposeNonexistentUserInForgotPasswordDialog']) {
236  $error = $this->pi_getLL('ll_forgot_reset_message_error');
237  }
238  // Generate message
239  if ($error) {
240  $markerArray['###STATUS_MESSAGE###'] = $this->cObj->stdWrap($error, $this->conf['forgotErrorMessage_stdWrap.']);
241  } else {
242  $markerArray['###STATUS_MESSAGE###'] = $this->cObj->stdWrap(
243  $this->pi_getLL('ll_forgot_reset_message_emailSent'),
244  $this->conf['forgotResetMessageEmailSentMessage_stdWrap.']
245  );
246  }
247  $subpartArray['###FORGOT_FORM###'] = '';
248  } else {
249  // Wrong email
250  $markerArray['###STATUS_MESSAGE###'] = $this->getDisplayText('forgot_reset_message', $this->conf['forgotMessage_stdWrap.']);
251  $markerArray['###BACKLINK_LOGIN###'] = '';
252  }
253  } else {
254  $markerArray['###STATUS_MESSAGE###'] = $this->getDisplayText('forgot_reset_message', $this->conf['forgotMessage_stdWrap.']);
255  $markerArray['###BACKLINK_LOGIN###'] = '';
256  }
257  $markerArray['###BACKLINK_LOGIN###'] = $this->getPageLink($this->pi_getLL('ll_forgot_header_backToLogin', '', TRUE), array());
258  $markerArray['###STATUS_HEADER###'] = $this->getDisplayText('forgot_header', $this->conf['forgotHeader_stdWrap.']);
259  $markerArray['###LEGEND###'] = $this->pi_getLL('legend', $this->pi_getLL('reset_password'), TRUE);
260  $markerArray['###ACTION_URI###'] = $this->getPageLink('', array($this->prefixId . '[forgot]' => 1), TRUE);
261  $markerArray['###EMAIL_LABEL###'] = $this->pi_getLL('your_email', '', TRUE);
262  $markerArray['###FORGOT_PASSWORD_ENTEREMAIL###'] = $this->pi_getLL('forgot_password_enterEmail', '', TRUE);
263  $markerArray['###FORGOT_EMAIL###'] = $this->prefixId . '[forgot_email]';
264  $markerArray['###SEND_PASSWORD###'] = $this->pi_getLL('reset_password', '', TRUE);
265  $markerArray['###DATA_LABEL###'] = $this->pi_getLL('ll_enter_your_data', '', TRUE);
266  $markerArray = array_merge($markerArray, $this->getUserFieldMarkers());
267  // Generate hash
268  $hash = md5($this->generatePassword(3));
269  $markerArray['###FORGOTHASH###'] = $hash;
270  // Set hash in feuser session
271  $GLOBALS['TSFE']->fe_user->setKey('ses', 'forgot_hash', array('forgot_hash' => $hash));
272  return $this->cObj->substituteMarkerArrayCached($subpart, $markerArray, $subpartArray, $linkpartArray);
273  }
274 
281  protected function changePassword() {
282  $subpartArray = ($linkpartArray = array());
283  $done = FALSE;
284  $minLength = (int)$this->conf['newPasswordMinLength'] ?: 6;
285  $subpart = $this->cObj->getSubpart($this->template, '###TEMPLATE_CHANGEPASSWORD###');
286  $markerArray['###STATUS_HEADER###'] = $this->getDisplayText('change_password_header', $this->conf['changePasswordHeader_stdWrap.']);
287  $markerArray['###STATUS_MESSAGE###'] = sprintf($this->getDisplayText(
288  'change_password_message',
289  $this->conf['changePasswordMessage_stdWrap.']
290  ), $minLength);
291 
292  $markerArray['###BACKLINK_LOGIN###'] = '';
293  $uid = $this->piVars['user'];
294  $piHash = $this->piVars['forgothash'];
295  $hash = explode('|', $piHash);
296  if ((int)$uid === 0) {
297  $markerArray['###STATUS_MESSAGE###'] = $this->getDisplayText(
298  'change_password_notvalid_message',
299  $this->conf['changePasswordNotValidMessage_stdWrap.']
300  );
301  $subpartArray['###CHANGEPASSWORD_FORM###'] = '';
302  } else {
303  $user = $this->pi_getRecord('fe_users', (int)$uid);
304  $userHash = $user['felogin_forgotHash'];
305  $compareHash = explode('|', $userHash);
306  if (!$compareHash || !$compareHash[1] || $compareHash[0] < time() || $hash[0] != $compareHash[0] || md5($hash[1]) != $compareHash[1]) {
307  $markerArray['###STATUS_MESSAGE###'] = $this->getDisplayText(
308  'change_password_notvalid_message',
309  $this->conf['changePasswordNotValidMessage_stdWrap.']
310  );
311  $subpartArray['###CHANGEPASSWORD_FORM###'] = '';
312  } else {
313  // All is fine, continue with new password
314  $postData = GeneralUtility::_POST($this->prefixId);
315  if (isset($postData['changepasswordsubmit'])) {
316  if (strlen($postData['password1']) < $minLength) {
317  $markerArray['###STATUS_MESSAGE###'] = sprintf($this->getDisplayText(
318  'change_password_tooshort_message',
319  $this->conf['changePasswordTooShortMessage_stdWrap.']),
320  $minLength
321  );
322  } elseif ($postData['password1'] != $postData['password2']) {
323  $markerArray['###STATUS_MESSAGE###'] = sprintf($this->getDisplayText(
324  'change_password_notequal_message',
325  $this->conf['changePasswordNotEqualMessage_stdWrap.']),
326  $minLength
327  );
328  } else {
329  $newPass = $postData['password1'];
330  if ($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['felogin']['password_changed']) {
331  $_params = array(
332  'user' => $user,
333  'newPassword' => $newPass
334  );
335  foreach ($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['felogin']['password_changed'] as $_funcRef) {
336  if ($_funcRef) {
337  GeneralUtility::callUserFunction($_funcRef, $_params, $this);
338  }
339  }
340  $newPass = $_params['newPassword'];
341  }
342  // Save new password and clear DB-hash
343  $res = $GLOBALS['TYPO3_DB']->exec_UPDATEquery(
344  'fe_users',
345  'uid=' . $user['uid'],
346  array('password' => $newPass, 'felogin_forgotHash' => '', 'tstamp' => $GLOBALS['EXEC_TIME'])
347  );
348  $markerArray['###STATUS_MESSAGE###'] = $this->getDisplayText(
349  'change_password_done_message',
350  $this->conf['changePasswordDoneMessage_stdWrap.']
351  );
352  $done = TRUE;
353  $subpartArray['###CHANGEPASSWORD_FORM###'] = '';
354  $markerArray['###BACKLINK_LOGIN###'] = $this->getPageLink(
355  $this->pi_getLL('ll_forgot_header_backToLogin', '', TRUE),
356  array($this->prefixId . '[redirectReferrer]' => 'off')
357  );
358  }
359  }
360  if (!$done) {
361  // Change password form
362  $markerArray['###ACTION_URI###'] = $this->getPageLink('', array(
363  $this->prefixId . '[user]' => $user['uid'],
364  $this->prefixId . '[forgothash]' => $piHash
365  ), TRUE);
366  $markerArray['###LEGEND###'] = $this->pi_getLL('change_password', '', TRUE);
367  $markerArray['###NEWPASSWORD1_LABEL###'] = $this->pi_getLL('newpassword_label1', '', TRUE);
368  $markerArray['###NEWPASSWORD2_LABEL###'] = $this->pi_getLL('newpassword_label2', '', TRUE);
369  $markerArray['###NEWPASSWORD1###'] = $this->prefixId . '[password1]';
370  $markerArray['###NEWPASSWORD2###'] = $this->prefixId . '[password2]';
371  $markerArray['###STORAGE_PID###'] = $this->spid;
372  $markerArray['###SEND_PASSWORD###'] = $this->pi_getLL('change_password', '', TRUE);
373  $markerArray['###FORGOTHASH###'] = $piHash;
374  }
375  }
376  }
377  return $this->cObj->substituteMarkerArrayCached($subpart, $markerArray, $subpartArray, $linkpartArray);
378  }
379 
386  protected function generateAndSendHash($user) {
387  $hours = (int)$this->conf['forgotLinkHashValidTime'] > 0 ? (int)$this->conf['forgotLinkHashValidTime'] : 24;
388  $validEnd = time() + 3600 * $hours;
389  $validEndString = date($this->conf['dateFormat'], $validEnd);
390  $hash = md5(GeneralUtility::generateRandomBytes(64));
391  $randHash = $validEnd . '|' . $hash;
392  $randHashDB = $validEnd . '|' . md5($hash);
393  // Write hash to DB
394  $res = $GLOBALS['TYPO3_DB']->exec_UPDATEquery('fe_users', 'uid=' . $user['uid'], array('felogin_forgotHash' => $randHashDB));
395  // Send hashlink to user
396  $this->conf['linkPrefix'] = -1;
397  $isAbsRelPrefix = !empty($GLOBALS['TSFE']->absRefPrefix);
398  $isBaseURL = !empty($GLOBALS['TSFE']->baseUrl);
399  $isFeloginBaseURL = !empty($this->conf['feloginBaseURL']);
400  $link = $this->pi_getPageLink($GLOBALS['TSFE']->id, '', array(
401  rawurlencode($this->prefixId . '[user]') => $user['uid'],
402  rawurlencode($this->prefixId . '[forgothash]') => $randHash
403  ));
404  // Prefix link if necessary
405  if ($isFeloginBaseURL) {
406  // First priority, use specific base URL
407  // "absRefPrefix" must be removed first, otherwise URL will be prepended twice
408  if (!empty($GLOBALS['TSFE']->absRefPrefix)) {
409  $link = substr($link, strlen($GLOBALS['TSFE']->absRefPrefix));
410  }
411  $link = $this->conf['feloginBaseURL'] . $link;
412  } elseif ($isAbsRelPrefix) {
413  // Second priority
414  // absRefPrefix must not necessarily contain a hostname and URL scheme, so add it if needed
415  $link = GeneralUtility::locationHeaderUrl($link);
416  } elseif ($isBaseURL) {
417  // Third priority
418  // Add the global base URL to the link
419  $link = $GLOBALS['TSFE']->baseUrlWrap($link);
420  } else {
421  // No prefix is set, return the error
422  return $this->pi_getLL('ll_change_password_nolinkprefix_message');
423  }
424  $msg = sprintf($this->pi_getLL('ll_forgot_validate_reset_password'), $user['username'], $link, $validEndString);
425  // Add hook for extra processing of mail message
426  if (
427  isset($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['felogin']['forgotPasswordMail'])
428  && is_array($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['felogin']['forgotPasswordMail'])
429  ) {
430  $params = array(
431  'message' => &$msg,
432  'user' => &$user
433  );
434  foreach ($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['felogin']['forgotPasswordMail'] as $reference) {
435  if ($reference) {
436  GeneralUtility::callUserFunction($reference, $params, $this);
437  }
438  }
439  }
440  // no RDCT - Links for security reasons
441  $oldSetting = $GLOBALS['TSFE']->config['config']['notification_email_urlmode'];
442  $GLOBALS['TSFE']->config['config']['notification_email_urlmode'] = 0;
443  // Send the email
444  $this->cObj->sendNotifyEmail($msg, $user['email'], '', $this->conf['email_from'], $this->conf['email_fromName'], $this->conf['replyTo']);
445  // Restore settings
446  $GLOBALS['TSFE']->config['config']['notification_email_urlmode'] = $oldSetting;
447  return '';
448  }
449 
455  protected function showLogout() {
456  $subpart = $this->cObj->getSubpart($this->template, '###TEMPLATE_LOGOUT###');
457  $subpartArray = ($linkpartArray = array());
458  $markerArray['###STATUS_HEADER###'] = $this->getDisplayText('status_header', $this->conf['logoutHeader_stdWrap.']);
459  $markerArray['###STATUS_MESSAGE###'] = $this->getDisplayText('status_message', $this->conf['logoutMessage_stdWrap.']);
460  $this->cObj->stdWrap($this->flexFormValue('message', 's_status'), $this->conf['logoutMessage_stdWrap.']);
461  $markerArray['###LEGEND###'] = $this->pi_getLL('logout', '', TRUE);
462  $markerArray['###ACTION_URI###'] = $this->getPageLink('', array(), TRUE);
463  $markerArray['###LOGOUT_LABEL###'] = $this->pi_getLL('logout', '', TRUE);
464  $markerArray['###NAME###'] = htmlspecialchars($GLOBALS['TSFE']->fe_user->user['name']);
465  $markerArray['###STORAGE_PID###'] = $this->spid;
466  $markerArray['###USERNAME###'] = htmlspecialchars($GLOBALS['TSFE']->fe_user->user['username']);
467  $markerArray['###USERNAME_LABEL###'] = $this->pi_getLL('username', '', TRUE);
468  $markerArray['###NOREDIRECT###'] = $this->noRedirect ? '1' : '0';
469  $markerArray['###PREFIXID###'] = $this->prefixId;
470  $markerArray = array_merge($markerArray, $this->getUserFieldMarkers());
471  if ($this->redirectUrl) {
472  // Use redirectUrl for action tag because of possible access restricted pages
473  $markerArray['###ACTION_URI###'] = htmlspecialchars($this->redirectUrl);
474  $this->redirectUrl = '';
475  }
476  return $this->cObj->substituteMarkerArrayCached($subpart, $markerArray, $subpartArray, $linkpartArray);
477  }
478 
484  protected function showLogin() {
485  $subpart = $this->cObj->getSubpart($this->template, '###TEMPLATE_LOGIN###');
486  $subpartArray = ($linkpartArray = ($markerArray = array()));
487  $gpRedirectUrl = '';
488  $markerArray['###LEGEND###'] = $this->pi_getLL('oLabel_header_welcome', '', TRUE);
489  if ($this->logintype === 'login') {
490  if ($this->userIsLoggedIn) {
491  // login success
492  $markerArray['###STATUS_HEADER###'] = $this->getDisplayText('success_header', $this->conf['successHeader_stdWrap.']);
493  $markerArray['###STATUS_MESSAGE###'] = $this->getDisplayText('success_message', $this->conf['successMessage_stdWrap.']);
494  $markerArray = array_merge($markerArray, $this->getUserFieldMarkers());
495  $subpartArray['###LOGIN_FORM###'] = '';
496  // Hook for general actions after after login has been confirmed (by Thomas Danzl <thomas@danzl.org>)
497  if ($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['felogin']['login_confirmed']) {
498  $_params = array();
499  foreach ($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['felogin']['login_confirmed'] as $_funcRef) {
500  if ($_funcRef) {
501  GeneralUtility::callUserFunction($_funcRef, $_params, $this);
502  }
503  }
504  }
505  // show logout form directly
506  if ($this->conf['showLogoutFormAfterLogin']) {
507  $this->redirectUrl = '';
508  return $this->showLogout();
509  }
510  } else {
511  // Hook for general actions on login error
512  if (
513  isset($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['felogin']['login_error'])
514  && is_array($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['felogin']['login_error'])
515  ) {
516  $params = array();
517  foreach ($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['felogin']['login_error'] as $funcRef) {
518  if ($funcRef) {
519  GeneralUtility::callUserFunction($funcRef, $params, $this);
520  }
521  }
522  }
523  // login error
524  $markerArray['###STATUS_HEADER###'] = $this->getDisplayText('error_header', $this->conf['errorHeader_stdWrap.']);
525  $markerArray['###STATUS_MESSAGE###'] = $this->getDisplayText('error_message', $this->conf['errorMessage_stdWrap.']);
526  $gpRedirectUrl = GeneralUtility::_GP('redirect_url');
527  }
528  } else {
529  if ($this->logintype === 'logout') {
530  // login form after logout
531  $markerArray['###STATUS_HEADER###'] = $this->getDisplayText('logout_header', $this->conf['logoutHeader_stdWrap.']);
532  $markerArray['###STATUS_MESSAGE###'] = $this->getDisplayText('logout_message', $this->conf['logoutMessage_stdWrap.']);
533  } else {
534  // login form
535  $markerArray['###STATUS_HEADER###'] = $this->getDisplayText('welcome_header', $this->conf['welcomeHeader_stdWrap.']);
536  $markerArray['###STATUS_MESSAGE###'] = $this->getDisplayText('welcome_message', $this->conf['welcomeMessage_stdWrap.']);
537  }
538  }
539 
540  // This hook allows to call User JS functions.
541  // The methods should also set the required JS functions to get included
542  $onSubmit = '';
543  $extraHidden = '';
544  $onSubmitAr = array();
545  $extraHiddenAr = array();
546  // Check for referer redirect method. if present, save referer in form field
547  if (GeneralUtility::inList($this->conf['redirectMode'], 'referer') || GeneralUtility::inList($this->conf['redirectMode'], 'refererDomains')) {
548  $referer = $this->referer ? $this->referer : GeneralUtility::getIndpEnv('HTTP_REFERER');
549  if ($referer) {
550  $extraHiddenAr[] = '<input type="hidden" name="referer" value="' . htmlspecialchars($referer) . '" />';
551  if ($this->piVars['redirectReferrer'] === 'off') {
552  $extraHiddenAr[] = '<input type="hidden" name="' . $this->prefixId . '[redirectReferrer]" value="off" />';
553  }
554  }
555  }
556  if (is_array($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['felogin']['loginFormOnSubmitFuncs'])) {
557  $_params = array();
558  foreach ($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['felogin']['loginFormOnSubmitFuncs'] as $funcRef) {
559  list($onSub, $hid) = GeneralUtility::callUserFunction($funcRef, $_params, $this);
560  $onSubmitAr[] = $onSub;
561  $extraHiddenAr[] = $hid;
562  }
563  }
564  if (count($onSubmitAr)) {
565  $onSubmit = implode('; ', $onSubmitAr) . '; return true;';
566  }
567  if (count($extraHiddenAr)) {
568  $extraHidden = implode(LF, $extraHiddenAr);
569  }
570  if (!$gpRedirectUrl && $this->redirectUrl) {
571  $gpRedirectUrl = $this->redirectUrl;
572  }
573  // Login form
574  $markerArray['###ACTION_URI###'] = $this->getPageLink('', array(), TRUE);
575  // Used by kb_md5fepw extension...
576  $markerArray['###EXTRA_HIDDEN###'] = $extraHidden;
577  $markerArray['###LEGEND###'] = $this->pi_getLL('login', '', TRUE);
578  $markerArray['###LOGIN_LABEL###'] = $this->pi_getLL('login', '', TRUE);
579  // Used by kb_md5fepw extension...
580  $markerArray['###ON_SUBMIT###'] = $onSubmit;
581  $markerArray['###PASSWORD_LABEL###'] = $this->pi_getLL('password', '', TRUE);
582  $markerArray['###STORAGE_PID###'] = $this->spid;
583  $markerArray['###USERNAME_LABEL###'] = $this->pi_getLL('username', '', TRUE);
584  $markerArray['###REDIRECT_URL###'] = htmlspecialchars($gpRedirectUrl);
585  $markerArray['###NOREDIRECT###'] = $this->noRedirect ? '1' : '0';
586  $markerArray['###PREFIXID###'] = $this->prefixId;
587  $markerArray = array_merge($markerArray, $this->getUserFieldMarkers());
588  if ($this->conf['showForgotPasswordLink']) {
589  $linkpartArray['###FORGOT_PASSWORD_LINK###'] = explode('|', $this->getPageLink('|', array($this->prefixId . '[forgot]' => 1)));
590  $markerArray['###FORGOT_PASSWORD###'] = $this->pi_getLL('ll_forgot_header', '', TRUE);
591  } else {
592  $subpartArray['###FORGOTP_VALID###'] = '';
593  }
594  // The permanent login checkbox should only be shown if permalogin is not deactivated (-1),
595  // not forced to be always active (2) and lifetime is greater than 0
596  if (
597  $this->conf['showPermaLogin']
598  && GeneralUtility::inList('0,1', $GLOBALS['TYPO3_CONF_VARS']['FE']['permalogin'])
599  && $GLOBALS['TYPO3_CONF_VARS']['FE']['lifetime'] > 0
600  ) {
601  $markerArray['###PERMALOGIN###'] = $this->pi_getLL('permalogin', '', TRUE);
602  if ($GLOBALS['TYPO3_CONF_VARS']['FE']['permalogin'] == 1) {
603  $markerArray['###PERMALOGIN_HIDDENFIELD_ATTRIBUTES###'] = 'disabled="disabled"';
604  $markerArray['###PERMALOGIN_CHECKBOX_ATTRIBUTES###'] = 'checked="checked"';
605  } else {
606  $markerArray['###PERMALOGIN_HIDDENFIELD_ATTRIBUTES###'] = '';
607  $markerArray['###PERMALOGIN_CHECKBOX_ATTRIBUTES###'] = '';
608  }
609  } else {
610  $subpartArray['###PERMALOGIN_VALID###'] = '';
611  }
612  return $this->cObj->substituteMarkerArrayCached($subpart, $markerArray, $subpartArray, $linkpartArray);
613  }
614 
620  protected function processRedirect() {
621  $redirect_url = array();
622  if ($this->conf['redirectMode']) {
623  $redirectMethods = GeneralUtility::trimExplode(',', $this->conf['redirectMode'], TRUE);
624  foreach ($redirectMethods as $redirMethod) {
625  if ($GLOBALS['TSFE']->loginUser && $this->logintype === 'login') {
626  // Logintype is needed because the login-page wouldn't be accessible anymore after a login (would always redirect)
627  switch ($redirMethod) {
628  case 'groupLogin':
629  // taken from dkd_redirect_at_login written by Ingmar Schlecht; database-field changed
630  $groupData = $GLOBALS['TSFE']->fe_user->groupData;
631  if (!empty($groupData['uid'])) {
632  // take the first group with a redirect page
633  $row = $GLOBALS['TYPO3_DB']->exec_SELECTgetSingleRow(
634  'felogin_redirectPid',
635  $GLOBALS['TSFE']->fe_user->usergroup_table,
636  'felogin_redirectPid<>\'\' AND uid IN (' . implode(',', $groupData['uid']) . ')'
637  );
638  if ($row) {
639  $redirect_url[] = $this->pi_getPageLink($row['felogin_redirectPid']);
640  }
641  }
642  break;
643  case 'userLogin':
644  $row = $GLOBALS['TYPO3_DB']->exec_SELECTgetSingleRow(
645  'felogin_redirectPid',
646  $GLOBALS['TSFE']->fe_user->user_table,
647  $GLOBALS['TSFE']->fe_user->userid_column . '=' . $GLOBALS['TSFE']->fe_user->user['uid'] . ' AND felogin_redirectPid<>\'\''
648  );
649  if ($row) {
650  $redirect_url[] = $this->pi_getPageLink($row['felogin_redirectPid']);
651  }
652  break;
653  case 'login':
654  if ($this->conf['redirectPageLogin']) {
655  $redirect_url[] = $this->pi_getPageLink((int)$this->conf['redirectPageLogin']);
656  }
657  break;
658  case 'getpost':
659  $redirect_url[] = $this->redirectUrl;
660  break;
661  case 'referer':
662  // Avoid redirect when logging in after changing password
663  if ($this->piVars['redirectReferrer'] !== 'off') {
664  // Avoid forced logout, when trying to login immediately after a logout
665  $redirect_url[] = preg_replace('/[&?]logintype=[a-z]+/', '', $this->referer);
666  }
667  break;
668  case 'refererDomains':
669  // Auto redirect.
670  // Feature to redirect to the page where the user came from (HTTP_REFERER).
671  // Allowed domains to redirect to, can be configured with plugin.tx_felogin_pi1.domains
672  // Thanks to plan2.net / Martin Kutschker for implementing this feature.
673  // also avoid redirect when logging in after changing password
674  if ($this->conf['domains'] && $this->piVars['redirectReferrer'] !== 'off') {
675  $url = $this->referer;
676  // Is referring url allowed to redirect?
677  $match = array();
678  if (preg_match('#^http://([[:alnum:]._-]+)/#', $url, $match)) {
679  $redirect_domain = $match[1];
680  $found = FALSE;
681  foreach (GeneralUtility::trimExplode(',', $this->conf['domains'], TRUE) as $d) {
682  if (preg_match('/(?:^|\\.)' . $d . '$/', $redirect_domain)) {
683  $found = TRUE;
684  break;
685  }
686  }
687  if (!$found) {
688  $url = '';
689  }
690  }
691  // Avoid forced logout, when trying to login immediately after a logout
692  if ($url) {
693  $redirect_url[] = preg_replace('/[&?]logintype=[a-z]+/', '', $url);
694  }
695  }
696  break;
697  }
698  } elseif ($this->logintype === 'login') {
699  // after login-error
700  switch ($redirMethod) {
701  case 'loginError':
702  if ($this->conf['redirectPageLoginError']) {
703  $redirect_url[] = $this->pi_getPageLink((int)$this->conf['redirectPageLoginError']);
704  }
705  break;
706  }
707  } elseif ($this->logintype == '' && $redirMethod == 'login' && $this->conf['redirectPageLogin']) {
708  // If login and page not accessible
709  $this->cObj->typolink('', array(
710  'parameter' => $this->conf['redirectPageLogin'],
711  'linkAccessRestrictedPages' => TRUE
712  ));
713  $redirect_url[] = $this->cObj->lastTypoLinkUrl;
714  } elseif ($this->logintype == '' && $redirMethod == 'logout' && $this->conf['redirectPageLogout'] && $GLOBALS['TSFE']->loginUser) {
715  // If logout and page not accessible
716  $redirect_url[] = $this->pi_getPageLink((int)$this->conf['redirectPageLogout']);
717  } elseif ($this->logintype === 'logout') {
718  // after logout
719  // Hook for general actions after after logout has been confirmed
720  if ($this->logintype === 'logout' && $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['felogin']['logout_confirmed']) {
721  $_params = array();
722  foreach ($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['felogin']['logout_confirmed'] as $_funcRef) {
723  if ($_funcRef) {
724  GeneralUtility::callUserFunction($_funcRef, $_params, $this);
725  }
726  }
727  }
728  switch ($redirMethod) {
729  case 'logout':
730  if ($this->conf['redirectPageLogout']) {
731  $redirect_url[] = $this->pi_getPageLink((int)$this->conf['redirectPageLogout']);
732  }
733  break;
734  }
735  } else {
736  // not logged in
737  // Placeholder for maybe future options
738  switch ($redirMethod) {
739  case 'getpost':
740  // Preserve the get/post value
741  $redirect_url[] = $this->redirectUrl;
742  break;
743  }
744  }
745  }
746  }
747  // Remove empty values
748  if (count($redirect_url)) {
749  return GeneralUtility::trimExplode(',', implode(',', $redirect_url), TRUE);
750  } else {
751  return array();
752  }
753  }
754 
760  protected function mergeflexFormValuesIntoConf() {
761  $flex = array();
762  if ($this->flexFormValue('showForgotPassword', 'sDEF')) {
763  $flex['showForgotPasswordLink'] = $this->flexFormValue('showForgotPassword', 'sDEF');
764  }
765  if ($this->flexFormValue('showPermaLogin', 'sDEF')) {
766  $flex['showPermaLogin'] = $this->flexFormValue('showPermaLogin', 'sDEF');
767  }
768  if ($this->flexFormValue('showLogoutFormAfterLogin', 'sDEF')) {
769  $flex['showLogoutFormAfterLogin'] = $this->flexFormValue('showLogoutFormAfterLogin', 'sDEF');
770  }
771  if ($this->flexFormValue('pages', 'sDEF')) {
772  $flex['pages'] = $this->flexFormValue('pages', 'sDEF');
773  }
774  if ($this->flexFormValue('recursive', 'sDEF')) {
775  $flex['recursive'] = $this->flexFormValue('recursive', 'sDEF');
776  }
777  if ($this->flexFormValue('templateFile', 'sDEF')) {
778  $flex['templateFile'] = $this->uploadDir . $this->flexFormValue('templateFile', 'sDEF');
779  }
780  if ($this->flexFormValue('redirectMode', 's_redirect')) {
781  $flex['redirectMode'] = $this->flexFormValue('redirectMode', 's_redirect');
782  }
783  if ($this->flexFormValue('redirectFirstMethod', 's_redirect')) {
784  $flex['redirectFirstMethod'] = $this->flexFormValue('redirectFirstMethod', 's_redirect');
785  }
786  if ($this->flexFormValue('redirectDisable', 's_redirect')) {
787  $flex['redirectDisable'] = $this->flexFormValue('redirectDisable', 's_redirect');
788  }
789  if ($this->flexFormValue('redirectPageLogin', 's_redirect')) {
790  $flex['redirectPageLogin'] = $this->flexFormValue('redirectPageLogin', 's_redirect');
791  }
792  if ($this->flexFormValue('redirectPageLoginError', 's_redirect')) {
793  $flex['redirectPageLoginError'] = $this->flexFormValue('redirectPageLoginError', 's_redirect');
794  }
795  if ($this->flexFormValue('redirectPageLogout', 's_redirect')) {
796  $flex['redirectPageLogout'] = $this->flexFormValue('redirectPageLogout', 's_redirect');
797  }
798  $pid = $flex['pages'] ? $this->pi_getPidList($flex['pages'], $flex['recursive']) : 0;
799  if ($pid > 0) {
800  $flex['storagePid'] = $pid;
801  }
802  $this->conf = array_merge($this->conf, $flex);
803  }
804 
812  protected function flexFormValue($var, $sheet) {
813  return $this->pi_getFFvalue($this->cObj->data['pi_flexform'], $var, $sheet);
814  }
815 
824  protected function getPageLink($label, $piVars, $returnUrl = FALSE) {
825  $additionalParams = '';
826  if (count($piVars)) {
827  foreach ($piVars as $key => $val) {
828  $additionalParams .= '&' . $key . '=' . $val;
829  }
830  }
831  // Should GETvars be preserved?
832  if ($this->conf['preserveGETvars']) {
833  $additionalParams .= $this->getPreserveGetVars();
834  }
835  $this->conf['linkConfig.']['parameter'] = $GLOBALS['TSFE']->id;
836  if ($additionalParams) {
837  $this->conf['linkConfig.']['additionalParams'] = $additionalParams;
838  }
839  if ($returnUrl) {
840  return htmlspecialchars($this->cObj->typolink_url($this->conf['linkConfig.']));
841  } else {
842  return $this->cObj->typolink($label, $this->conf['linkConfig.']);
843  }
844  }
845 
854  protected function getPreserveGetVars() {
855  $getVars = GeneralUtility::_GET();
856  unset(
857  $getVars['id'],
858  $getVars['no_cache'],
859  $getVars['logintype'],
860  $getVars['redirect_url'],
861  $getVars['cHash'],
862  $getVars[$this->prefixId]
863  );
864  if ($this->conf['preserveGETvars'] === 'all') {
865  $preserveQueryParts = $getVars;
866  } else {
867  $preserveQueryParts = GeneralUtility::trimExplode(',', $this->conf['preserveGETvars']);
868  $preserveQueryParts = GeneralUtility::explodeUrl2Array(implode('=1&', $preserveQueryParts) . '=1', TRUE);
869  $preserveQueryParts = \TYPO3\CMS\Core\Utility\ArrayUtility::intersectRecursive($getVars, $preserveQueryParts);
870  }
871  $parameters = GeneralUtility::implodeArrayForUrl('', $preserveQueryParts);
872  return $parameters;
873  }
874 
882  protected function generatePassword($len) {
883  $pass = '';
884  while ($len--) {
885  $char = rand(0, 35);
886  if ($char < 10) {
887  $pass .= '' . $char;
888  } else {
889  $pass .= chr($char - 10 + 97);
890  }
891  }
892  return $pass;
893  }
894 
902  protected function getDisplayText($label, $stdWrapArray = array()) {
903  $text = $this->flexFormValue($label, 's_messages') ? $this->cObj->stdWrap($this->flexFormValue($label, 's_messages'), $stdWrapArray) : $this->cObj->stdWrap($this->pi_getLL('ll_' . $label), $stdWrapArray);
904  $replace = $this->getUserFieldMarkers();
905  return strtr($text, $replace);
906  }
907 
913  protected function getUserFieldMarkers() {
914  $marker = array();
915  // replace markers with fe_user data
916  if ($GLOBALS['TSFE']->fe_user->user) {
917  // All fields of fe_user will be replaced, scheme is ###FEUSER_FIELDNAME###
918  foreach ($GLOBALS['TSFE']->fe_user->user as $field => $value) {
919  $marker['###FEUSER_' . GeneralUtility::strtoupper($field) . '###'] = $this->cObj->stdWrap($value, $this->conf['userfields.'][$field . '.']);
920  }
921  // Add ###USER### for compatibility
922  $marker['###USER###'] = $marker['###FEUSER_USERNAME###'];
923  }
924  return $marker;
925  }
926 
933  protected function validateRedirectUrl($url) {
934  $url = strval($url);
935  if ($url === '') {
936  return '';
937  }
938  $decodedUrl = rawurldecode($url);
939  $sanitizedUrl = GeneralUtility::removeXSS($decodedUrl);
940  if ($decodedUrl !== $sanitizedUrl || preg_match('#["<>\\\\]+#', $url)) {
941  GeneralUtility::sysLog(sprintf($this->pi_getLL('xssAttackDetected'), $url), 'felogin', GeneralUtility::SYSLOG_SEVERITY_WARNING);
942  return '';
943  }
944  // Validate the URL:
945  if ($this->isRelativeUrl($url) || $this->isInCurrentDomain($url) || $this->isInLocalDomain($url)) {
946  return $url;
947  }
948  // URL is not allowed
949  GeneralUtility::sysLog(sprintf($this->pi_getLL('noValidRedirectUrl'), $url), 'felogin', GeneralUtility::SYSLOG_SEVERITY_WARNING);
950  return '';
951  }
952 
960  protected function isInCurrentDomain($url) {
961  $urlWithoutSchema = preg_replace('#^https?://#', '', $url);
962  $siteUrlWithoutSchema = preg_replace('#^https?://#', '', GeneralUtility::getIndpEnv('TYPO3_SITE_URL'));
963  return GeneralUtility::isFirstPartOfStr($urlWithoutSchema . '/', GeneralUtility::getIndpEnv('HTTP_HOST') . '/')
964  && GeneralUtility::isFirstPartOfStr($urlWithoutSchema, $siteUrlWithoutSchema);
965  }
966 
974  protected function isInLocalDomain($url) {
975  $result = FALSE;
976  if (GeneralUtility::isValidUrl($url)) {
977  $parsedUrl = parse_url($url);
978  if ($parsedUrl['scheme'] === 'http' || $parsedUrl['scheme'] === 'https') {
979  $host = $parsedUrl['host'];
980  // Removes the last path segment and slash sequences like /// (if given):
981  $path = preg_replace('#/+[^/]*$#', '', $parsedUrl['path']);
982  $localDomains = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows('domainName', 'sys_domain', '1=1' . $this->cObj->enableFields('sys_domain'));
983  if (is_array($localDomains)) {
984  foreach ($localDomains as $localDomain) {
985  // strip trailing slashes (if given)
986  $domainName = rtrim($localDomain['domainName'], '/');
987  if (GeneralUtility::isFirstPartOfStr($host . $path . '/', $domainName . '/')) {
988  $result = TRUE;
989  break;
990  }
991  }
992  }
993  }
994  }
995  return $result;
996  }
997 
1005  protected function isRelativeUrl($url) {
1006  $parsedUrl = @parse_url($url);
1007  if ($parsedUrl !== FALSE && !isset($parsedUrl['scheme']) && !isset($parsedUrl['host'])) {
1008  // If the relative URL starts with a slash, we need to check if it's within the current site path
1009  return $parsedUrl['path'][0] !== '/' || GeneralUtility::isFirstPartOfStr($parsedUrl['path'], GeneralUtility::getIndpEnv('TYPO3_SITE_PATH'));
1010  }
1011  return FALSE;
1012  }
1013 
1014 }
pi_getFFvalue($T3FlexForm_array, $fieldName, $sheet='sDEF', $lang='lDEF', $value='vDEF')
static explodeUrl2Array($string, $multidim=FALSE)
$parameters
Definition: FileDumpEID.php:15
static isFirstPartOfStr($str, $partStr)
pi_getRecord($table, $uid, $checkPage=0)
$uid
Definition: server.php:36
static generateRandomBytes($bytesToReturn)
static trimExplode($delim, $string, $removeEmptyValues=FALSE, $limit=0)
static callUserFunction($funcName, &$params, &$ref, $checkPrefix='', $errorMode=0)
if($list_of_literals) if(!empty($literals)) if(!empty($literals)) $result
Analyse literals to prepend the N char to them if their contents aren&#39;t numeric.
$host
Definition: server.php:35
pi_getLL($key, $alternativeLabel='', $hsc=FALSE)
pi_getPageLink($id, $target='', $urlParameters=array())
static intersectRecursive(array $source, array $mask=array())
static implodeArrayForUrl($name, array $theArray, $str='', $skipBlank=FALSE, $rawurlencodeParamName=FALSE)
static redirect($url, $httpStatus=self::HTTP_STATUS_303)
Definition: HttpUtility.php:76
if(!defined('TYPO3_MODE')) $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_userauth.php']['logoff_pre_processing'][]