You are here

email_confirm.module in Email Change Confirmation 6

Same filename and directory in other branches
  1. 5 email_confirm.module
  2. 7 email_confirm.module

File

email_confirm.module
View source
<?php

// $Id$

/**
 * Implementation of hook_help().
 */
function email_confirm_help($path, $arg) {
  switch ($path) {
    case 'admin/modules#description':
      return t('Configuration of confirmation email sent to users who attempt to change their email address.');
    case 'admin/help#email_confirm':
      return t('<p>The Email Change Confirmation module addresses missing functionality in the core distribution of Drupal. With this module enabled, a user who attempts to change the email address associated with their account must confirm that change by clicking a confirmation link that is sent to the new email address. The confirmation link must be clicked with a certain time period after which the pending update to their email address will expire and they will have to attempt to update their account again. This module was based on code from <a href="!url">this issue</a></p>', array(
        '!url' => 'http://drupal.org/node/85494',
      ));
    case 'admin/settings/email_confirm':
      return t('When the Email Change Confirmation module is enabled, users who attempt to update their email address will be required to confirm their changes by clicking a confirmation link in an email sent to the new email address. The settings below determine the subject and body of the confirmation email sent to the user. A copy is sent to both the user\'s original email address and the new address.');
  }
}

/**
 * Implementation of hook_menu().
 */
function email_confirm_menu() {
  $items = array();
  $items['user/change-mail'] = array(
    'title' => 'Change e-mail',
    'page callback' => 'email_confirm_user_change_mail',
    'access callback' => TRUE,
    'type' => MENU_CALLBACK,
  );
  $items['admin/settings/email_confirm'] = array(
    'title' => 'Email change confirmation settings',
    'description' => 'Configuration of confirmation email sent to users who attempt to change their email address.',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'email_confirm_admin_settings',
    ),
    'access callback' => 'user_access',
    'access arguments' => array(
      'administer site configuration',
    ),
    'type' => MENU_NORMAL_ITEM,
  );
  return $items;
}

/**
 * Implementation of hook_settings().
 */
function email_confirm_admin_settings() {
  $form = array();
  $form['email_confirm_confirmation_email_subject'] = array(
    '#type' => 'textfield',
    '#title' => t('Email address change request email subject'),
    '#description' => t('The above text will be the subject for the email sent to a user that is attempting to update their email address. The placeholders !username and !site will be replaced by the username and the site name.'),
    '#default_value' => email_confirm_mail_text('email_confirm_confirmation_email_subject'),
    '#size' => 60,
    '#maxlength' => 256,
    '#required' => TRUE,
  );
  $form['email_confirm_confirmation_email_author'] = array(
    '#type' => 'textfield',
    '#title' => t('Email address change request email author'),
    '#default_value' => variable_get('email_confirm_confirmation_email_author', ''),
    '#size' => 60,
    '#description' => t('The above address will be the \'From\' email address for the confirmation email for an email address change request. If no address is supplied the default site email address will be used.'),
  );
  $form['email_confirm_confirmation_email_bcc'] = array(
    '#type' => 'textfield',
    '#title' => t('Email address change request email BCC email address'),
    '#default_value' => variable_get('email_confirm_confirmation_email_bcc', ''),
    '#size' => 60,
    '#description' => t('The above address will receive a BCC email copy of the confirmation email for an email address change request.'),
  );
  $form['email_confirm_confirmation_email_body'] = array(
    '#type' => 'textarea',
    '#title' => t('Email address change request email body'),
    '#description' => t("The above text will be the body for the email sent to a user that is attempting to update their email address. The text here will be sent to the user's new email address. The placeholders !username and !site will be replaced by the username and the site name."),
    '#default_value' => email_confirm_mail_text('email_confirm_confirmation_email_body'),
    '#cols' => 80,
    '#rows' => 10,
    '#required' => TRUE,
  );
  $form['email_confirm_confirmation_original_email_body'] = array(
    '#type' => 'textarea',
    '#title' => t('Email address change request email body (Original)'),
    '#description' => t("The above text will be the body for the email sent to a user that is attempting to update their email address. The text here will be sent to the user's original email address. The placeholders !username and !site will be replaced by the username and the site name."),
    '#default_value' => email_confirm_mail_text('email_confirm_confirmation_original_email_body'),
    '#cols' => 80,
    '#rows' => 10,
    '#required' => TRUE,
  );
  return system_settings_form($form);
}

/**
 * Admin settings validate
 */
