b2evolution PHP Cross Reference Blogging Systems

Source: /htsrv/login.php - 588 lines - 20978 bytes - Summary - Text - Print

Description: This is the login screen. It also handles actions related to loggin in and registering. This file is part of the evoCore framework - {@link http://evocore.net/} See also {@link http://sourceforge.net/projects/evocms/}.

   1  <?php
   2  /**
   3   * This is the login screen. It also handles actions related to loggin in and registering.
   4   *
   5   * This file is part of the evoCore framework - {@link http://evocore.net/}
   6   * See also {@link http://sourceforge.net/projects/evocms/}.
   7   *
   8   * @copyright (c)2003-2014 by Francois Planque - {@link http://fplanque.com/}
   9   * Parts of this file are copyright (c)2004-2006 by Daniel HAHLER - {@link http://thequod.de/contact}.
  10   *
  11   * {@internal License choice
  12   * - If you have received this file as part of a package, please find the license.txt file in
  13   *   the same folder or the closest folder above for complete license terms.
  14   * - If you have received this file individually (e-g: from http://evocms.cvs.sourceforge.net/)
  15   *   then you must choose one of the following licenses before using the file:
  16   *   - GNU General Public License 2 (GPL) - http://www.opensource.org/licenses/gpl-license.php
  17   *   - Mozilla Public License 1.1 (MPL) - http://www.opensource.org/licenses/mozilla1.1.php
  18   * }}
  19   *
  20   * {@internal Open Source relicensing agreement:
  21   * Daniel HAHLER grants Francois PLANQUE the right to license
  22   * Daniel HAHLER's contributions to this file and the b2evolution project
  23   * under any OSI approved OSS license (http://www.opensource.org/licenses/).
  24   *
  25   * Matt FOLLETT grants Francois PLANQUE the right to license
  26   * Matt FOLLETT's contributions to this file and the b2evolution project
  27   * under any OSI approved OSS license (http://www.opensource.org/licenses/).
  28   * }}
  29   *
  30   * @package htsrv
  31   *
  32   * @version $Id: login.php 6136 2014-03-08 07:59:48Z manuel $
  33   */
  34  
  35  /**
  36   * Includes:
  37   */
  38  require_once dirname(__FILE__).'/../conf/_config.php';
  39  require_once $inc_path.'_main.inc.php';
  40  
  41  $login = param( $dummy_fields[ 'login' ], 'string', '' );
  42  param( 'action', 'string', 'req_login' );
  43  param( 'mode', 'string', '' );
  44  param( 'inskin', 'boolean', false );
  45  if( $inskin )
  46  {
  47      param( 'blog', 'integer', NULL );
  48  }
  49  
  50  // gets used by header_redirect();
  51  param( 'redirect_to', 'url', $ReqURI );
  52  
  53  switch( $action )
  54  {
  55      case 'logout':
  56          logout();          // logout $Session and set $current_User = NULL
  57  
  58          // TODO: to give the user feedback through Messages, we would need to start a new $Session here and append $Messages to it.
  59  
  60          // Redirect to $baseurl on logout if redirect URI is not set. Temporarily fix until we remove actions from redirect URIs
  61          if( $redirect_to == $ReqURI )
  62          {
  63              $redirect_to = $baseurl;
  64          }
  65  
  66          header_redirect(); // defaults to redirect_to param and exits
  67          /* exited */
  68          break;
  69  
  70      case 'closeaccount': // close user account and log out
  71          global $Session, $Messages, $UserSettings;
  72          $Session->assert_received_crumb( 'closeaccountform' );
  73  
  74          if( is_logged_in() && $current_User->update_status_from_Request( true, 'closed' ) )
  75          { // user account was closed successful
  76              // Send notification email about closed account to users with edit users permission
  77              $email_template_params = array(
  78                      'login'   => $current_User->login,
  79                      'email'   => $current_User->email,
  80                      'reason'  => param( 'account_close_reason', 'text', '' ),
  81                      'user_ID' => $current_User->ID,
  82                  );
  83              send_admin_notification( NT_('User account closed'), 'account_closed', $email_template_params );
  84  
  85              // log out current User
  86              logout();
  87          }
  88          else
  89          { // db update was unsuccessful
  90              $Messages->add( T_( 'Unable to close your account. Please contact to system administrator.' ) );
  91          }
  92  
  93          header_redirect();
  94          /* exited */
  95          break;
  96  
  97      case 'retrievepassword': // Send password change request by mail
  98          global $servertimenow;
  99          $login_required = true; // Do not display "Without login.." link on the form
 100  
 101          $request_ts_login = $Session->get( 'core.changepwd.request_ts_login' );
 102          if( $request_ts_login != NULL )
 103          {
 104              list( $last_request_ts, $last_request_login ) = preg_split( '~_~', $request_ts_login );
 105              if( ( $login == $last_request_login ) && ( ( $servertimenow - $pwdchange_request_delay ) < $last_request_ts ) )
 106              { // the same request was sent from the same session in the last $pwdchange_request_delay seconds ( 5 minutes by default )
 107                  $Messages->add( sprintf( T_('We have already sent you a password recovery email at %s. Please allow %d minutes for delivery before requesting a new one.' ), date( locale_datetimefmt(), $last_request_ts ), $pwdchange_request_delay / 60 ) );
 108                  $action = 'req_login';
 109                  break;
 110              }
 111          }
 112  
 113          $UserCache = & get_UserCache();
 114          $UserCache->clear();
 115          if( is_email( $login ) )
 116          { // user gave an email, get users by email
 117              $only_activated = false;
 118              // load all not closed users with this email address
 119              $UserCache->load_where( 'user_email = "'.$login.'" && user_status <> "closed"' );
 120  
 121              $not_activated_Ids = array();
 122              while( ( $iterator_User = & $UserCache->get_next() ) != NULL )
 123              { // Iterate through UserCache
 124                  if( $iterator_User->check_status( 'is_validated' ) )
 125                  {
 126                      $only_activated = true;
 127                  }
 128                  else
 129                  { // strore not activated user Ids for further use
 130                      $not_activated_Ids[] = $iterator_User->ID;
 131                  }
 132              }
 133  
 134              // if we have activated users then remove every not activated from the cache
 135              if( $only_activated && ( !empty( $not_activated_Ids ) ) )
 136              {
 137                  foreach( $not_activated_Ids as $not_activated_Id )
 138                  {
 139                      $UserCache->remove_by_ID( $not_activated_Id );
 140                  }
 141              }
 142  
 143              $UserCache->rewind();
 144              $forgetful_User = & $UserCache->get_next();
 145              $UserCache->rewind();
 146          }
 147          else
 148          { // get user by login
 149              $forgetful_User = & $UserCache->get_by_login( $login );
 150          }
 151  
 152          if( ! $forgetful_User )
 153          { // User does not exist
 154              // pretend that the email is sent for avoiding guessing user_login
 155              $Messages->add( T_('If you correctly entered your login or email address, a link to change your password has been sent to your registered email address.' ), 'success' );
 156              $action = 'req_login';
 157              break;
 158          }
 159  
 160          // echo 'email: ', $forgetful_User->email;
 161          // echo 'locale: '.$forgetful_User->locale;
 162  
 163          if( $demo_mode && ($forgetful_User->ID <= 3) )
 164          {
 165              $Messages->add( T_('You cannot reset this account in demo mode.'), 'error' );
 166              $action = 'req_login';
 167              break;
 168          }
 169  
 170          locale_temp_switch( $forgetful_User->locale );
 171  
 172          // DEBUG!
 173          // echo $message.' (password not set yet, only when sending email does not fail);
 174  
 175          if( empty( $forgetful_User->email ) )
 176          {
 177              $Messages->add( T_('You have no email address with your profile, therefore we cannot reset your password.')
 178                  .' '.T_('Please try contacting the admin.'), 'error' );
 179          }
 180          else
 181          {
 182              $request_id = generate_random_key(22); // 22 to make it not too long for URL but unique/safe enough
 183  
 184              // Count how many users match to this login ( It can be more then one in case of email login )
 185              $user_ids = $UserCache->get_ID_array();
 186              $user_count = count( $user_ids );
 187  
 188              // Set blog param for email link
 189              $blog_param = '';
 190              if( !empty( $blog ) )
 191              {
 192                  $blog_param = '&inskin=true&blog='.$blog;
 193              }
 194  
 195              $subject = sprintf( T_( 'Password change request for %s' ), $login );
 196              $email_template_params = array(
 197                      'user_count'     => $user_count,
 198                      'request_id'     => $request_id,
 199                      'blog_param'     => $blog_param,
 200                  );
 201  
 202              if( ! send_mail_to_User( $forgetful_User->ID, $subject, 'account_password_reset', $email_template_params, true ) )
 203              {
 204                  $Messages->add( T_('Sorry, the email with the link to reset your password could not be sent.')
 205                      .'<br />'.T_('Possible reason: the PHP mail() function may have been disabled on the server.'), 'error' );
 206              }
 207              else
 208              {
 209                  $Session->set( 'core.changepwd.request_id', $request_id, 86400 * 2 ); // expires in two days (or when clicked)
 210                  $Session->set( 'core.changepwd.request_ts_login', $servertimenow.'_'.$login, 360 ); // request timestamp and login/email - expires in six minutes
 211                  $Session->dbsave(); // save immediately
 212  
 213                  $Messages->add( T_('If you correctly entered your login or email address, a link to change your password has been sent to your registered email address.' ), 'success' );
 214              }
 215          }
 216  
 217          locale_restore_previous();
 218  
 219          $action = 'req_login';
 220          break;
 221  
 222  
 223      case 'changepwd': // Clicked "Change password request" link from a mail
 224          param( 'reqID', 'string', '' );
 225          param( 'sessID', 'integer', '' );
 226  
 227          $UserCache = & get_UserCache();
 228          $forgetful_User = & $UserCache->get_by_login($login);
 229  
 230          locale_temp_switch( $forgetful_User->locale );
 231  
 232          if( ! $forgetful_User || empty($reqID) )
 233          { // This was not requested
 234              $Messages->add( T_('Invalid password change request! Please try again...'), 'error' );
 235              $action = 'lostpassword';
 236              $login_required = true; // Do not display "Without login.." link on the form
 237              break;
 238          }
 239  
 240          if( $sessID != $Session->ID )
 241          { // Another session ID than for requesting password change link used!
 242              $Messages->add( T_('You have to use the same session (by means of your session cookie) as when you have requested the action. Please try again...'), 'error' );
 243              $action = 'lostpassword';
 244              $login_required = true; // Do not display "Without login.." link on the form
 245              break;
 246          }
 247  
 248          // Validate provided reqID against the one stored in the user's session
 249          if( $Session->get( 'core.changepwd.request_id' ) != $reqID )
 250          {
 251              $Messages->add( T_('Invalid password change request! Please try again...'), 'error' );
 252              $action = 'lostpassword';
 253              $login_required = true; // Do not display "Without login.." link on the form
 254              break;
 255          }
 256  
 257          // Link User to Session:
 258          $Session->set_user_ID( $forgetful_User->ID );
 259  
 260          // Add Message to change the password:
 261          $Messages->add( T_( 'Please change your password to something you remember now.' ), 'success' );
 262  
 263          // Note: the 'core.changepwd.request_id' Session setting gets removed in b2users.php
 264  
 265          // Redirect to the user's change password tab
 266          $changepwd_url = NULL;
 267          if( !empty( $blog ) )
 268          { // blog is set, redirect to in-skin change password form
 269              $BlogCache = & get_BlogCache();
 270              $Blog = $BlogCache->get_by_ID( $blog );
 271              if( $Blog )
 272              {
 273                  $changepwd_url = url_add_param( $Blog->gen_blogurl(), 'disp=pwdchange&reqID='.$reqID );
 274              }
 275          }
 276          if( empty( $changepwd_url ) )
 277          { // redirect to admin change password form
 278              $changepwd_url = url_add_param( $admin_url, 'ctrl=user&user_tab=pwdchange&user_ID='.$forgetful_User->ID.'&reqID='.$reqID, '&' );
 279          }
 280  
 281          locale_restore_previous();
 282  
 283          // redirect Will save $Messages into Session:
 284          header_redirect( $changepwd_url ); // display user's change password tab
 285          /* exited */
 286          break;
 287  
 288  
 289      case 'activateaccount': // Clicked to activate account link from an account activation reminder email
 290          // Stop a request from the blocked IP addresses
 291          antispam_block_ip();
 292  
 293          global $UserSettings, $Session, $baseurl;
 294  
 295          // get user id and reminder key
 296          $userID = param( 'userID', 'integer', '' );
 297          $reminder_key = param( 'reminderKey', 'string', '' );
 298  
 299          $UserCache = & get_UserCache();
 300          $User = $UserCache->get_by_ID( $userID );
 301          $last_reminder_key = $UserSettings->get( 'last_activation_reminder_key', $userID );
 302          if( !$User->check_status( 'can_be_validated' ) )
 303          {
 304              if( $User->check_status( 'is_validated' ) )
 305              { // Already activated, e.g. clicked on an obsolete email link:
 306                  $Messages->add( T_('Your account has already been activated.'), 'note' );
 307                  $action = 'req_login';
 308                  break;
 309              }
 310              elseif( $User->check_status( 'is_closed' ) )
 311              { // Account was closed, don't let to activate the account
 312                  $Messages->add( T_('Your account is closed. You cannot activate it.'), 'error' );
 313                  // redirect to base url
 314                  header_redirect( $baseurl );
 315                  /* exited */
 316              }
 317          }
 318          elseif( empty( $last_reminder_key ) || ( $last_reminder_key != $reminder_key ) )
 319          { // the reminder key in db is empty or not equal with the received one
 320              $Messages->add( T_('Invalid account activation request!'), 'error' );
 321              $action = 'req_validatemail';
 322              break;
 323          }
 324  
 325          // log in with user
 326          $Session->set_user_ID( $userID );
 327  
 328          // activate user account
 329          $User->activate_from_Request();
 330          $Messages->add( T_('Your account is now activated.'), 'success' );
 331  
 332          header_redirect( redirect_after_account_activation() );
 333          /* exited */
 334          break;
 335  
 336      case 'validatemail': // Clicked "Validate email" link from a mail
 337          // Stop a request from the blocked IP addresses
 338          antispam_block_ip();
 339  
 340          param( 'reqID', 'string', '' );
 341          param( 'sessID', 'integer', '' );
 342  
 343          if( check_user_status( 'is_validated' ) )
 344          { // Already validated, e.g. clicked on an obsolete email link:
 345              $Messages->add( T_('Your email address has already been validated.'), 'note' );
 346              // no break: cleanup & redirect below
 347          }
 348          else
 349          {
 350              // Check valid format:
 351              if( empty($reqID) )
 352              { // This was not requested
 353                  $Messages->add( T_('Invalid email address validation request!'), 'error' );
 354                  $action = 'req_validatemail';
 355                  break;
 356              }
 357  
 358              // Check valid session (format only, meant as help for the user):
 359              if( $sessID != $Session->ID )
 360              { // Another session ID than for requesting account validation link used!
 361                  $Messages->add( T_('You have to use the same session (by means of your session cookie) as when you have requested the action. Please try again...'), 'error' );
 362                  $action = 'req_validatemail';
 363                  break;
 364              }
 365  
 366              // Validate provided reqID against the one stored in the user's session
 367              $request_ids = $Session->get( 'core.validatemail.request_ids' );
 368              if( ( ! is_array($request_ids) || ! in_array( $reqID, $request_ids ) )
 369                  && ! ( isset($current_User) && $current_User->grp_ID == 1 && $reqID == 1 /* admin users can validate themselves by a button click */ ) )
 370              {
 371                  $Messages->add( T_('Invalid email address validation request!'), 'error' );
 372                  $action = 'req_validatemail';
 373                  $login_required = true; // Do not display "Without login.." link on the form
 374                  break;
 375              }
 376  
 377              if( ! is_logged_in() )
 378              { // this can happen, if a new user registers and clicks on the "validate by email" link, without logging in first
 379                  // Note: we reuse $reqID and $sessID in the form to come back here.
 380  
 381                  $Messages->add( T_('Please login to validate your account.'), 'error' );
 382                  break;
 383              }
 384  
 385              // activate user account
 386              $current_User->activate_from_Request();
 387  
 388              $Messages->add( T_( 'Your email address has been validated.' ), 'success' );
 389          }
 390  
 391          // init redirect_to
 392          $redirect_to = redirect_after_account_activation();
 393  
 394          // Cleanup:
 395          $Session->delete('core.validatemail.request_ids');
 396          $Session->delete('core.validatemail.redirect_to');
 397  
 398          // redirect Will save $Messages into Session:
 399          header_redirect( $redirect_to );
 400          /* exited */
 401          break;
 402  
 403  } // switch( $action ) (1st)
 404  
 405  
 406  
 407  /* For actions that other delegate to from the switch above: */
 408  switch( $action )
 409  {
 410      case 'req_validatemail':
 411          // Send activation link by email (initial form and action)
 412          if( ! is_logged_in() )
 413          {
 414              $Messages->add( T_('You have to be logged in to request an account validation link.'), 'error' );
 415              $action = '';
 416              break;
 417          }
 418  
 419          if( check_user_status( 'is_validated' ) )
 420          { // Activation not required (check this after login, so it does not get "announced")
 421              $action = '';
 422              break;
 423          }
 424  
 425          param( 'req_validatemail_submit', 'integer', 0 ); // has the form been submitted
 426          $email = param( $dummy_fields['email'], 'string', $current_User->email ); // the email address is editable
 427  
 428          if( $req_validatemail_submit )
 429          { // Form has been submitted
 430              param_check_email( $dummy_fields['email'], true );
 431  
 432              // check if user email was changed
 433              $email_changed = ( $current_User->get( 'email' ) != $email );
 434  
 435              // check if we really needs to send a new validation email
 436              if( !$email_changed )
 437              { // the email was not changed
 438                  $last_activation_email_date = $UserSettings->get( 'last_activation_email', $current_User->ID );
 439                  if( ! empty( $last_activation_email_date ) )
 440                  { // at least one validation email was sent
 441                      // convert date to timestamp
 442                      $last_activation_email_ts = mysql2timestamp( $last_activation_email_date );
 443                      $activate_requests_limit = $Settings->get( 'activate_requests_limit' );
 444                      if( $servertimenow - $last_activation_email_ts < $activate_requests_limit )
 445                      { // a validation email was sent to the same email address less then the x seconds, where x is the "Activation requests limit" value
 446                          // get difference between local time and server time
 447                          $time_difference = $Settings->get('time_difference');
 448                          // get last activation email local date and time
 449                          $last_email_date = date( locale_datetimefmt(), $last_activation_email_ts + $time_difference );
 450                          $Messages->add( sprintf( T_( "We have already sent you an activation message to %s at %s. Please allow %d minutes for delivery before requesting a new one." ), $email, $last_email_date, $activate_requests_limit / 60 ) );
 451                      }
 452                  }
 453              }
 454  
 455              // Call plugin event to allow catching input in general and validating own things from DisplayRegisterFormFieldset event
 456              $Plugins->trigger_event( 'ValidateAccountFormSent' );
 457  
 458              if( $Messages->has_errors() )
 459              {
 460                  break;
 461              }
 462  
 463              if( $email_changed )
 464              { // Update user's email:
 465                  $current_User->set_email( $email );
 466                  if( !$current_User->dbupdate() )
 467                  { // email address couldn't be updated
 468                      $Messages->add( T_('Could not update your email address.'), 'error' );
 469                      break;
 470                  }
 471              }
 472  
 473              $inskin_blog = $inskin ? $blog : NULL;
 474              if( $current_User->send_validate_email( $redirect_to, $inskin_blog, $email_changed ) )
 475              {
 476                  $Messages->add( sprintf( /* TRANS: %s gets replaced by the user's email address */ T_('An email has been sent to your email address (%s). Please click on the link therein to validate your account.'), $current_User->dget('email') ), 'success' );
 477              }
 478              elseif( $demo_mode )
 479              {
 480                  $Messages->add( 'Sorry, could not send email. Sending email in demo mode is disabled.', 'error' );
 481              }
 482              else
 483              {
 484                  $Messages->add( T_('Sorry, the email with the link to validate and activate your password could not be sent.')
 485                              .'<br />'.T_('Possible reason: the PHP mail() function may have been disabled on the server.'), 'error' );
 486              }
 487          }
 488          else
 489          { // Form not yet submitted:
 490              // Add a note, if we have already sent validation links:
 491              $request_ids = $Session->get( 'core.validatemail.request_ids' );
 492              if( is_array($request_ids) && count($request_ids) )
 493              {
 494                  $Messages->add( sprintf( T_('We have already sent you %d email(s) with a validation link.'), count($request_ids) ), 'note' );
 495              }
 496  
 497              if( empty($current_User->email) )
 498              { // add (error) note to be displayed in the form
 499                  $Messages->add( T_('You have no email address with your profile, therefore we cannot validate it. Please give your email address below.'), 'error' );
 500              }
 501          }
 502          break;
 503  }
 504  
 505  
 506  if( strlen($redirect_to) )
 507  { // Make it relative to the form's target, in case it has been set absolute (and can be made relative).
 508      $redirect_to = url_rel_to_same_host( $redirect_to, $secure_htsrv_url );
 509  }
 510  
 511  
 512  if( preg_match( '#/login.php([&?].*)?$#', $redirect_to ) )
 513  { // avoid "endless loops"
 514      $redirect_to = $baseurl;
 515  }
 516  
 517  // Remove login and pwd parameters from URL, so that they do not trigger the login screen again:
 518  $redirect_to = preg_replace( '~(?<=\?|&) (login|pwd) = [^&]+ ~x', '', $redirect_to );
 519  $Debuglog->add( 'redirect_to: '.$redirect_to );
 520  
 521  
 522  /*
 523   * Display in-skin login if it's supported
 524   */
 525  if( $inskin && use_in_skin_login() )
 526  { // in-skin display:
 527      $BlogCache = & get_BlogCache();
 528      $Blog = $BlogCache->get_by_ID( $blog, false, false );
 529      if( ! empty( $Blog ) )
 530      {
 531          if( !empty( $login_error ) )
 532          {
 533              $Messages->add( $login_error );
 534          }
 535          if( empty( $redirect_to ) )
 536          {
 537              $redirect_to = $Blog->gen_blogurl();
 538          }
 539          // check if action was req_validatemail
 540          if( ( $action == 'req_validatemail' ) && !empty( $current_User ) )
 541          { // redirect to inskin activate account page
 542              $redirect = url_add_param( $Blog->gen_blogurl(), 'disp=activateinfo', '&' );
 543              if( $Messages->has_errors() )
 544              {    // Redirect to a form for requesting an activation again if some errors exist
 545                  $redirect = url_add_param( $redirect, 'force_request=1', '&' );
 546              }
 547          }
 548          else
 549          { // redirect to inskin login page
 550              $redirect = url_add_param( $Blog->gen_blogurl(), 'disp=login', '&' );
 551          }
 552          $redirect = url_add_param( $redirect, 'redirect_to='.$redirect_to, '&' );
 553          header_redirect( $redirect );
 554          // already exited here
 555          exit(0);
 556      }
 557  }
 558  
 559  /**
 560   * Display standard login screen:
 561   */
 562  switch( $action )
 563  {
 564      case 'lostpassword':
 565          // Lost password:
 566          $page_title = T_('Lost password ?');
 567          $page_icon = 'login';
 568          $hidden_params = array( 'redirect_to' => url_rel_to_same_host($redirect_to, $secure_htsrv_url) );
 569          // Include page header:
 570          require $adminskins_path.'login/_html_header.inc.php';
 571          // Display form:
 572          display_lostpassword_form( $login, $hidden_params );
 573          require $adminskins_path.'login/_html_footer.inc.php';
 574          break;
 575  
 576      case 'req_validatemail':
 577          // Send activation link by email (initial form and action)
 578          // Display validation form:
 579          require $adminskins_path.'login/_validate_form.main.php';
 580          break;
 581  
 582      default:
 583          // Display login form:
 584          require $adminskins_path.'login/_login_form.main.php';
 585  }
 586  
 587  exit(0);
 588  ?>

title

Description

title

Description

title

Description

title

title

Body