function email_confirm_admin_settings_validate($form, $form_state) {
  if (!empty($form_state['values']['email_confirm_confirmation_email_author']) && !valid_email_address($form_state['values']['email_confirm_confirmation_email_author'])) {
    form_set_error('email_confirm_confirmation_email_author', t('You must enter a valid email address for the "Email address change request email author" setting.'));
  }
  if (!empty($form_state['values']['email_confirm_confirmation_email_bcc']) && !valid_email_address($form_state['values']['email_confirm_confirmation_email_bcc'])) {
    form_set_error('email_confirm_confirmation_email_bcc', t('You must enter a valid email address for the "Email address change request email BCC email address" setting.'));
  }
}

/**
 * Implementation of hook_user().
 */
function email_confirm_user($op, &$edit, &$account) {
  switch ($op) {
    case 'submit':
      if (!empty($edit['mail']) && $account->mail != $edit['mail'] && !user_access('administer users')) {
        email_confirm_build_mail($edit);
        module_invoke_all('email_confirm', 'email change', $account->uid, $account->mail, $edit['mail']);
        if (module_exists('rules')) {
          rules_invoke_event('email_confirm_email_change_request', $account, $account->mail, $edit['mail']);
        }
        unset($edit['mail']);
      }
      break;
  }
}

/**
 * Menu callback; process one time email change confirm
 * and redirects to the user page on success.
 */
function email_confirm_user_change_mail($uid = NULL, $timestamp = NULL, $new_mail = NULL, $hash = NULL) {
  global $user;

  // Check if all required parameters are present.
  if (!isset($uid) || !is_numeric($uid) || !isset($timestamp) || !is_numeric($timestamp) || !isset($new_mail) || !isset($hash)) {
    drupal_access_denied();
    return;
  }
  $account = user_load(array(
    'uid' => $uid,
    'status' => 1,
  ));
  $new_mail = str_replace(' ', '+', $new_mail);

  // Time out, in seconds, until login URL expires. 24 hours = 86400 seconds.
  $timeout = 86400;
  $current = time();

  // Some redundant checks for extra security ?
  if ($timestamp < $current && $account) {
    if ($current - $timestamp > $timeout) {
      drupal_set_message(t('You have tried to use a one-time e-mail change link for %account that has expired--your change of e-mail request was not completed. Please visit your account edit page if you wish to attempt the change again.', array(
        '%account' => $account->name,
      )), 'error');
      if ($account->uid == $user->uid) {
        drupal_goto('user/' . $account->uid . '/edit');
      }
      else {
        drupal_goto();
      }
    }
    else {
      if ($user->uid && $user->uid != $account->uid) {
        drupal_set_message(t('You are currently logged in as %user, and are attempting to confirm an e-mail change for %account, which is not allowed. Please log in as %account and initiate a new change of e-mail request.', array(
          '%user' => $user->name,
          '%account' => $account->name,
        )), 'error');
        drupal_goto();
      }
      else {
        if ($hash != email_confirm_user_email_rehash($account->pass, $new_mail)) {
          drupal_set_message(t('There was a problem verifying your change of e-mail request--please visit your account edit page and attempt the change again'), 'error');
          if ($user->uid) {
            drupal_goto('user/' . $user->uid . '/edit');
          }
          else {
            drupal_goto('user/login', 'destination=user/' . $user->uid . '/edit');
          }
        }
        else {
          if ($timestamp > $account->login && $timestamp < $current) {
            watchdog('user', 'User %name used one-time e-mail change link at time %timestamp.', array(
              '%name' => $account->name,
              '%timestamp' => $timestamp,
            ));
            $old_mail = $account->mail;
            user_save($account, array(
              'mail' => $new_mail,
              'login' => time(),
            ));
            module_invoke_all('email_confirm', 'email confirmation', $account->uid, $old_mail, $new_mail);
            if (module_exists('rules')) {
              rules_invoke_event('email_confirm_email_change_confirmation', $account, $old_mail, $new_mail);
            }
            drupal_set_message(t('Your e-mail address is now %mail.', array(
              '%mail' => $new_mail,
            )));
            if ($user->uid) {
              drupal_goto('user/' . $user->uid);
            }
            else {
              drupal_goto('user');
            }
          }
          else {
            drupal_set_message(t('You have tried to use a one-time e-mail change link which has either been used or has expired. Please request a new one.'), 'error');
            if ($user->uid) {
              drupal_goto('user/' . $user->uid . '/edit');
            }
            else {
              drupal_goto('user/login', 'destination=user/' . $user->uid . '/edit');
            }
          }
        }
      }
    }
  }
  else {

    // Deny access, no more clues.
    // Everything will be in the watchdog's URL for the administrator to check.
    drupal_access_denied();
  }
}

/**
 * Implementation of hook_mail().
 */
function email_confirm_mail($key, &$message, $params) {
  $language = $message['language'];
  $account = $params['account'];
  $context = $params['context'];
  $variables = user_mail_tokens($account, $language);
  $variables += array(
    '!email_url' => $context['url'],
  );
  $message['subject'] = strtr($context['subject'], $variables);
  $message['body'][] = strtr($context['body'], $variables);
  if ($params['headers']['bcc']) {
    $message['headers']['bcc'] = $params['headers']['bcc'];
  }
}

/**
 * Build and send out the confirmation email to the user's
 * current and proposed new email address.
 */
function email_confirm_build_mail($edit) {
  global $user;
  $params = array();
  $params['account'] = $user;
  $timestamp = time();
  $pass = $edit['pass'] ? md5($edit['pass']) : $user->pass;
  $hash = email_confirm_user_email_rehash($pass, $edit['mail']);
  $params['context']['url'] = url('user/change-mail/' . $user->uid . '/' . $timestamp . '/' . $edit['mail'] . '/' . $hash, array(
    'absolute' => TRUE,
  ));
  if (module_exists('smtp') && variable_get('smtp_from', '') != '') {
    $default_from = $smtp_from;
  }
  else {
    $default_from = variable_get('site_mail', ini_get('sendmail_from'));
  }
  $from = variable_get('email_confirm_confirmation_email_author', $default_from);
  $bcc = variable_get('email_confirm_confirmation_email_bcc', '');
  $params['context']['subject'] = email_confirm_mail_text('email_confirm_confirmation_email_subject');
  $params['context']['body'] = email_confirm_mail_text('email_confirm_confirmation_email_body');
  $params['headers'] = array();
  if ($bcc) {
    $params['headers']['bcc'] = $bcc;
  }
  if ($message['result'] = drupal_mail('email_confirm', 'user_change_mail', $edit['mail'], user_preferred_language($user), $params, $from)) {
    $params['context']['body'] = email_confirm_mail_text('email_confirm_confirmation_original_email_body');
    drupal_mail('email_confirm', 'user_change_mail_original', $user->mail, user_preferred_language($user), $params, $from);
    drupal_set_message(t('A confirmation email has been sent to your new email address. You must follow the link provided in that email within 24 hours in order to confirm the change to your account email address.'));
  }
}
function email_confirm_user_email_rehash($pass, $mail) {
  return md5($pass . $mail . drupal_get_private_key());
}

/**
 * Returns an email subject or body string.
 *
 * Used by email_confirm_build_mail() and the settings forms to retrieve strings.
 */
function email_confirm_mail_text($key, $language = NULL, $variables = array()) {
  $langcode = isset($language) ? $language->language : NULL;
  if ($default_text = variable_get($key, FALSE)) {
    return strtr($default_text, $variables);
  }
  else {
    switch ($key) {
      case 'email_confirm_confirmation_email_subject':
      case 'user_change_mail_subject':

      // Mail Edit integration
      case 'user_change_mail_original_subject':

        // Mail Edit integration
        return t('Email address change request for !username at !site', $variables, $langcode);
        break;
      case 'email_confirm_confirmation_email_body':
      case 'user_change_mail_body':

        // Mail Edit integration
        return t('Hello !username,

A request to change your email address has been made at !site.
You need to verify the change by clicking on the link below or by
copying and pasting it in your browser:

!email_url

This is a one-time URL - it can be used only once. It expires after
24 hours. If you do not click the link to confirm, your email address
at !site will not be updated.
', $variables, $langcode);
        break;
      case 'email_confirm_confirmation_original_email_body':
      case 'user_change_mail_original_body':

        // Mail Edit integration
        return t('Hello !username,

A request to change your email address has been made at !site.
In order to confirm the update of your email address you will
need to follow the instructions sent to your new email address
within 24 hours.
', $variables, $langcode);
        break;
    }
  }
}

/**
 * Mail Edit module integration
 */
if (module_exists('mail_edit')) {
  module_load_include('inc', 'email_confirm', 'email_confirm.mail_edit');
}

Functions

Namesort descending Description
email_confirm_admin_settings Implementation of hook_settings().
email_confirm_admin_settings_validate Admin settings validate
email_confirm_build_mail Build and send out the confirmation email to the user's current and proposed new email address.
email_confirm_help Implementation of hook_help().
email_confirm_mail Implementation of hook_mail().
email_confirm_mail_text Returns an email subject or body string.
email_confirm_menu Implementation of hook_menu().
email_confirm_user Implementation of hook_user().
email_confirm_user_change_mail Menu callback; process one time email change confirm and redirects to the user page on success.
email_confirm_user_email_rehash