Drupal PHP Cross Reference Content Management Systems

Source: /modules/user/user.module - 3963 lines - 139291 bytes - Summary - Text - Print

   1  <?php
   2  
   3  /**
   4   * @file
   5   * Enables the user registration and login system.
   6   */
   7  
   8  /**
   9   * Maximum length of username text field.
  10   */
  11  define('USERNAME_MAX_LENGTH', 60);
  12  
  13  /**
  14   * Maximum length of user e-mail text field.
  15   */
  16  define('EMAIL_MAX_LENGTH', 254);
  17  
  18  /**
  19   * Only administrators can create user accounts.
  20   */
  21  define('USER_REGISTER_ADMINISTRATORS_ONLY', 0);
  22  
  23  /**
  24   * Visitors can create their own accounts.
  25   */
  26  define('USER_REGISTER_VISITORS', 1);
  27  
  28  /**
  29   * Visitors can create accounts, but they don't become active without
  30   * administrative approval.
  31   */
  32  define('USER_REGISTER_VISITORS_ADMINISTRATIVE_APPROVAL', 2);
  33  
  34  /**
  35   * Implement hook_help().
  36   */
  37  function user_help($path, $arg) {
  38    global $user;
  39  
  40    switch ($path) {
  41      case 'admin/help#user':
  42        $output = '';
  43        $output .= '<h3>' . t('About') . '</h3>';
  44        $output .= '<p>' . t('The User module allows users to register, log in, and log out. It also allows users with proper permissions to manage user roles (used to classify users) and permissions associated with those roles. For more information, see the online handbook entry for <a href="@user">User module</a>.', array('@user' => 'http://drupal.org/documentation/modules/user')) . '</p>';
  45        $output .= '<h3>' . t('Uses') . '</h3>';
  46        $output .= '<dl>';
  47        $output .= '<dt>' . t('Creating and managing users') . '</dt>';
  48        $output .= '<dd>' . t('The User module allows users with the appropriate <a href="@permissions">permissions</a> to create user accounts through the <a href="@people">People administration page</a>, where they can also assign users to one or more roles, and block or delete user accounts. If allowed, users without accounts (anonymous users) can create their own accounts on the <a href="@register">Create new account</a> page.', array('@permissions' => url('admin/people/permissions', array('fragment' => 'module-user')), '@people' => url('admin/people'), '@register' => url('user/register'))) . '</dd>';
  49        $output .= '<dt>' . t('User roles and permissions') . '</dt>';
  50        $output .= '<dd>' . t('<em>Roles</em> are used to group and classify users; each user can be assigned one or more roles. By default there are two roles: <em>anonymous user</em> (users that are not logged in) and <em>authenticated user</em> (users that are registered and logged in). Depending on choices you made when you installed Drupal, the installation process may have defined more roles, and you can create additional custom roles on the <a href="@roles">Roles page</a>. After creating roles, you can set permissions for each role on the <a href="@permissions_user">Permissions page</a>. Granting a permission allows users who have been assigned a particular role to perform an action on the site, such as viewing a particular type of content, editing or creating content, administering settings for a particular module, or using a particular function of the site (such as search).', array('@permissions_user' => url('admin/people/permissions'), '@roles' => url('admin/people/permissions/roles'))) . '</dd>';
  51        $output .= '<dt>' . t('Account settings') . '</dt>';
  52        $output .= '<dd>' . t('The <a href="@accounts">Account settings page</a> allows you to manage settings for the displayed name of the anonymous user role, personal contact forms, user registration, and account cancellation. On this page you can also manage settings for account personalization (including signatures and user pictures), and adapt the text for the e-mail messages that are sent automatically during the user registration process.', array('@accounts'  => url('admin/config/people/accounts'))) . '</dd>';
  53        $output .= '</dl>';
  54        return $output;
  55      case 'admin/people/create':
  56        return '<p>' . t("This web page allows administrators to register new users. Users' e-mail addresses and usernames must be unique.") . '</p>';
  57      case 'admin/people/permissions':
  58        return '<p>' . t('Permissions let you control what users can do and see on your site. You can define a specific set of permissions for each role. (See the <a href="@role">Roles</a> page to create a role). Two important roles to consider are Authenticated Users and Administrators. Any permissions granted to the Authenticated Users role will be given to any user who can log into your site. You can make any role the Administrator role for the site, meaning this will be granted all new permissions automatically. You can do this on the <a href="@settings">User Settings</a> page. You should be careful to ensure that only trusted users are given this access and level of control of your site.', array('@role' => url('admin/people/permissions/roles'), '@settings' => url('admin/config/people/accounts'))) . '</p>';
  59      case 'admin/people/permissions/roles':
  60        $output = '<p>' . t('Roles allow you to fine tune the security and administration of Drupal. A role defines a group of users that have certain privileges as defined on the <a href="@permissions">permissions page</a>. Examples of roles include: anonymous user, authenticated user, moderator, administrator and so on. In this area you will define the names and order of the roles on your site. It is recommended to order your roles from least permissive (anonymous user) to most permissive (administrator). To delete a role choose "edit role".', array('@permissions' => url('admin/people/permissions'))) . '</p>';
  61        $output .= '<p>' . t('By default, Drupal comes with two user roles:') . '</p>';
  62        $output .= '<ul>';
  63        $output .= '<li>' . t("Anonymous user: this role is used for users that don't have a user account or that are not authenticated.") . '</li>';
  64        $output .= '<li>' . t('Authenticated user: this role is automatically granted to all logged in users.') . '</li>';
  65        $output .= '</ul>';
  66        return $output;
  67      case 'admin/config/people/accounts/fields':
  68        return '<p>' . t('This form lets administrators add, edit, and arrange fields for storing user data.') . '</p>';
  69      case 'admin/config/people/accounts/display':
  70        return '<p>' . t('This form lets administrators configure how fields should be displayed when rendering a user profile page.') . '</p>';
  71      case 'admin/people/search':
  72        return '<p>' . t('Enter a simple pattern ("*" may be used as a wildcard match) to search for a username or e-mail address. For example, one may search for "br" and Drupal might return "brian", "brad", and "brenda@example.com".') . '</p>';
  73    }
  74  }
  75  
  76  /**
  77   * Invokes a user hook in every module.
  78   *
  79   * We cannot use module_invoke() for this, because the arguments need to
  80   * be passed by reference.
  81   *
  82   * @param $type
  83   *   A text string that controls which user hook to invoke.  Valid choices are:
  84   *   - cancel: Invokes hook_user_cancel().
  85   *   - insert: Invokes hook_user_insert().
  86   *   - login: Invokes hook_user_login().
  87   *   - presave: Invokes hook_user_presave().
  88   *   - update: Invokes hook_user_update().
  89   * @param $edit
  90   *   An associative array variable containing form values to be passed
  91   *   as the first parameter of the hook function.
  92   * @param $account
  93   *   The user account object to be passed as the second parameter of the hook
  94   *   function.
  95   * @param $category
  96   *   The category of user information being acted upon.
  97   */
  98  function user_module_invoke($type, &$edit, $account, $category = NULL) {
  99    foreach (module_implements('user_' . $type) as $module) {
 100      $function = $module . '_user_' . $type;
 101      $function($edit, $account, $category);
 102    }
 103  }
 104  
 105  /**
 106   * Implements hook_theme().
 107   */
 108  function user_theme() {
 109    return array(
 110      'user_picture' => array(
 111        'variables' => array('account' => NULL),
 112        'template' => 'user-picture',
 113      ),
 114      'user_profile' => array(
 115        'render element' => 'elements',
 116        'template' => 'user-profile',
 117        'file' => 'user.pages.inc',
 118      ),
 119      'user_profile_category' => array(
 120        'render element' => 'element',
 121        'template' => 'user-profile-category',
 122        'file' => 'user.pages.inc',
 123      ),
 124      'user_profile_item' => array(
 125        'render element' => 'element',
 126        'template' => 'user-profile-item',
 127        'file' => 'user.pages.inc',
 128      ),
 129      'user_list' => array(
 130        'variables' => array('users' => NULL, 'title' => NULL),
 131      ),
 132      'user_admin_permissions' => array(
 133        'render element' => 'form',
 134        'file' => 'user.admin.inc',
 135      ),
 136      'user_admin_roles' => array(
 137        'render element' => 'form',
 138        'file' => 'user.admin.inc',
 139      ),
 140      'user_permission_description' => array(
 141        'variables' => array('permission_item' => NULL, 'hide' => NULL),
 142        'file' => 'user.admin.inc',
 143      ),
 144      'user_signature' => array(
 145        'variables' => array('signature' => NULL),
 146      ),
 147    );
 148  }
 149  
 150  /**
 151   * Implements hook_entity_info().
 152   */
 153  function user_entity_info() {
 154    $return = array(
 155      'user' => array(
 156        'label' => t('User'),
 157        'controller class' => 'UserController',
 158        'base table' => 'users',
 159        'uri callback' => 'user_uri',
 160        'label callback' => 'format_username',
 161        'fieldable' => TRUE,
 162        // $user->language is only the preferred user language for the user
 163        // interface textual elements. As it is not necessarily related to the
 164        // language assigned to fields, we do not define it as the entity language
 165        // key.
 166        'entity keys' => array(
 167          'id' => 'uid',
 168        ),
 169        'bundles' => array(
 170          'user' => array(
 171            'label' => t('User'),
 172            'admin' => array(
 173              'path' => 'admin/config/people/accounts',
 174              'access arguments' => array('administer users'),
 175            ),
 176          ),
 177        ),
 178        'view modes' => array(
 179          'full' => array(
 180            'label' => t('User account'),
 181            'custom settings' => FALSE,
 182          ),
 183        ),
 184      ),
 185    );
 186    return $return;
 187  }
 188  
 189  /**
 190   * Entity URI callback.
 191   */
 192  function user_uri($user) {
 193    return array(
 194      'path' => 'user/' . $user->uid,
 195    );
 196  }
 197  
 198  /**
 199   * Implements hook_field_info_alter().
 200   */
 201  function user_field_info_alter(&$info) {
 202    // Add the 'user_register_form' instance setting to all field types.
 203    foreach ($info as $field_type => &$field_type_info) {
 204      $field_type_info += array('instance_settings' => array());
 205      $field_type_info['instance_settings'] += array(
 206        'user_register_form' => FALSE,
 207      );
 208    }
 209  }
 210  
 211  /**
 212   * Implements hook_field_extra_fields().
 213   */
 214  function user_field_extra_fields() {
 215    $return['user']['user'] = array(
 216      'form' => array(
 217        'account' => array(
 218          'label' => t('User name and password'),
 219          'description' => t('User module account form elements.'),
 220          'weight' => -10,
 221        ),
 222        'timezone' => array(
 223          'label' => t('Timezone'),
 224          'description' => t('User module timezone form element.'),
 225          'weight' => 6,
 226        ),
 227      ),
 228      'display' => array(
 229        'summary' => array(
 230          'label' => t('History'),
 231          'description' => t('User module history view element.'),
 232          'weight' => 5,
 233        ),
 234      ),
 235    );
 236  
 237    return $return;
 238  }
 239  
 240  /**
 241   * Fetches a user object based on an external authentication source.
 242   *
 243   * @param string $authname
 244   *   The external authentication username.
 245   *
 246   * @return
 247   *   A fully-loaded user object if the user is found or FALSE if not found.
 248   */
 249  function user_external_load($authname) {
 250    $uid = db_query("SELECT uid FROM {authmap} WHERE authname = :authname", array(':authname' => $authname))->fetchField();
 251  
 252    if ($uid) {
 253      return user_load($uid);
 254    }
 255    else {
 256      return FALSE;
 257    }
 258  }
 259  
 260  /**
 261   * Load multiple users based on certain conditions.
 262   *
 263   * This function should be used whenever you need to load more than one user
 264   * from the database. Users are loaded into memory and will not require
 265   * database access if loaded again during the same page request.
 266   *
 267   * @param $uids
 268   *   An array of user IDs.
 269   * @param $conditions
 270   *   (deprecated) An associative array of conditions on the {users}
 271   *   table, where the keys are the database fields and the values are the
 272   *   values those fields must have. Instead, it is preferable to use
 273   *   EntityFieldQuery to retrieve a list of entity IDs loadable by
 274   *   this function.
 275   * @param $reset
 276   *   A boolean indicating that the internal cache should be reset. Use this if
 277   *   loading a user object which has been altered during the page request.
 278   *
 279   * @return
 280   *   An array of user objects, indexed by uid.
 281   *
 282   * @see entity_load()
 283   * @see user_load()
 284   * @see user_load_by_mail()
 285   * @see user_load_by_name()
 286   * @see EntityFieldQuery
 287   *
 288   * @todo Remove $conditions in Drupal 8.
 289   */
 290  function user_load_multiple($uids = array(), $conditions = array(), $reset = FALSE) {
 291    return entity_load('user', $uids, $conditions, $reset);
 292  }
 293  
 294  /**
 295   * Controller class for users.
 296   *
 297   * This extends the DrupalDefaultEntityController class, adding required
 298   * special handling for user objects.
 299   */
 300  class UserController extends DrupalDefaultEntityController {
 301  
 302    function attachLoad(&$queried_users, $revision_id = FALSE) {
 303      // Build an array of user picture IDs so that these can be fetched later.
 304      $picture_fids = array();
 305      foreach ($queried_users as $key => $record) {
 306        $picture_fids[] = $record->picture;
 307        $queried_users[$key]->data = unserialize($record->data);
 308        $queried_users[$key]->roles = array();
 309        if ($record->uid) {
 310          $queried_users[$record->uid]->roles[DRUPAL_AUTHENTICATED_RID] = 'authenticated user';
 311        }
 312        else {
 313          $queried_users[$record->uid]->roles[DRUPAL_ANONYMOUS_RID] = 'anonymous user';
 314        }
 315      }
 316  
 317      // Add any additional roles from the database.
 318      $result = db_query('SELECT r.rid, r.name, ur.uid FROM {role} r INNER JOIN {users_roles} ur ON ur.rid = r.rid WHERE ur.uid IN (:uids)', array(':uids' => array_keys($queried_users)));
 319      foreach ($result as $record) {
 320        $queried_users[$record->uid]->roles[$record->rid] = $record->name;
 321      }
 322  
 323      // Add the full file objects for user pictures if enabled.
 324      if (!empty($picture_fids) && variable_get('user_pictures', 1) == 1) {
 325        $pictures = file_load_multiple($picture_fids);
 326        foreach ($queried_users as $account) {
 327          if (!empty($account->picture) && isset($pictures[$account->picture])) {
 328            $account->picture = $pictures[$account->picture];
 329          }
 330          else {
 331            $account->picture = NULL;
 332          }
 333        }
 334      }
 335      // Call the default attachLoad() method. This will add fields and call
 336      // hook_user_load().
 337      parent::attachLoad($queried_users, $revision_id);
 338    }
 339  }
 340  
 341  /**
 342   * Loads a user object.
 343   *
 344   * Drupal has a global $user object, which represents the currently-logged-in
 345   * user. So to avoid confusion and to avoid clobbering the global $user object,
 346   * it is a good idea to assign the result of this function to a different local
 347   * variable, generally $account. If you actually do want to act as the user you
 348   * are loading, it is essential to call drupal_save_session(FALSE); first.
 349   * See
 350   * @link http://drupal.org/node/218104 Safely impersonating another user @endlink
 351   * for more information.
 352   *
 353   * @param $uid
 354   *   Integer specifying the user ID to load.
 355   * @param $reset
 356   *   TRUE to reset the internal cache and load from the database; FALSE
 357   *   (default) to load from the internal cache, if set.
 358   *
 359   * @return
 360   *   A fully-loaded user object upon successful user load, or FALSE if the user
 361   *   cannot be loaded.
 362   *
 363   * @see user_load_multiple()
 364   */
 365  function user_load($uid, $reset = FALSE) {
 366    $users = user_load_multiple(array($uid), array(), $reset);
 367    return reset($users);
 368  }
 369  
 370  /**
 371   * Fetch a user object by email address.
 372   *
 373   * @param $mail
 374   *   String with the account's e-mail address.
 375   * @return
 376   *   A fully-loaded $user object upon successful user load or FALSE if user
 377   *   cannot be loaded.
 378   *
 379   * @see user_load_multiple()
 380   */
 381  function user_load_by_mail($mail) {
 382    $users = user_load_multiple(array(), array('mail' => $mail));
 383    return reset($users);
 384  }
 385  
 386  /**
 387   * Fetch a user object by account name.
 388   *
 389   * @param $name
 390   *   String with the account's user name.
 391   * @return
 392   *   A fully-loaded $user object upon successful user load or FALSE if user
 393   *   cannot be loaded.
 394   *
 395   * @see user_load_multiple()
 396   */
 397  function user_load_by_name($name) {
 398    $users = user_load_multiple(array(), array('name' => $name));
 399    return reset($users);
 400  }
 401  
 402  /**
 403   * Save changes to a user account or add a new user.
 404   *
 405   * @param $account
 406   *   (optional) The user object to modify or add. If you want to modify
 407   *   an existing user account, you will need to ensure that (a) $account
 408   *   is an object, and (b) you have set $account->uid to the numeric
 409   *   user ID of the user account you wish to modify. If you
 410   *   want to create a new user account, you can set $account->is_new to
 411   *   TRUE or omit the $account->uid field.
 412   * @param $edit
 413   *   An array of fields and values to save. For example array('name'
 414   *   => 'My name'). Key / value pairs added to the $edit['data'] will be
 415   *   serialized and saved in the {users.data} column.
 416   * @param $category
 417   *   (optional) The category for storing profile information in.
 418   *
 419   * @return
 420   *   A fully-loaded $user object upon successful save or FALSE if the save failed.
 421   *
 422   * @todo D8: Drop $edit and fix user_save() to be consistent with others.
 423   */
 424  function user_save($account, $edit = array(), $category = 'account') {
 425    $transaction = db_transaction();
 426    try {
 427      if (!empty($edit['pass'])) {
 428        // Allow alternate password hashing schemes.
 429        require_once DRUPAL_ROOT . '/' . variable_get('password_inc', 'includes/password.inc');
 430        $edit['pass'] = user_hash_password(trim($edit['pass']));
 431        // Abort if the hashing failed and returned FALSE.
 432        if (!$edit['pass']) {
 433          return FALSE;
 434        }
 435      }
 436      else {
 437        // Avoid overwriting an existing password with a blank password.
 438        unset($edit['pass']);
 439      }
 440      if (isset($edit['mail'])) {
 441        $edit['mail'] = trim($edit['mail']);
 442      }
 443  
 444      // Load the stored entity, if any.
 445      if (!empty($account->uid) && !isset($account->original)) {
 446        $account->original = entity_load_unchanged('user', $account->uid);
 447      }
 448  
 449      if (empty($account)) {
 450        $account = new stdClass();
 451      }
 452      if (!isset($account->is_new)) {
 453        $account->is_new = empty($account->uid);
 454      }
 455      // Prepopulate $edit['data'] with the current value of $account->data.
 456      // Modules can add to or remove from this array in hook_user_presave().
 457      if (!empty($account->data)) {
 458        $edit['data'] = !empty($edit['data']) ? array_merge($account->data, $edit['data']) : $account->data;
 459      }
 460  
 461      // Invoke hook_user_presave() for all modules.
 462      user_module_invoke('presave', $edit, $account, $category);
 463  
 464      // Invoke presave operations of Field Attach API and Entity API. Those APIs
 465      // require a fully-fledged and updated entity object. Therefore, we need to
 466      // copy any new property values of $edit into it.
 467      foreach ($edit as $key => $value) {
 468        $account->$key = $value;
 469      }
 470      field_attach_presave('user', $account);
 471      module_invoke_all('entity_presave', $account, 'user');
 472  
 473      if (is_object($account) && !$account->is_new) {
 474        // Process picture uploads.
 475        if (!empty($account->picture->fid) && (!isset($account->original->picture->fid) || $account->picture->fid != $account->original->picture->fid)) {
 476          $picture = $account->picture;
 477          // If the picture is a temporary file move it to its final location and
 478          // make it permanent.
 479          if (!$picture->status) {
 480            $info = image_get_info($picture->uri);
 481            $picture_directory =  file_default_scheme() . '://' . variable_get('user_picture_path', 'pictures');
 482  
 483            // Prepare the pictures directory.
 484            file_prepare_directory($picture_directory, FILE_CREATE_DIRECTORY);
 485            $destination = file_stream_wrapper_uri_normalize($picture_directory . '/picture-' . $account->uid . '-' . REQUEST_TIME . '.' . $info['extension']);
 486  
 487            // Move the temporary file into the final location.
 488            if ($picture = file_move($picture, $destination, FILE_EXISTS_RENAME)) {
 489              $picture->status = FILE_STATUS_PERMANENT;
 490              $account->picture = file_save($picture);
 491              file_usage_add($picture, 'user', 'user', $account->uid);
 492            }
 493          }
 494          // Delete the previous picture if it was deleted or replaced.
 495          if (!empty($account->original->picture->fid)) {
 496            file_usage_delete($account->original->picture, 'user', 'user', $account->uid);
 497            file_delete($account->original->picture);
 498          }
 499        }
 500        elseif (isset($edit['picture_delete']) && $edit['picture_delete']) {
 501          file_usage_delete($account->original->picture, 'user', 'user', $account->uid);
 502          file_delete($account->original->picture);
 503        }
 504        $account->picture = empty($account->picture->fid) ? 0 : $account->picture->fid;
 505  
 506        // Do not allow 'uid' to be changed.
 507        $account->uid = $account->original->uid;
 508        // Save changes to the user table.
 509        $success = drupal_write_record('users', $account, 'uid');
 510        if ($success === FALSE) {
 511          // The query failed - better to abort the save than risk further
 512          // data loss.
 513          return FALSE;
 514        }
 515  
 516        // Reload user roles if provided.
 517        if ($account->roles != $account->original->roles) {
 518          db_delete('users_roles')
 519            ->condition('uid', $account->uid)
 520            ->execute();
 521  
 522          $query = db_insert('users_roles')->fields(array('uid', 'rid'));
 523          foreach (array_keys($account->roles) as $rid) {
 524            if (!in_array($rid, array(DRUPAL_ANONYMOUS_RID, DRUPAL_AUTHENTICATED_RID))) {
 525              $query->values(array(
 526                'uid' => $account->uid,
 527                'rid' => $rid,
 528              ));
 529            }
 530          }
 531          $query->execute();
 532        }
 533  
 534        // Delete a blocked user's sessions to kick them if they are online.
 535        if ($account->original->status != $account->status && $account->status == 0) {
 536          drupal_session_destroy_uid($account->uid);
 537        }
 538  
 539        // If the password changed, delete all open sessions and recreate
 540        // the current one.
 541        if ($account->pass != $account->original->pass) {
 542          drupal_session_destroy_uid($account->uid);
 543          if ($account->uid == $GLOBALS['user']->uid) {
 544            drupal_session_regenerate();
 545          }
 546        }
 547  
 548        // Save Field data.
 549        field_attach_update('user', $account);
 550  
 551        // Send emails after we have the new user object.
 552        if ($account->status != $account->original->status) {
 553          // The user's status is changing; conditionally send notification email.
 554          $op = $account->status == 1 ? 'status_activated' : 'status_blocked';
 555          _user_mail_notify($op, $account);
 556        }
 557  
 558        // Update $edit with any interim changes to $account.
 559        foreach ($account as $key => $value) {
 560          if (!property_exists($account->original, $key) || $value !== $account->original->$key) {
 561            $edit[$key] = $value;
 562          }
 563        }
 564        user_module_invoke('update', $edit, $account, $category);
 565        module_invoke_all('entity_update', $account, 'user');
 566      }
 567      else {
 568        // Allow 'uid' to be set by the caller. There is no danger of writing an
 569        // existing user as drupal_write_record will do an INSERT.
 570        if (empty($account->uid)) {
 571          $account->uid = db_next_id(db_query('SELECT MAX(uid) FROM {users}')->fetchField());
 572        }
 573        // Allow 'created' to be set by the caller.
 574        if (!isset($account->created)) {
 575          $account->created = REQUEST_TIME;
 576        }
 577        $success = drupal_write_record('users', $account);
 578        if ($success === FALSE) {
 579          // On a failed INSERT some other existing user's uid may be returned.
 580          // We must abort to avoid overwriting their account.
 581          return FALSE;
 582        }
 583  
 584        // Make sure $account is properly initialized.
 585        $account->roles[DRUPAL_AUTHENTICATED_RID] = 'authenticated user';
 586  
 587        field_attach_insert('user', $account);
 588        $edit = (array) $account;
 589        user_module_invoke('insert', $edit, $account, $category);
 590        module_invoke_all('entity_insert', $account, 'user');
 591  
 592        // Save user roles.
 593        if (count($account->roles) > 1) {
 594          $query = db_insert('users_roles')->fields(array('uid', 'rid'));
 595          foreach (array_keys($account->roles) as $rid) {
 596            if (!in_array($rid, array(DRUPAL_ANONYMOUS_RID, DRUPAL_AUTHENTICATED_RID))) {
 597              $query->values(array(
 598                'uid' => $account->uid,
 599                'rid' => $rid,
 600              ));
 601            }
 602          }
 603          $query->execute();
 604        }
 605      }
 606      // Clear internal properties.
 607      unset($account->is_new);
 608      unset($account->original);
 609      // Clear the static loading cache.
 610      entity_get_controller('user')->resetCache(array($account->uid));
 611  
 612      return $account;
 613    }
 614    catch (Exception $e) {
 615      $transaction->rollback();
 616      watchdog_exception('user', $e);
 617      throw $e;
 618    }
 619  }
 620  
 621  /**
 622   * Verify the syntax of the given name.
 623   */
 624  function user_validate_name($name) {
 625    if (!$name) {
 626      return t('You must enter a username.');
 627    }
 628    if (substr($name, 0, 1) == ' ') {
 629      return t('The username cannot begin with a space.');
 630    }
 631    if (substr($name, -1) == ' ') {
 632      return t('The username cannot end with a space.');
 633    }
 634    if (strpos($name, '  ') !== FALSE) {
 635      return t('The username cannot contain multiple spaces in a row.');
 636    }
 637    if (preg_match('/[^\x{80}-\x{F7} a-z0-9@_.\'-]/i', $name)) {
 638      return t('The username contains an illegal character.');
 639    }
 640    if (preg_match('/[\x{80}-\x{A0}' .         // Non-printable ISO-8859-1 + NBSP
 641                    '\x{AD}' .                // Soft-hyphen
 642                    '\x{2000}-\x{200F}' .     // Various space characters
 643                    '\x{2028}-\x{202F}' .     // Bidirectional text overrides
 644                    '\x{205F}-\x{206F}' .     // Various text hinting characters
 645                    '\x{FEFF}' .              // Byte order mark
 646                    '\x{FF01}-\x{FF60}' .     // Full-width latin
 647                    '\x{FFF9}-\x{FFFD}' .     // Replacement characters
 648                    '\x{0}-\x{1F}]/u',        // NULL byte and control characters
 649                    $name)) {
 650      return t('The username contains an illegal character.');
 651    }
 652    if (drupal_strlen($name) > USERNAME_MAX_LENGTH) {
 653      return t('The username %name is too long: it must be %max characters or less.', array('%name' => $name, '%max' => USERNAME_MAX_LENGTH));
 654    }
 655  }
 656  
 657  /**
 658   * Validates a user's email address.
 659   *
 660   * Checks that a user's email address exists and follows all standard
 661   * validation rules. Returns error messages when the address is invalid.
 662   *
 663   * @param $mail
 664   *   A user's email address.
 665   *
 666   * @return
 667   *   If the address is invalid, a human-readable error message is returned.
 668   *   If the address is valid, nothing is returned.
 669   */
 670  function user_validate_mail($mail) {
 671    if (!$mail) {
 672      return t('You must enter an e-mail address.');
 673    }
 674    if (!valid_email_address($mail)) {
 675      return t('The e-mail address %mail is not valid.', array('%mail' => $mail));
 676    }
 677  }
 678  
 679  /**
 680   * Validates an image uploaded by a user.
 681   *
 682   * @see user_account_form()
 683   */
 684  function user_validate_picture(&$form, &$form_state) {
 685    // If required, validate the uploaded picture.
 686    $validators = array(
 687      'file_validate_is_image' => array(),
 688      'file_validate_image_resolution' => array(variable_get('user_picture_dimensions', '85x85')),
 689      'file_validate_size' => array(variable_get('user_picture_file_size', '30') * 1024),
 690    );
 691  
 692    // Save the file as a temporary file.
 693    $file = file_save_upload('picture_upload', $validators);
 694    if ($file === FALSE) {
 695      form_set_error('picture_upload', t("Failed to upload the picture image; the %directory directory doesn't exist or is not writable.", array('%directory' => variable_get('user_picture_path', 'pictures'))));
 696    }
 697    elseif ($file !== NULL) {
 698      $form_state['values']['picture_upload'] = $file;
 699    }
 700  }
 701  
 702  /**
 703   * Generate a random alphanumeric password.
 704   */
 705  function user_password($length = 10) {
 706    // This variable contains the list of allowable characters for the
 707    // password. Note that the number 0 and the letter 'O' have been
 708    // removed to avoid confusion between the two. The same is true
 709    // of 'I', 1, and 'l'.
 710    $allowable_characters = 'abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789';
 711  
 712    // Zero-based count of characters in the allowable list:
 713    $len = strlen($allowable_characters) - 1;
 714  
 715    // Declare the password as a blank string.
 716    $pass = '';
 717  
 718    // Loop the number of times specified by $length.
 719    for ($i = 0; $i < $length; $i++) {
 720  
 721      // Each iteration, pick a random character from the
 722      // allowable string and append it to the password:
 723      $pass .= $allowable_characters[mt_rand(0, $len)];
 724    }
 725  
 726    return $pass;
 727  }
 728  
 729  /**
 730   * Determine the permissions for one or more roles.
 731   *
 732   * @param $roles
 733   *   An array whose keys are the role IDs of interest, such as $user->roles.
 734   *
 735   * @return
 736   *   An array indexed by role ID. Each value is an array whose keys are the
 737   *   permission strings for the given role ID.
 738   */
 739  function user_role_permissions($roles = array()) {
 740    $cache = &drupal_static(__FUNCTION__, array());
 741  
 742    $role_permissions = $fetch = array();
 743  
 744    if ($roles) {
 745      foreach ($roles as $rid => $name) {
 746        if (isset($cache[$rid])) {
 747          $role_permissions[$rid] = $cache[$rid];
 748        }
 749        else {
 750          // Add this rid to the list of those needing to be fetched.
 751          $fetch[] = $rid;
 752          // Prepare in case no permissions are returned.
 753          $cache[$rid] = array();
 754        }
 755      }
 756  
 757      if ($fetch) {
 758        // Get from the database permissions that were not in the static variable.
 759        // Only role IDs with at least one permission assigned will return rows.
 760        $result = db_query("SELECT rid, permission FROM {role_permission} WHERE rid IN (:fetch)", array(':fetch' => $fetch));
 761  
 762        foreach ($result as $row) {
 763          $cache[$row->rid][$row->permission] = TRUE;
 764        }
 765        foreach ($fetch as $rid) {
 766          // For every rid, we know we at least assigned an empty array.
 767          $role_permissions[$rid] = $cache[$rid];
 768        }
 769      }
 770    }
 771  
 772    return $role_permissions;
 773  }
 774  
 775  /**
 776   * Determine whether the user has a given privilege.
 777   *
 778   * @param $string
 779   *   The permission, such as "administer nodes", being checked for.
 780   * @param $account
 781   *   (optional) The account to check, if not given use currently logged in user.
 782   *
 783   * @return
 784   *   Boolean TRUE if the current user has the requested permission.
 785   *
 786   * All permission checks in Drupal should go through this function. This
 787   * way, we guarantee consistent behavior, and ensure that the superuser
 788   * can perform all actions.
 789   */
 790  function user_access($string, $account = NULL) {
 791    global $user;
 792  
 793    if (!isset($account)) {
 794      $account = $user;
 795    }
 796  
 797    // User #1 has all privileges:
 798    if ($account->uid == 1) {
 799      return TRUE;
 800    }
 801  
 802    // To reduce the number of SQL queries, we cache the user's permissions
 803    // in a static variable.
 804    // Use the advanced drupal_static() pattern, since this is called very often.
 805    static $drupal_static_fast;
 806    if (!isset($drupal_static_fast)) {
 807      $drupal_static_fast['perm'] = &drupal_static(__FUNCTION__);
 808    }
 809    $perm = &$drupal_static_fast['perm'];
 810    if (!isset($perm[$account->uid])) {
 811      $role_permissions = user_role_permissions($account->roles);
 812  
 813      $perms = array();
 814      foreach ($role_permissions as $one_role) {
 815        $perms += $one_role;
 816      }
 817      $perm[$account->uid] = $perms;
 818    }
 819  
 820    return isset($perm[$account->uid][$string]);
 821  }
 822  
 823  /**
 824   * Checks for usernames blocked by user administration.
 825   *
 826   * @param $name
 827   *   A string containing a name of the user.
 828   *
 829   * @return
 830   *   Object with property 'name' (the user name), if the user is blocked;
 831   *   FALSE if the user is not blocked.
 832   */
 833  function user_is_blocked($name) {
 834    return db_select('users')
 835      ->fields('users', array('name'))
 836      ->condition('name', db_like($name), 'LIKE')
 837      ->condition('status', 0)
 838      ->execute()->fetchObject();
 839  }
 840  
 841  /**
 842   * Implements hook_permission().
 843   */
 844  function user_permission() {
 845    return array(
 846      'administer permissions' =>  array(
 847        'title' => t('Administer permissions'),
 848        'restrict access' => TRUE,
 849      ),
 850      'administer users' => array(
 851        'title' => t('Administer users'),
 852        'restrict access' => TRUE,
 853      ),
 854      'access user profiles' => array(
 855        'title' => t('View user profiles'),
 856      ),
 857      'change own username' => array(
 858        'title' => t('Change own username'),
 859      ),
 860      'cancel account' => array(
 861        'title' => t('Cancel own user account'),
 862        'description' => t('Note: content may be kept, unpublished, deleted or transferred to the %anonymous-name user depending on the configured <a href="@user-settings-url">user settings</a>.', array('%anonymous-name' => variable_get('anonymous', t('Anonymous')), '@user-settings-url' => url('admin/config/people/accounts'))),
 863      ),
 864      'select account cancellation method' => array(
 865        'title' => t('Select method for cancelling own account'),
 866        'restrict access' => TRUE,
 867      ),
 868    );
 869  }
 870  
 871  /**
 872   * Implements hook_file_download().
 873   *
 874   * Ensure that user pictures (avatars) are always downloadable.
 875   */
 876  function user_file_download($uri) {
 877    if (strpos(file_uri_target($uri), variable_get('user_picture_path', 'pictures') . '/picture-') === 0) {
 878      $info = image_get_info($uri);
 879      return array('Content-Type' => $info['mime_type']);
 880    }
 881  }
 882  
 883  /**
 884   * Implements hook_file_move().
 885   */
 886  function user_file_move($file, $source) {
 887    // If a user's picture is replaced with a new one, update the record in
 888    // the users table.
 889    if (isset($file->fid) && isset($source->fid) && $file->fid != $source->fid) {
 890      db_update('users')
 891        ->fields(array(
 892          'picture' => $file->fid,
 893        ))
 894        ->condition('picture', $source->fid)
 895        ->execute();
 896    }
 897  }
 898  
 899  /**
 900   * Implements hook_file_delete().
 901   */
 902  function user_file_delete($file) {
 903    // Remove any references to the file.
 904    db_update('users')
 905      ->fields(array('picture' => 0))
 906      ->condition('picture', $file->fid)
 907      ->execute();
 908  }
 909  
 910  /**
 911   * Implements hook_search_info().
 912   */
 913  function user_search_info() {
 914    return array(
 915      'title' => 'Users',
 916    );
 917  }
 918  
 919  /**
 920   * Implements hook_search_access().
 921   */
 922  function user_search_access() {
 923    return user_access('access user profiles');
 924  }
 925  
 926  /**
 927   * Implements hook_search_execute().
 928   */
 929  function user_search_execute($keys = NULL, $conditions = NULL) {
 930    $find = array();
 931    // Replace wildcards with MySQL/PostgreSQL wildcards.
 932    $keys = preg_replace('!\*+!', '%', $keys);
 933    $query = db_select('users')->extend('PagerDefault');
 934    $query->fields('users', array('uid'));
 935    if (user_access('administer users')) {
 936      // Administrators can also search in the otherwise private email field.
 937      $query->fields('users', array('mail'));
 938      $query->condition(db_or()->
 939        condition('name', '%' . db_like($keys) . '%', 'LIKE')->
 940        condition('mail', '%' . db_like($keys) . '%', 'LIKE'));
 941    }
 942    else {
 943      $query->condition('name', '%' . db_like($keys) . '%', 'LIKE');
 944    }
 945    $uids = $query
 946      ->limit(15)
 947      ->execute()
 948      ->fetchCol();
 949    $accounts = user_load_multiple($uids);
 950  
 951    $results = array();
 952    foreach ($accounts as $account) {
 953      $result = array(
 954        'title' => format_username($account),
 955        'link' => url('user/' . $account->uid, array('absolute' => TRUE)),
 956      );
 957      if (user_access('administer users')) {
 958        $result['title'] .= ' (' . $account->mail . ')';
 959      }
 960      $results[] = $result;
 961    }
 962  
 963    return $results;
 964  }
 965  
 966  /**
 967   * Implements hook_element_info().
 968   */
 969  function user_element_info() {
 970    $types['user_profile_category'] = array(
 971      '#theme_wrappers' => array('user_profile_category'),
 972    );
 973    $types['user_profile_item'] = array(
 974      '#theme' => 'user_profile_item',
 975    );
 976    return $types;
 977  }
 978  
 979  /**
 980   * Implements hook_user_view().
 981   */
 982  function user_user_view($account) {
 983    $account->content['user_picture'] = array(
 984      '#markup' => theme('user_picture', array('account' => $account)),
 985      '#weight' => -10,
 986    );
 987    if (!isset($account->content['summary'])) {
 988      $account->content['summary'] = array();
 989    }
 990    $account->content['summary'] += array(
 991      '#type' => 'user_profile_category',
 992      '#attributes' => array('class' => array('user-member')),
 993      '#weight' => 5,
 994      '#title' => t('History'),
 995    );
 996    $account->content['summary']['member_for'] = array(
 997      '#type' => 'user_profile_item',
 998      '#title' => t('Member for'),
 999      '#markup' => format_interval(REQUEST_TIME - $account->created),
1000    );
1001  }
1002  
1003  /**
1004   * Helper function to add default user account fields to user registration and edit form.
1005   *
1006   * @see user_account_form_validate()
1007   * @see user_validate_current_pass()
1008   * @see user_validate_picture()
1009   * @see user_validate_mail()
1010   */
1011  function user_account_form(&$form, &$form_state) {
1012    global $user;
1013  
1014    $account = $form['#user'];
1015    $register = ($form['#user']->uid > 0 ? FALSE : TRUE);
1016  
1017    $admin = user_access('administer users');
1018  
1019    $form['#validate'][] = 'user_account_form_validate';
1020  
1021    // Account information.
1022    $form['account'] = array(
1023      '#type'   => 'container',
1024      '#weight' => -10,
1025    );
1026    // Only show name field on registration form or user can change own username.
1027    $form['account']['name'] = array(
1028      '#type' => 'textfield',
1029      '#title' => t('Username'),
1030      '#maxlength' => USERNAME_MAX_LENGTH,
1031      '#description' => t('Spaces are allowed; punctuation is not allowed except for periods, hyphens, apostrophes, and underscores.'),
1032      '#required' => TRUE,
1033      '#attributes' => array('class' => array('username')),
1034      '#default_value' => (!$register ? $account->name : ''),
1035      '#access' => ($register || ($user->uid == $account->uid && user_access('change own username')) || $admin),
1036      '#weight' => -10,
1037    );
1038  
1039    $form['account']['mail'] = array(
1040      '#type' => 'textfield',
1041      '#title' => t('E-mail address'),
1042      '#maxlength' => EMAIL_MAX_LENGTH,
1043      '#description' => t('A valid e-mail address. All e-mails from the system will be sent to this address. The e-mail address is not made public and will only be used if you wish to receive a new password or wish to receive certain news or notifications by e-mail.'),
1044      '#required' => TRUE,
1045      '#default_value' => (!$register ? $account->mail : ''),
1046    );
1047  
1048    // Display password field only for existing users or when user is allowed to
1049    // assign a password during registration.
1050    if (!$register) {
1051      $form['account']['pass'] = array(
1052        '#type' => 'password_confirm',
1053        '#size' => 25,
1054        '#description' => t('To change the current user password, enter the new password in both fields.'),
1055      );
1056      // To skip the current password field, the user must have logged in via a
1057      // one-time link and have the token in the URL.
1058      $pass_reset = isset($_SESSION['pass_reset_' . $account->uid]) && isset($_GET['pass-reset-token']) && ($_GET['pass-reset-token'] == $_SESSION['pass_reset_' . $account->uid]);
1059      $protected_values = array();
1060      $current_pass_description = '';
1061      // The user may only change their own password without their current
1062      // password if they logged in via a one-time login link.
1063      if (!$pass_reset) {
1064        $protected_values['mail'] = $form['account']['mail']['#title'];
1065        $protected_values['pass'] = t('Password');
1066        $request_new = l(t('Request new password'), 'user/password', array('attributes' => array('title' => t('Request new password via e-mail.'))));
1067        $current_pass_description = t('Enter your current password to change the %mail or %pass. !request_new.', array('%mail' => $protected_values['mail'], '%pass' => $protected_values['pass'], '!request_new' => $request_new));
1068      }
1069      // The user must enter their current password to change to a new one.
1070      if ($user->uid == $account->uid) {
1071        $form['account']['current_pass_required_values'] = array(
1072          '#type' => 'value',
1073          '#value' => $protected_values,
1074        );
1075        $form['account']['current_pass'] = array(
1076          '#type' => 'password',
1077          '#title' => t('Current password'),
1078          '#size' => 25,
1079          '#access' => !empty($protected_values),
1080          '#description' => $current_pass_description,
1081          '#weight' => -5,
1082          '#attributes' => array('autocomplete' => 'off'),
1083        );
1084        $form['#validate'][] = 'user_validate_current_pass';
1085      }
1086    }
1087    elseif (!variable_get('user_email_verification', TRUE) || $admin) {
1088      $form['account']['pass'] = array(
1089        '#type' => 'password_confirm',
1090        '#size' => 25,
1091        '#description' => t('Provide a password for the new account in both fields.'),
1092        '#required' => TRUE,
1093      );
1094    }
1095  
1096    if ($admin) {
1097      $status = isset($account->status) ? $account->status : 1;
1098    }
1099    else {
1100      $status = $register ? variable_get('user_register', USER_REGISTER_VISITORS_ADMINISTRATIVE_APPROVAL) == USER_REGISTER_VISITORS : $account->status;
1101    }
1102    $form['account']['status'] = array(
1103      '#type' => 'radios',
1104      '#title' => t('Status'),
1105      '#default_value' => $status,
1106      '#options' => array(t('Blocked'), t('Active')),
1107      '#access' => $admin,
1108    );
1109  
1110    $roles = array_map('check_plain', user_roles(TRUE));
1111    // The disabled checkbox subelement for the 'authenticated user' role
1112    // must be generated separately and added to the checkboxes element,
1113    // because of a limitation in Form API not supporting a single disabled
1114    // checkbox within a set of checkboxes.
1115    // @todo This should be solved more elegantly. See issue #119038.
1116    $checkbox_authenticated = array(
1117      '#type' => 'checkbox',
1118      '#title' => $roles[DRUPAL_AUTHENTICATED_RID],
1119      '#default_value' => TRUE,
1120      '#disabled' => TRUE,
1121    );
1122    unset($roles[DRUPAL_AUTHENTICATED_RID]);
1123    $form['account']['roles'] = array(
1124      '#type' => 'checkboxes',
1125      '#title' => t('Roles'),
1126      '#default_value' => (!$register && isset($account->roles) ? array_keys($account->roles) : array()),
1127      '#options' => $roles,
1128      '#access' => $roles && user_access('administer permissions'),
1129      DRUPAL_AUTHENTICATED_RID => $checkbox_authenticated,
1130    );
1131  
1132    $form['account']['notify'] = array(
1133      '#type' => 'checkbox',
1134      '#title' => t('Notify user of new account'),
1135      '#access' => $register && $admin,
1136    );
1137  
1138    // Signature.
1139    $form['signature_settings'] = array(
1140      '#type' => 'fieldset',
1141      '#title' => t('Signature settings'),
1142      '#weight' => 1,
1143      '#access' => (!$register && variable_get('user_signatures', 0)),
1144    );
1145  
1146    $form['signature_settings']['signature'] = array(
1147      '#type' => 'text_format',
1148      '#title' => t('Signature'),
1149      '#default_value' => isset($account->signature) ? $account->signature : '',
1150      '#description' => t('Your signature will be publicly displayed at the end of your comments.'),
1151      '#format' => isset($account->signature_format) ? $account->signature_format : NULL,
1152    );
1153  
1154    // Picture/avatar.
1155    $form['picture'] = array(
1156      '#type' => 'fieldset',
1157      '#title' => t('Picture'),
1158      '#weight' => 1,
1159      '#access' => (!$register && variable_get('user_pictures', 0)),
1160    );
1161    $form['picture']['picture'] = array(
1162      '#type' => 'value',
1163      '#value' => isset($account->picture) ? $account->picture : NULL,
1164    );
1165    $form['picture']['picture_current'] = array(
1166      '#markup' => theme('user_picture', array('account' => $account)),
1167    );
1168    $form['picture']['picture_delete'] = array(
1169      '#type' => 'checkbox',
1170      '#title' => t('Delete picture'),
1171      '#access' => !empty($account->picture->fid),
1172      '#description' => t('Check this box to delete your current picture.'),
1173    );
1174    $form['picture']['picture_upload'] = array(
1175      '#type' => 'file',
1176      '#title' => t('Upload picture'),
1177      '#size' => 48,
1178      '#description' => t('Your virtual face or picture. Pictures larger than @dimensions pixels will be scaled down.', array('@dimensions' => variable_get('user_picture_dimensions', '85x85'))) . ' ' . filter_xss_admin(variable_get('user_picture_guidelines', '')),
1179    );
1180    $form['#validate'][] = 'user_validate_picture';
1181  }
1182  
1183  /**
1184   * Form validation handler for the current password on the user_account_form().
1185   *
1186   * @see user_account_form()
1187   */
1188  function user_validate_current_pass(&$form, &$form_state) {
1189    $account = $form['#user'];
1190    foreach ($form_state['values']['current_pass_required_values'] as $key => $name) {
1191      // This validation only works for required textfields (like mail) or
1192      // form values like password_confirm that have their own validation
1193      // that prevent them from being empty if they are changed.
1194      if ((strlen(trim($form_state['values'][$key])) > 0) && ($form_state['values'][$key] != $account->$key)) {
1195        require_once DRUPAL_ROOT . '/' . variable_get('password_inc', 'includes/password.inc');
1196        $current_pass_failed = empty($form_state['values']['current_pass']) || !user_check_password($form_state['values']['current_pass'], $account);
1197        if ($current_pass_failed) {
1198          form_set_error('current_pass', t("Your current password is missing or incorrect; it's required to change the %name.", array('%name' => $name)));
1199          form_set_error($key);
1200        }
1201        // We only need to check the password once.
1202        break;
1203      }
1204    }
1205  }
1206  
1207  /**
1208   * Form validation handler for user_account_form().
1209   *
1210   * @see user_account_form()
1211   */
1212  function user_account_form_validate($form, &$form_state) {
1213    if ($form['#user_category'] == 'account' || $form['#user_category'] == 'register') {
1214      $account = $form['#user'];
1215      // Validate new or changing username.
1216      if (isset($form_state['values']['name'])) {
1217        if ($error = user_validate_name($form_state['values']['name'])) {
1218          form_set_error('name', $error);
1219        }
1220        elseif ((bool) db_select('users')->fields('users', array('uid'))->condition('uid', $account->uid, '<>')->condition('name', db_like($form_state['values']['name']), 'LIKE')->range(0, 1)->execute()->fetchField()) {
1221          form_set_error('name', t('The name %name is already taken.', array('%name' => $form_state['values']['name'])));
1222        }
1223      }
1224  
1225      // Trim whitespace from mail, to prevent confusing 'e-mail not valid'
1226      // warnings often caused by cutting and pasting.
1227      $mail = trim($form_state['values']['mail']);
1228      form_set_value($form['account']['mail'], $mail, $form_state);
1229  
1230      // Validate the e-mail address, and check if it is taken by an existing user.
1231      if ($error = user_validate_mail($form_state['values']['mail'])) {
1232        form_set_error('mail', $error);
1233      }
1234      elseif ((bool) db_select('users')->fields('users', array('uid'))->condition('uid', $account->uid, '<>')->condition('mail', db_like($form_state['values']['mail']), 'LIKE')->range(0, 1)->execute()->fetchField()) {
1235        // Format error message dependent on whether the user is logged in or not.
1236        if ($GLOBALS['user']->uid) {
1237          form_set_error('mail', t('The e-mail address %email is already taken.', array('%email' => $form_state['values']['mail'])));
1238        }
1239        else {
1240          form_set_error('mail', t('The e-mail address %email is already registered. <a href="@password">Have you forgotten your password?</a>', array('%email' => $form_state['values']['mail'], '@password' => url('user/password'))));
1241        }
1242      }
1243  
1244      // Make sure the signature isn't longer than the size of the database field.
1245      // Signatures are disabled by default, so make sure it exists first.
1246      if (isset($form_state['values']['signature'])) {
1247        // Move text format for user signature into 'signature_format'.
1248        $form_state['values']['signature_format'] = $form_state['values']['signature']['format'];
1249        // Move text value for user signature into 'signature'.
1250        $form_state['values']['signature'] = $form_state['values']['signature']['value'];
1251  
1252        $user_schema = drupal_get_schema('users');
1253        if (drupal_strlen($form_state['values']['signature']) > $user_schema['fields']['signature']['length']) {
1254          form_set_error('signature', t('The signature is too long: it must be %max characters or less.', array('%max' => $user_schema['fields']['signature']['length'])));
1255        }
1256      }
1257    }
1258  }
1259  
1260  /**
1261   * Implements hook_user_presave().
1262   */
1263  function user_user_presave(&$edit, $account, $category) {
1264    if ($category == 'account' || $category == 'register') {
1265      if (!empty($edit['picture_upload'])) {
1266        $edit['picture'] = $edit['picture_upload'];
1267      }
1268      // Delete picture if requested, and if no replacement picture was given.
1269      elseif (!empty($edit['picture_delete'])) {
1270        $edit['picture'] = NULL;
1271      }
1272      // Prepare user roles.
1273      if (isset($edit['roles'])) {
1274        $edit['roles'] = array_filter($edit['roles']);
1275      }
1276    }
1277  
1278    // Move account cancellation information into $user->data.
1279    foreach (array('user_cancel_method', 'user_cancel_notify') as $key) {
1280      if (isset($edit[$key])) {
1281        $edit['data'][$key] = $edit[$key];
1282      }
1283    }
1284  }
1285  
1286  /**
1287   * Implements hook_user_categories().
1288   */
1289  function user_user_categories() {
1290    return array(array(
1291      'name' => 'account',
1292      'title' => t('Account settings'),
1293      'weight' => 1,
1294    ));
1295  }
1296  
1297  function user_login_block($form) {
1298    $form['#action'] = url(current_path(), array('query' => drupal_get_destination(), 'external' => FALSE));
1299    $form['#id'] = 'user-login-form';
1300    $form['#validate'] = user_login_default_validators();
1301    $form['#submit'][] = 'user_login_submit';
1302    $form['name'] = array('#type' => 'textfield',
1303      '#title' => t('Username'),
1304      '#maxlength' => USERNAME_MAX_LENGTH,
1305      '#size' => 15,
1306      '#required' => TRUE,
1307    );
1308    $form['pass'] = array('#type' => 'password',
1309      '#title' => t('Password'),
1310      '#size' => 15,
1311      '#required' => TRUE,
1312    );
1313    $form['actions'] = array('#type' => 'actions');
1314    $form['actions']['submit'] = array('#type' => 'submit',
1315      '#value' => t('Log in'),
1316    );
1317    $items = array();
1318    if (variable_get('user_register', USER_REGISTER_VISITORS_ADMINISTRATIVE_APPROVAL)) {
1319      $items[] = l(t('Create new account'), 'user/register', array('attributes' => array('title' => t('Create a new user account.'))));
1320    }
1321    $items[] = l(t('Request new password'), 'user/password', array('attributes' => array('title' => t('Request new password via e-mail.'))));
1322    $form['links'] = array('#markup' => theme('item_list', array('items' => $items)));
1323    return $form;
1324  }
1325  
1326  /**
1327   * Implements hook_block_info().
1328   */
1329  function user_block_info() {
1330    global $user;
1331  
1332    $blocks['login']['info'] = t('User login');
1333    // Not worth caching.
1334    $blocks['login']['cache'] = DRUPAL_NO_CACHE;
1335  
1336    $blocks['new']['info'] = t('Who\'s new');
1337    $blocks['new']['properties']['administrative'] = TRUE;
1338  
1339    // Too dynamic to cache.
1340    $blocks['online']['info'] = t('Who\'s online');
1341    $blocks['online']['cache'] = DRUPAL_NO_CACHE;
1342    $blocks['online']['properties']['administrative'] = TRUE;
1343  
1344    return $blocks;
1345  }
1346  
1347  /**
1348   * Implements hook_block_configure().
1349   */
1350  function user_block_configure($delta = '') {
1351    global $user;
1352  
1353    switch ($delta) {
1354      case 'new':
1355        $form['user_block_whois_new_count'] = array(
1356          '#type' => 'select',
1357          '#title' => t('Number of users to display'),
1358          '#default_value' => variable_get('user_block_whois_new_count', 5),
1359          '#options' => drupal_map_assoc(array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)),
1360        );
1361        return $form;
1362  
1363      case 'online':
1364        $period = drupal_map_assoc(array(30, 60, 120, 180, 300, 600, 900, 1800, 2700, 3600, 5400, 7200, 10800, 21600, 43200, 86400), 'format_interval');
1365        $form['user_block_seconds_online'] = array('#type' => 'select', '#title' => t('User activity'), '#default_value' => variable_get('user_block_seconds_online', 900), '#options' => $period, '#description' => t('A user is considered online for this long after they have last viewed a page.'));
1366        $form['user_block_max_list_count'] = array('#type' => 'select', '#title' => t('User list length'), '#default_value' => variable_get('user_block_max_list_count', 10), '#options' => drupal_map_assoc(array(0, 5, 10, 15, 20, 25, 30, 40, 50, 75, 100)), '#description' => t('Maximum number of currently online users to display.'));
1367        return $form;
1368    }
1369  }
1370  
1371  /**
1372   * Implements hook_block_save().
1373   */
1374  function user_block_save($delta = '', $edit = array()) {
1375    global $user;
1376  
1377    switch ($delta) {
1378      case 'new':
1379        variable_set('user_block_whois_new_count', $edit['user_block_whois_new_count']);
1380        break;
1381  
1382      case 'online':
1383        variable_set('user_block_seconds_online', $edit['user_block_seconds_online']);
1384        variable_set('user_block_max_list_count', $edit['user_block_max_list_count']);
1385        break;
1386    }
1387  }
1388  
1389  /**
1390   * Implements hook_block_view().
1391   */
1392  function user_block_view($delta = '') {
1393    global $user;
1394  
1395    $block = array();
1396  
1397    switch ($delta) {
1398      case 'login':
1399        // For usability's sake, avoid showing two login forms on one page.
1400        if (!$user->uid && !(arg(0) == 'user' && !is_numeric(arg(1)))) {
1401  
1402          $block['subject'] = t('User login');
1403          $block['content'] = drupal_get_form('user_login_block');
1404        }
1405        return $block;
1406  
1407      case 'new':
1408        if (user_access('access content')) {
1409          // Retrieve a list of new users who have subsequently accessed the site successfully.
1410          $items = db_query_range('SELECT uid, name FROM {users} WHERE status <> 0 AND access <> 0 ORDER BY created DESC', 0, variable_get('user_block_whois_new_count', 5))->fetchAll();
1411          $output = theme('user_list', array('users' => $items));
1412  
1413          $block['subject'] = t('Who\'s new');
1414          $block['content'] = $output;
1415        }
1416        return $block;
1417  
1418      case 'online':
1419        if (user_access('access content')) {
1420          // Count users active within the defined period.
1421          $interval = REQUEST_TIME - variable_get('user_block_seconds_online', 900);
1422  
1423          // Perform database queries to gather online user lists. We use s.timestamp
1424          // rather than u.access because it is much faster.
1425          $authenticated_count = db_query("SELECT COUNT(DISTINCT s.uid) FROM {sessions} s WHERE s.timestamp >= :timestamp AND s.uid > 0", array(':timestamp' => $interval))->fetchField();
1426  
1427          $output = '<p>' . format_plural($authenticated_count, 'There is currently 1 user online.', 'There are currently @count users online.') . '</p>';
1428  
1429          // Display a list of currently online users.
1430          $max_users = variable_get('user_block_max_list_count', 10);
1431          if ($authenticated_count && $max_users) {
1432            $items = db_query_range('SELECT u.uid, u.name, MAX(s.timestamp) AS max_timestamp FROM {users} u INNER JOIN {sessions} s ON u.uid = s.uid WHERE s.timestamp >= :interval AND s.uid > 0 GROUP BY u.uid, u.name ORDER BY max_timestamp DESC', 0, $max_users, array(':interval' => $interval))->fetchAll();
1433            $output .= theme('user_list', array('users' => $items));
1434          }
1435  
1436          $block['subject'] = t('Who\'s online');
1437          $block['content'] = $output;
1438        }
1439        return $block;
1440    }
1441  }
1442  
1443  /**
1444   * Process variables for user-picture.tpl.php.
1445   *
1446   * The $variables array contains the following arguments:
1447   * - $account: A user, node or comment object with 'name', 'uid' and 'picture'
1448   *   fields.
1449   *
1450   * @see user-picture.tpl.php
1451   */
1452  function template_preprocess_user_picture(&$variables) {
1453    $variables['user_picture'] = '';
1454    if (variable_get('user_pictures', 0)) {
1455      $account = $variables['account'];
1456      if (!empty($account->picture)) {
1457        // @TODO: Ideally this function would only be passed file objects, but
1458        // since there's a lot of legacy code that JOINs the {users} table to
1459        // {node} or {comments} and passes the results into this function if we
1460        // a numeric value in the picture field we'll assume it's a file id
1461        // and load it for them. Once we've got user_load_multiple() and
1462        // comment_load_multiple() functions the user module will be able to load
1463        // the picture files in mass during the object's load process.
1464        if (is_numeric($account->picture)) {
1465          $account->picture = file_load($account->picture);
1466        }
1467        if (!empty($account->picture->uri)) {
1468          $filepath = $account->picture->uri;
1469        }
1470      }
1471      elseif (variable_get('user_picture_default', '')) {
1472        $filepath = variable_get('user_picture_default', '');
1473      }
1474      if (isset($filepath)) {
1475        $alt = t("@user's picture", array('@user' => format_username($account)));
1476        // If the image does not have a valid Drupal scheme (for eg. HTTP),
1477        // don't load image styles.
1478        if (module_exists('image') && file_valid_uri($filepath) && $style = variable_get('user_picture_style', '')) {
1479          $variables['user_picture'] = theme('image_style', array('style_name' => $style, 'path' => $filepath, 'alt' => $alt, 'title' => $alt));
1480        }
1481        else {
1482          $variables['user_picture'] = theme('image', array('path' => $filepath, 'alt' => $alt, 'title' => $alt));
1483        }
1484        if (!empty($account->uid) && user_access('access user profiles')) {
1485          $attributes = array('attributes' => array('title' => t('View user profile.')), 'html' => TRUE);
1486          $variables['user_picture'] = l($variables['user_picture'], "user/$account->uid", $attributes);
1487        }
1488      }
1489    }
1490  }
1491  
1492  /**
1493   * Returns HTML for a list of users.
1494   *
1495   * @param $variables
1496   *   An associative array containing:
1497   *   - users: An array with user objects. Should contain at least the name and
1498   *     uid.
1499   *   - title: (optional) Title to pass on to theme_item_list().
1500   *
1501   * @ingroup themeable
1502   */
1503  function theme_user_list($variables) {
1504    $users = $variables['users'];
1505    $title = $variables['title'];
1506    $items = array();
1507  
1508    if (!empty($users)) {
1509      foreach ($users as $user) {
1510        $items[] = theme('username', array('account' => $user));
1511      }
1512    }
1513    return theme('item_list', array('items' => $items, 'title' => $title));
1514  }
1515  
1516  function user_is_anonymous() {
1517    // Menu administrators can see items for anonymous when administering.
1518    return !$GLOBALS['user']->uid || !empty($GLOBALS['menu_admin']);
1519  }
1520  
1521  function user_is_logged_in() {
1522    return (bool) $GLOBALS['user']->uid;
1523  }
1524  
1525  function user_register_access() {
1526    return user_is_anonymous() && variable_get('user_register', USER_REGISTER_VISITORS_ADMINISTRATIVE_APPROVAL);
1527  }
1528  
1529  /**
1530   * User view access callback.
1531   *
1532   * @param $account
1533   *   Can either be a full user object or a $uid.
1534   */
1535  function user_view_access($account) {
1536    $uid = is_object($account) ? $account->uid : (int) $account;
1537  
1538    // Never allow access to view the anonymous user account.
1539    if ($uid) {
1540      // Admins can view all, users can view own profiles at all times.
1541      if ($GLOBALS['user']->uid == $uid || user_access('administer users')) {
1542        return TRUE;
1543      }
1544      elseif (user_access('access user profiles')) {
1545        // At this point, load the complete account object.
1546        if (!is_object($account)) {
1547          $account = user_load($uid);
1548        }
1549        return (is_object($account) && $account->status);
1550      }
1551    }
1552    return FALSE;
1553  }
1554  
1555  /**
1556   * Access callback for user account editing.
1557   */
1558  function user_edit_access($account) {
1559    return (($GLOBALS['user']->uid == $account->uid) || user_access('administer users')) && $account->uid > 0;
1560  }
1561  
1562  /**
1563   * Menu access callback; limit access to account cancellation pages.
1564   *
1565   * Limit access to users with the 'cancel account' permission or administrative
1566   * users, and prevent the anonymous user from cancelling the account.
1567   */
1568  function user_cancel_access($account) {
1569    return ((($GLOBALS['user']->uid == $account->uid) && user_access('cancel account')) || user_access('administer users')) && $account->uid > 0;
1570  }
1571  
1572  /**
1573   * Implements hook_menu().
1574   */
1575  function user_menu() {
1576    $items['user/autocomplete'] = array(
1577      'title' => 'User autocomplete',
1578      'page callback' => 'user_autocomplete',
1579      'access callback' => 'user_access',
1580      'access arguments' => array('access user profiles'),
1581      'type' => MENU_CALLBACK,
1582      'file' => 'user.pages.inc',
1583    );
1584  
1585    // Registration and login pages.
1586    $items['user'] = array(
1587      'title' => 'User account',
1588      'title callback' => 'user_menu_title',
1589      'page callback' => 'user_page',
1590      'access callback' => TRUE,
1591      'file' => 'user.pages.inc',
1592      'weight' => -10,
1593      'menu_name' => 'user-menu',
1594    );
1595  
1596    $items['user/login'] = array(
1597      'title' => 'Log in',
1598      'access callback' => 'user_is_anonymous',
1599      'type' => MENU_DEFAULT_LOCAL_TASK,
1600    );
1601  
1602    $items['user/register'] = array(
1603      'title' => 'Create new account',
1604      'page callback' => 'drupal_get_form',
1605      'page arguments' => array('user_register_form'),
1606      'access callback' => 'user_register_access',
1607      'type' => MENU_LOCAL_TASK,
1608    );
1609  
1610    $items['user/password'] = array(
1611      'title' => 'Request new password',
1612      'page callback' => 'drupal_get_form',
1613      'page arguments' => array('user_pass'),
1614      'access callback' => TRUE,
1615      'type' => MENU_LOCAL_TASK,
1616      'file' => 'user.pages.inc',
1617    );
1618    $items['user/reset/%/%/%'] = array(
1619      'title' => 'Reset password',
1620      'page callback' => 'drupal_get_form',
1621      'page arguments' => array('user_pass_reset', 2, 3, 4),
1622      'access callback' => TRUE,
1623      'type' => MENU_CALLBACK,
1624      'file' => 'user.pages.inc',
1625    );
1626  
1627    $items['user/logout'] = array(
1628      'title' => 'Log out',
1629      'access callback' => 'user_is_logged_in',
1630      'page callback' => 'user_logout',
1631      'weight' => 10,
1632      'menu_name' => 'user-menu',
1633      'file' => 'user.pages.inc',
1634    );
1635  
1636    // User listing pages.
1637    $items['admin/people'] = array(
1638      'title' => 'People',
1639      'description' => 'Manage user accounts, roles, and permissions.',
1640      'page callback' => 'user_admin',
1641      'page arguments' => array('list'),
1642      'access arguments' => array('administer users'),
1643      'position' => 'left',
1644      'weight' => -4,
1645      'file' => 'user.admin.inc',
1646    );
1647    $items['admin/people/people'] = array(
1648      'title' => 'List',
1649      'description' => 'Find and manage people interacting with your site.',
1650      'access arguments' => array('administer users'),
1651      'type' => MENU_DEFAULT_LOCAL_TASK,
1652      'weight' => -10,
1653      'file' => 'user.admin.inc',
1654    );
1655  
1656    // Permissions and role forms.
1657    $items['admin/people/permissions'] = array(
1658      'title' => 'Permissions',
1659      'description' => 'Determine access to features by selecting permissions for roles.',
1660      'page callback' => 'drupal_get_form',
1661      'page arguments' => array('user_admin_permissions'),
1662      'access arguments' => array('administer permissions'),
1663      'file' => 'user.admin.inc',
1664      'type' => MENU_LOCAL_TASK,
1665    );
1666    $items['admin/people/permissions/list'] = array(
1667      'title' => 'Permissions',
1668      'description' => 'Determine access to features by selecting permissions for roles.',
1669      'type' => MENU_DEFAULT_LOCAL_TASK,
1670      'weight' => -8,
1671    );
1672    $items['admin/people/permissions/roles'] = array(
1673      'title' => 'Roles',
1674      'description' => 'List, edit, or add user roles.',
1675      'page callback' => 'drupal_get_form',
1676      'page arguments' => array('user_admin_roles'),
1677      'access arguments' => array('administer permissions'),
1678      'file' => 'user.admin.inc',
1679      'type' => MENU_LOCAL_TASK,
1680      'weight' => -5,
1681    );
1682    $items['admin/people/permissions/roles/edit/%user_role'] = array(
1683      'title' => 'Edit role',
1684      'page arguments' => array('user_admin_role', 5),
1685      'access callback' => 'user_role_edit_access',
1686      'access arguments' => array(5),
1687    );
1688    $items['admin/people/permissions/roles/delete/%user_role'] = array(
1689      'title' => 'Delete role',
1690      'page callback' => 'drupal_get_form',
1691      'page arguments' => array('user_admin_role_delete_confirm', 5),
1692      'access callback' => 'user_role_edit_access',
1693      'access arguments' => array(5),
1694      'file' => 'user.admin.inc',
1695    );
1696  
1697    $items['admin/people/create'] = array(
1698      'title' => 'Add user',
1699      'page arguments' => array('create'),
1700      'access arguments' => array('administer users'),
1701      'type' => MENU_LOCAL_ACTION,
1702    );
1703  
1704    // Administration pages.
1705    $items['admin/config/people'] = array(
1706     'title' => 'People',
1707     'description' => 'Configure user accounts.',
1708     'position' => 'left',
1709     'weight' => -20,
1710     'page callback' => 'system_admin_menu_block_page',
1711     'access arguments' => array('access administration pages'),
1712     'file' => 'system.admin.inc',
1713     'file path' => drupal_get_path('module', 'system'),
1714    );
1715    $items['admin/config/people/accounts'] = array(
1716      'title' => 'Account settings',
1717      'description' => 'Configure default behavior of users, including registration requirements, e-mails, fields, and user pictures.',
1718      'page callback' => 'drupal_get_form',
1719      'page arguments' => array('user_admin_settings'),
1720      'access arguments' => array('administer users'),
1721      'file' => 'user.admin.inc',
1722      'weight' => -10,
1723    );
1724    $items['admin/config/people/accounts/settings'] = array(
1725      'title' => 'Settings',
1726      'type' => MENU_DEFAULT_LOCAL_TASK,
1727      'weight' => -10,
1728    );
1729  
1730    $items['user/%user'] = array(
1731      'title' => 'My account',
1732      'title callback' => 'user_page_title',
1733      'title arguments' => array(1),
1734      'page callback' => 'user_view_page',
1735      'page arguments' => array(1),
1736      'access callback' => 'user_view_access',
1737      'access arguments' => array(1),
1738      // By assigning a different menu name, this item (and all registered child
1739      // paths) are no longer considered as children of 'user'. When accessing the
1740      // user account pages, the preferred menu link that is used to build the
1741      // active trail (breadcrumb) will be found in this menu (unless there is
1742      // more specific link), so the link to 'user' will not be in the breadcrumb.
1743      'menu_name' => 'navigation',
1744    );
1745  
1746    $items['user/%user/view'] = array(
1747      'title' => 'View',
1748      'type' => MENU_DEFAULT_LOCAL_TASK,
1749      'weight' => -10,
1750    );
1751  
1752    $items['user/%user/cancel'] = array(
1753      'title' => 'Cancel account',
1754      'page callback' => 'drupal_get_form',
1755      'page arguments' => array('user_cancel_confirm_form', 1),
1756      'access callback' => 'user_cancel_access',
1757      'access arguments' => array(1),
1758      'file' => 'user.pages.inc',
1759    );
1760  
1761    $items['user/%user/cancel/confirm/%/%'] = array(
1762      'title' => 'Confirm account cancellation',
1763      'page callback' => 'user_cancel_confirm',
1764      'page arguments' => array(1, 4, 5),
1765      'access callback' => 'user_cancel_access',
1766      'access arguments' => array(1),
1767      'file' => 'user.pages.inc',
1768    );
1769  
1770    $items['user/%user/edit'] = array(
1771      'title' => 'Edit',
1772      'page callback' => 'drupal_get_form',
1773      'page arguments' => array('user_profile_form', 1),
1774      'access callback' => 'user_edit_access',
1775      'access arguments' => array(1),
1776      'type' => MENU_LOCAL_TASK,
1777      'file' => 'user.pages.inc',
1778    );
1779  
1780    $items['user/%user_category/edit/account'] = array(
1781      'title' => 'Account',
1782      'type' => MENU_DEFAULT_LOCAL_TASK,
1783      'load arguments' => array('%map', '%index'),
1784    );
1785  
1786    if (($categories = _user_categories()) && (count($categories) > 1)) {
1787      foreach ($categories as $key => $category) {
1788        // 'account' is already handled by the MENU_DEFAULT_LOCAL_TASK.
1789        if ($category['name'] != 'account') {
1790          $items['user/%user_category/edit/' . $category['name']] = array(
1791            'title callback' => 'check_plain',
1792            'title arguments' => array($category['title']),
1793            'page callback' => 'drupal_get_form',
1794            'page arguments' => array('user_profile_form', 1, 3),
1795            'access callback' => isset($category['access callback']) ? $category['access callback'] : 'user_edit_access',
1796            'access arguments' => isset($category['access arguments']) ? $category['access arguments'] : array(1),
1797            'type' => MENU_LOCAL_TASK,
1798            'weight' => $category['weight'],
1799            'load arguments' => array('%map', '%index'),
1800            'tab_parent' => 'user/%/edit',
1801            'file' => 'user.pages.inc',
1802          );
1803        }
1804      }
1805    }
1806    return $items;
1807  }
1808  
1809  /**
1810   * Implements hook_menu_site_status_alter().
1811   */
1812  function user_menu_site_status_alter(&$menu_site_status, $path) {
1813    if ($menu_site_status == MENU_SITE_OFFLINE) {
1814      // If the site is offline, log out unprivileged users.
1815      if (user_is_logged_in() && !user_access('access site in maintenance mode')) {
1816        module_load_include('pages.inc', 'user', 'user');
1817        user_logout();
1818      }
1819  
1820      if (user_is_anonymous()) {
1821        switch ($path) {
1822          case 'user':
1823            // Forward anonymous user to login page.
1824            drupal_goto('user/login');
1825          case 'user/login':
1826          case 'user/password':
1827            // Disable offline mode.
1828            $menu_site_status = MENU_SITE_ONLINE;
1829            break;
1830          default:
1831            if (strpos($path, 'user/reset/') === 0) {
1832              // Disable offline mode.
1833              $menu_site_status = MENU_SITE_ONLINE;
1834            }
1835            break;
1836        }
1837      }
1838    }
1839    if (user_is_logged_in()) {
1840      if ($path == 'user/login') {
1841        // If user is logged in, redirect to 'user' instead of giving 403.
1842        drupal_goto('user');
1843      }
1844      if ($path == 'user/register') {
1845        // Authenticated user should be redirected to user edit page.
1846        drupal_goto('user/' . $GLOBALS['user']->uid . '/edit');
1847      }
1848    }
1849  }
1850  
1851  /**
1852   * Implements hook_menu_link_alter().
1853   */
1854  function user_menu_link_alter(&$link) {
1855    // The path 'user' must be accessible for anonymous users, but only visible
1856    // for authenticated users. Authenticated users should see "My account", but
1857    // anonymous users should not see it at all. Therefore, invoke
1858    // user_translated_menu_link_alter() to conditionally hide the link.
1859    if ($link['link_path'] == 'user' && $link['module'] == 'system') {
1860      $link['options']['alter'] = TRUE;
1861    }
1862  
1863    // Force the Logout link to appear on the top-level of 'user-menu' menu by
1864    // default (i.e., unless it has been customized).
1865    if ($link['link_path'] == 'user/logout' && $link['module'] == 'system' && empty($link['customized'])) {
1866      $link['plid'] = 0;
1867    }
1868  }
1869  
1870  /**
1871   * Implements hook_translated_menu_link_alter().
1872   */
1873  function user_translated_menu_link_alter(&$link) {
1874    // Hide the "User account" link for anonymous users.
1875    if ($link['link_path'] == 'user' && $link['module'] == 'system' && !$GLOBALS['user']->uid) {
1876      $link['hidden'] = 1;
1877    }
1878  }
1879  
1880  /**
1881   * Implements hook_admin_paths().
1882   */
1883  function user_admin_paths() {
1884    $paths = array(
1885      'user/*/cancel' => TRUE,
1886      'user/*/edit' => TRUE,
1887      'user/*/edit/*' => TRUE,
1888    );
1889    return $paths;
1890  }
1891  
1892  /**
1893   * Returns $arg or the user ID of the current user if $arg is '%' or empty.
1894   *
1895   * Deprecated. Use %user_uid_optional instead.
1896   *
1897   * @todo D8: Remove.
1898   */
1899  function user_uid_only_optional_to_arg($arg) {
1900    return user_uid_optional_to_arg($arg);
1901  }
1902  
1903  /**
1904   * Load either a specified or the current user account.
1905   *
1906   * @param $uid
1907   *   An optional user ID of the user to load. If not provided, the current
1908   *   user's ID will be used.
1909   * @return
1910   *   A fully-loaded $user object upon successful user load, FALSE if user
1911   *   cannot be loaded.
1912   *
1913   * @see user_load()
1914   * @todo rethink the naming of this in Drupal 8.
1915   */
1916  function user_uid_optional_load($uid = NULL) {
1917    if (!isset($uid)) {
1918      $uid = $GLOBALS['user']->uid;
1919    }
1920    return user_load($uid);
1921  }
1922  
1923  /**
1924   * Return a user object after checking if any profile category in the path exists.
1925   */
1926  function user_category_load($uid, &$map, $index) {
1927    static $user_categories, $accounts;
1928  
1929    // Cache $account - this load function will get called for each profile tab.
1930    if (!isset($accounts[$uid])) {
1931      $accounts[$uid] = user_load($uid);
1932    }
1933    $valid = TRUE;
1934    if ($account = $accounts[$uid]) {
1935      // Since the path is like user/%/edit/category_name, the category name will
1936      // be at a position 2 beyond the index corresponding to the % wildcard.
1937      $category_index = $index + 2;
1938      // Valid categories may contain slashes, and hence need to be imploded.
1939      $category_path = implode('/', array_slice($map, $category_index));
1940      if ($category_path) {
1941        // Check that the requested category exists.
1942        $valid = FALSE;
1943        if (!isset($user_categories)) {
1944          $user_categories = _user_categories();
1945        }
1946        foreach ($user_categories as $category) {
1947          if ($category['name'] == $category_path) {
1948            $valid = TRUE;
1949            // Truncate the map array in case the category name had slashes.
1950            $map = array_slice($map, 0, $category_index);
1951            // Assign the imploded category name to the last map element.
1952            $map[$category_index] = $category_path;
1953            break;
1954          }
1955        }
1956      }
1957    }
1958    return $valid ? $account : FALSE;
1959  }
1960  
1961  /**
1962   * Returns $arg or the user ID of the current user if $arg is '%' or empty.
1963   *
1964   * @todo rethink the naming of this in Drupal 8.
1965   */
1966  function user_uid_optional_to_arg($arg) {
1967    // Give back the current user uid when called from eg. tracker, aka.
1968    // with an empty arg. Also use the current user uid when called from
1969    // the menu with a % for the current account link.
1970    return empty($arg) || $arg == '%' ? $GLOBALS['user']->uid : $arg;
1971  }
1972  
1973  /**
1974   * Menu item title callback for the 'user' path.
1975   *
1976   * Anonymous users should see "User account", but authenticated users are
1977   * expected to see "My account".
1978   */
1979  function user_menu_title() {
1980    return user_is_logged_in() ? t('My account') : t('User account');
1981  }
1982  
1983  /**
1984   * Menu item title callback - use the user name.
1985   */
1986  function user_page_title($account) {
1987    return is_object($account) ? format_username($account) : '';
1988  }
1989  
1990  /**
1991   * Discover which external authentication module(s) authenticated a username.
1992   *
1993   * @param $authname
1994   *   A username used by an external authentication module.
1995   * @return
1996   *   An associative array with module as key and username as value.
1997   */
1998  function user_get_authmaps($authname = NULL) {
1999    $authmaps = db_query("SELECT module, authname FROM {authmap} WHERE authname = :authname", array(':authname' => $authname))->fetchAllKeyed();
2000    return count($authmaps) ? $authmaps : 0;
2001  }
2002  
2003  /**
2004   * Save mappings of which external authentication module(s) authenticated
2005   * a user. Maps external usernames to user ids in the users table.
2006   *
2007   * @param $account
2008   *   A user object.
2009   * @param $authmaps
2010   *   An associative array with a compound key and the username as the value.
2011   *   The key is made up of 'authname_' plus the name of the external authentication
2012   *   module.
2013   * @see user_external_login_register()
2014   */
2015  function user_set_authmaps($account, $authmaps) {
2016    foreach ($authmaps as $key => $value) {
2017      $module = explode('_', $key, 2);
2018      if ($value) {
2019        db_merge('authmap')
2020          ->key(array(
2021            'uid' => $account->uid,
2022            'module' => $module[1],
2023          ))
2024          ->fields(array('authname' => $value))
2025          ->execute();
2026      }
2027      else {
2028        db_delete('authmap')
2029          ->condition('uid', $account->uid)
2030          ->condition('module', $module[1])
2031          ->execute();
2032      }
2033    }
2034  }
2035  
2036  /**
2037   * Form builder; the main user login form.
2038   *
2039   * @ingroup forms
2040   */
2041  function user_login($form, &$form_state) {
2042    global $user;
2043  
2044    // If we are already logged on, go to the user page instead.
2045    if ($user->uid) {
2046      drupal_goto('user/' . $user->uid);
2047    }
2048  
2049    // Display login form:
2050    $form['name'] = array('#type' => 'textfield',
2051      '#title' => t('Username'),
2052      '#size' => 60,
2053      '#maxlength' => USERNAME_MAX_LENGTH,
2054      '#required' => TRUE,
2055    );
2056  
2057    $form['name']['#description'] = t('Enter your @s username.', array('@s' => variable_get('site_name', 'Drupal')));
2058    $form['pass'] = array('#type' => 'password',
2059      '#title' => t('Password'),
2060      '#description' => t('Enter the password that accompanies your username.'),
2061      '#required' => TRUE,
2062    );
2063    $form['#validate'] = user_login_default_validators();
2064    $form['actions'] = array('#type' => 'actions');
2065    $form['actions']['submit'] = array('#type' => 'submit', '#value' => t('Log in'));
2066  
2067    return $form;
2068  }
2069  
2070  /**
2071   * Set up a series for validators which check for blocked users,
2072   * then authenticate against local database, then return an error if
2073   * authentication fails. Distributed authentication modules are welcome
2074   * to use hook_form_alter() to change this series in order to
2075   * authenticate against their user database instead of the local users
2076   * table. If a distributed authentication module is successful, it
2077   * should set $form_state['uid'] to a user ID.
2078   *
2079   * We use three validators instead of one since external authentication
2080   * modules usually only need to alter the second validator.
2081   *
2082   * @see user_login_name_validate()
2083   * @see user_login_authenticate_validate()
2084   * @see user_login_final_validate()
2085   * @return array
2086   *   A simple list of validate functions.
2087   */
2088  function user_login_default_validators() {
2089    return array('user_login_name_validate', 'user_login_authenticate_validate', 'user_login_final_validate');
2090  }
2091  
2092  /**
2093   * A FAPI validate handler. Sets an error if supplied username has been blocked.
2094   */
2095  function user_login_name_validate($form, &$form_state) {
2096    if (isset($form_state['values']['name']) && user_is_blocked($form_state['values']['name'])) {
2097      // Blocked in user administration.
2098      form_set_error('name', t('The username %name has not been activated or is blocked.', array('%name' => $form_state['values']['name'])));
2099    }
2100  }
2101  
2102  /**
2103   * A validate handler on the login form. Check supplied username/password
2104   * against local users table. If successful, $form_state['uid']
2105   * is set to the matching user ID.
2106   */
2107  function user_login_authenticate_validate($form, &$form_state) {
2108    $password = trim($form_state['values']['pass']);
2109    if (!empty($form_state['values']['name']) && !empty($password)) {
2110      // Do not allow any login from the current user's IP if the limit has been
2111      // reached. Default is 50 failed attempts allowed in one hour. This is
2112      // independent of the per-user limit to catch attempts from one IP to log
2113      // in to many different user accounts.  We have a reasonably high limit
2114      // since there may be only one apparent IP for all users at an institution.
2115      if (!flood_is_allowed('failed_login_attempt_ip', variable_get('user_failed_login_ip_limit', 50), variable_get('user_failed_login_ip_window', 3600))) {
2116        $form_state['flood_control_triggered'] = 'ip';
2117        return;
2118      }
2119      $account = db_query("SELECT * FROM {users} WHERE name = :name AND status = 1", array(':name' => $form_state['values']['name']))->fetchObject();
2120      if ($account) {
2121        if (variable_get('user_failed_login_identifier_uid_only', FALSE)) {
2122          // Register flood events based on the uid only, so they apply for any
2123          // IP address. This is the most secure option.
2124          $identifier = $account->uid;
2125        }
2126        else {
2127          // The default identifier is a combination of uid and IP address. This
2128          // is less secure but more resistant to denial-of-service attacks that
2129          // could lock out all users with public user names.
2130          $identifier = $account->uid . '-' . ip_address();
2131        }
2132        $form_state['flood_control_user_identifier'] = $identifier;
2133  
2134        // Don't allow login if the limit for this user has been reached.
2135        // Default is to allow 5 failed attempts every 6 hours.
2136        if (!flood_is_allowed('failed_login_attempt_user', variable_get('user_failed_login_user_limit', 5), variable_get('user_failed_login_user_window', 21600), $identifier)) {
2137          $form_state['flood_control_triggered'] = 'user';
2138          return;
2139        }
2140      }
2141      // We are not limited by flood control, so try to authenticate.
2142      // Set $form_state['uid'] as a flag for user_login_final_validate().
2143      $form_state['uid'] = user_authenticate($form_state['values']['name'], $password);
2144    }
2145  }
2146  
2147  /**
2148   * The final validation handler on the login form.
2149   *
2150   * Sets a form error if user has not been authenticated, or if too many
2151   * logins have been attempted. This validation function should always
2152   * be the last one.
2153   */
2154  function user_login_final_validate($form, &$form_state) {
2155    if (empty($form_state['uid'])) {
2156      // Always register an IP-based failed login event.
2157      flood_register_event('failed_login_attempt_ip', variable_get('user_failed_login_ip_window', 3600));
2158      // Register a per-user failed login event.
2159      if (isset($form_state['flood_control_user_identifier'])) {
2160        flood_register_event('failed_login_attempt_user', variable_get('user_failed_login_user_window', 21600), $form_state['flood_control_user_identifier']);
2161      }
2162  
2163      if (isset($form_state['flood_control_triggered'])) {
2164        if ($form_state['flood_control_triggered'] == 'user') {
2165          form_set_error('name', format_plural(variable_get('user_failed_login_user_limit', 5), 'Sorry, there has been more than one failed login attempt for this account. It is temporarily blocked. Try again later or <a href="@url">request a new password</a>.', 'Sorry, there have been more than @count failed login attempts for this account. It is temporarily blocked. Try again later or <a href="@url">request a new password</a>.', array('@url' => url('user/password'))));
2166        }
2167        else {
2168          // We did not find a uid, so the limit is IP-based.
2169          form_set_error('name', t('Sorry, too many failed login attempts from your IP address. This IP address is temporarily blocked. Try again later or <a href="@url">request a new password</a>.', array('@url' => url('user/password'))));
2170        }
2171      }
2172      else {
2173        form_set_error('name', t('Sorry, unrecognized username or password. <a href="@password">Have you forgotten your password?</a>', array('@password' => url('user/password'))));
2174        watchdog('user', 'Login attempt failed for %user.', array('%user' => $form_state['values']['name']));
2175      }
2176    }
2177    elseif (isset($form_state['flood_control_user_identifier'])) {
2178      // Clear past failures for this user so as not to block a user who might
2179      // log in and out more than once in an hour.
2180      flood_clear_event('failed_login_attempt_user', $form_state['flood_control_user_identifier']);
2181    }
2182  }
2183  
2184  /**
2185   * Try to validate the user's login credentials locally.
2186   *
2187   * @param $name
2188   *   User name to authenticate.
2189   * @param $password
2190   *   A plain-text password, such as trimmed text from form values.
2191   * @return
2192   *   The user's uid on success, or FALSE on failure to authenticate.
2193   */
2194  function user_authenticate($name, $password) {
2195    $uid = FALSE;
2196    if (!empty($name) && !empty($password)) {
2197      $account = user_load_by_name($name);
2198      if ($account) {
2199        // Allow alternate password hashing schemes.
2200        require_once DRUPAL_ROOT . '/' . variable_get('password_inc', 'includes/password.inc');
2201        if (user_check_password($password, $account)) {
2202          // Successful authentication.
2203          $uid = $account->uid;
2204  
2205          // Update user to new password scheme if needed.
2206          if (user_needs_new_hash($account)) {
2207            user_save($account, array('pass' => $password));
2208          }
2209        }
2210      }
2211    }
2212    return $uid;
2213  }
2214  
2215  /**
2216   * Finalize the login process. Must be called when logging in a user.
2217   *
2218   * The function records a watchdog message about the new session, saves the
2219   * login timestamp, calls hook_user op 'login' and generates a new session. *
2220   */
2221  function user_login_finalize(&$edit = array()) {
2222    global $user;
2223    watchdog('user', 'Session opened for %name.', array('%name' => $user->name));
2224    // Update the user table timestamp noting user has logged in.
2225    // This is also used to invalidate one-time login links.
2226    $user->login = REQUEST_TIME;
2227    db_update('users')
2228      ->fields(array('login' => $user->login))
2229      ->condition('uid', $user->uid)
2230      ->execute();
2231  
2232    // Regenerate the session ID to prevent against session fixation attacks.
2233    // This is called before hook_user in case one of those functions fails
2234    // or incorrectly does a redirect which would leave the old session in place.
2235    drupal_session_regenerate();
2236  
2237    user_module_invoke('login', $edit, $user);
2238  }
2239  
2240  /**
2241   * Submit handler for the login form. Load $user object and perform standard login
2242   * tasks. The user is then redirected to the My Account page. Setting the
2243   * destination in the query string overrides the redirect.
2244   */
2245  function user_login_submit($form, &$form_state) {
2246    global $user;
2247    $user = user_load($form_state['uid']);
2248    $form_state['redirect'] = 'user/' . $user->uid;
2249  
2250    user_login_finalize($form_state);
2251  }
2252  
2253  /**
2254   * Helper function for authentication modules. Either logs in or registers
2255   * the current user, based on username. Either way, the global $user object is
2256   * populated and login tasks are performed.
2257   */
2258  function user_external_login_register($name, $module) {
2259    $account = user_external_load($name);
2260    if (!$account) {
2261      // Register this new user.
2262      $userinfo = array(
2263        'name' => $name,
2264        'pass' => user_password(),
2265        'init' => $name,
2266        'status' => 1,
2267        'access' => REQUEST_TIME
2268      );
2269      $account = user_save(drupal_anonymous_user(), $userinfo);
2270      // Terminate if an error occurred during user_save().
2271      if (!$account) {
2272        drupal_set_message(t("Error saving user account."), 'error');
2273        return;
2274      }
2275      user_set_authmaps($account, array("authname_$module" => $name));
2276    }
2277  
2278    // Log user in.
2279    $form_state['uid'] = $account->uid;
2280    user_login_submit(array(), $form_state);
2281  }
2282  
2283  /**
2284   * Generates a unique URL for a user to login and reset their password.
2285   *
2286   * @param object $account
2287   *   An object containing the user account.
2288   *
2289   * @return
2290   *   A unique URL that provides a one-time log in for the user, from which
2291   *   they can change their password.
2292   */
2293  function user_pass_reset_url($account) {
2294    $timestamp = REQUEST_TIME;
2295    return url("user/reset/$account->uid/$timestamp/" . user_pass_rehash($account->pass, $timestamp, $account->login), array('absolute' => TRUE));
2296  }
2297  
2298  /**
2299   * Generates a URL to confirm an account cancellation request.
2300   *
2301   * @param object $account
2302   *   The user account object, which must contain at least the following
2303   *   properties:
2304   *   - uid: The user uid number.
2305   *   - pass: The hashed user password string.
2306   *   - login: The user login name.
2307   *
2308   * @return
2309   *   A unique URL that may be used to confirm the cancellation of the user
2310   *   account.
2311   *
2312   * @see user_mail_tokens()
2313   * @see user_cancel_confirm()
2314   */
2315  function user_cancel_url($account) {
2316    $timestamp = REQUEST_TIME;
2317    return url("user/$account->uid/cancel/confirm/$timestamp/" . user_pass_rehash($account->pass, $timestamp, $account->login), array('absolute' => TRUE));
2318  }
2319  
2320  /**
2321   * Creates a unique hash value for use in time-dependent per-user URLs.
2322   *
2323   * This hash is normally used to build a unique and secure URL that is sent to
2324   * the user by email for purposes such as resetting the user's password. In
2325   * order to validate the URL, the same hash can be generated again, from the
2326   * same information, and compared to the hash value from the URL. The URL
2327   * normally contains both the time stamp and the numeric user ID. The login
2328   * name and hashed password are retrieved from the database as necessary. For a
2329   * usage example, see user_cancel_url() and user_cancel_confirm().
2330   *
2331   * @param $password
2332   *   The hashed user account password value.
2333   * @param $timestamp
2334   *   A unix timestamp.
2335   * @param $login
2336   *   The user account login name.
2337   *
2338   * @return
2339   *   A string that is safe for use in URLs and SQL statements.
2340   */
2341  function user_pass_rehash($password, $timestamp, $login) {
2342    return drupal_hmac_base64($timestamp . $login, drupal_get_hash_salt() . $password);
2343  }
2344  
2345  /**
2346   * Cancel a user account.
2347   *
2348   * Since the user cancellation process needs to be run in a batch, either
2349   * Form API will invoke it, or batch_process() needs to be invoked after calling
2350   * this function and should define the path to redirect to.
2351   *
2352   * @param $edit
2353   *   An array of submitted form values.
2354   * @param $uid
2355   *   The user ID of the user account to cancel.
2356   * @param $method
2357   *   The account cancellation method to use.
2358   *
2359   * @see _user_cancel()
2360   */
2361  function user_cancel($edit, $uid, $method) {
2362    global $user;
2363  
2364    $account = user_load($uid);
2365  
2366    if (!$account) {
2367      drupal_set_message(t('The user account %id does not exist.', array('%id' => $uid)), 'error');
2368      watchdog('user', 'Attempted to cancel non-existing user account: %id.', array('%id' => $uid), WATCHDOG_ERROR);
2369      return;
2370    }
2371  
2372    // Initialize batch (to set title).
2373    $batch = array(
2374      'title' => t('Cancelling account'),
2375      'operations' => array(),
2376    );
2377    batch_set($batch);
2378  
2379    // Modules use hook_user_delete() to respond to deletion.
2380    if ($method != 'user_cancel_delete') {
2381      // Allow modules to add further sets to this batch.
2382      module_invoke_all('user_cancel', $edit, $account, $method);
2383    }
2384  
2385    // Finish the batch and actually cancel the account.
2386    $batch = array(
2387      'title' => t('Cancelling user account'),
2388      'operations' => array(
2389        array('_user_cancel', array($edit, $account, $method)),
2390      ),
2391    );
2392    batch_set($batch);
2393  
2394    // Batch processing is either handled via Form API or has to be invoked
2395    // manually.
2396  }
2397  
2398  /**
2399   * Last batch processing step for cancelling a user account.
2400   *
2401   * Since batch and session API require a valid user account, the actual
2402   * cancellation of a user account needs to happen last.
2403   *
2404   * @see user_cancel()
2405   */
2406  function _user_cancel($edit, $account, $method) {
2407    global $user;
2408  
2409    switch ($method) {
2410      case 'user_cancel_block':
2411      case 'user_cancel_block_unpublish':
2412      default:
2413        // Send account blocked notification if option was checked.
2414        if (!empty($edit['user_cancel_notify'])) {
2415          _user_mail_notify('status_blocked', $account);
2416        }
2417        user_save($account, array('status' => 0));
2418        drupal_set_message(t('%name has been disabled.', array('%name' => $account->name)));
2419        watchdog('user', 'Blocked user: %name %email.', array('%name' => $account->name, '%email' => '<' . $account->mail . '>'), WATCHDOG_NOTICE);
2420        break;
2421  
2422      case 'user_cancel_reassign':
2423      case 'user_cancel_delete':
2424        // Send account canceled notification if option was checked.
2425        if (!empty($edit['user_cancel_notify'])) {
2426          _user_mail_notify('status_canceled', $account);
2427        }
2428        user_delete($account->uid);
2429        drupal_set_message(t('%name has been deleted.', array('%name' => $account->name)));
2430        watchdog('user', 'Deleted user: %name %email.', array('%name' => $account->name, '%email' => '<' . $account->mail . '>'), WATCHDOG_NOTICE);
2431        break;
2432    }
2433  
2434    // After cancelling account, ensure that user is logged out.
2435    if ($account->uid == $user->uid) {
2436      // Destroy the current session, and reset $user to the anonymous user.
2437      session_destroy();
2438    }
2439  
2440    // Clear the cache for anonymous users.
2441    cache_clear_all();
2442  }
2443  
2444  /**
2445   * Delete a user.
2446   *
2447   * @param $uid
2448   *   A user ID.
2449   */
2450  function user_delete($uid) {
2451    user_delete_multiple(array($uid));
2452  }
2453  
2454  /**
2455   * Delete multiple user accounts.
2456   *
2457   * @param $uids
2458   *   An array of user IDs.
2459   */
2460  function user_delete_multiple(array $uids) {
2461    if (!empty($uids)) {
2462      $accounts = user_load_multiple($uids, array());
2463  
2464      $transaction = db_transaction();
2465      try {
2466        foreach ($accounts as $uid => $account) {
2467          module_invoke_all('user_delete', $account);
2468          module_invoke_all('entity_delete', $account, 'user');
2469          field_attach_delete('user', $account);
2470          drupal_session_destroy_uid($account->uid);
2471        }
2472  
2473        db_delete('users')
2474          ->condition('uid', $uids, 'IN')
2475          ->execute();
2476        db_delete('users_roles')
2477          ->condition('uid', $uids, 'IN')
2478          ->execute();
2479        db_delete('authmap')
2480          ->condition('uid', $uids, 'IN')
2481          ->execute();
2482      }
2483      catch (Exception $e) {
2484        $transaction->rollback();
2485        watchdog_exception('user', $e);
2486        throw $e;
2487      }
2488      entity_get_controller('user')->resetCache();
2489    }
2490  }
2491  
2492  /**
2493   * Page callback wrapper for user_view().
2494   */
2495  function user_view_page($account) {
2496    // An administrator may try to view a non-existent account,
2497    // so we give them a 404 (versus a 403 for non-admins).
2498    return is_object($account) ? user_view($account) : MENU_NOT_FOUND;
2499  }
2500  
2501  /**
2502   * Generate an array for rendering the given user.
2503   *
2504   * When viewing a user profile, the $page array contains:
2505   *
2506   * - $page['content']['Profile Category']:
2507   *   Profile categories keyed by their human-readable names.
2508   * - $page['content']['Profile Category']['profile_machine_name']:
2509   *   Profile fields keyed by their machine-readable names.
2510   * - $page['content']['user_picture']:
2511   *   User's rendered picture.
2512   * - $page['content']['summary']:
2513   *   Contains the default "History" profile data for a user.
2514   * - $page['content']['#account']:
2515   *   The user account of the profile being viewed.
2516   *
2517   * To theme user profiles, copy modules/user/user-profile.tpl.php
2518   * to your theme directory, and edit it as instructed in that file's comments.
2519   *
2520   * @param $account
2521   *   A user object.
2522   * @param $view_mode
2523   *   View mode, e.g. 'full'.
2524   * @param $langcode
2525   *   (optional) A language code to use for rendering. Defaults to the global
2526   *   content language of the current request.
2527   *
2528   * @return
2529   *   An array as expected by drupal_render().
2530   */
2531  function user_view($account, $view_mode = 'full', $langcode = NULL) {
2532    if (!isset($langcode)) {
2533      $langcode = $GLOBALS['language_content']->language;
2534    }
2535  
2536    // Retrieve all profile fields and attach to $account->content.
2537    user_build_content($account, $view_mode, $langcode);
2538  
2539    $build = $account->content;
2540    // We don't need duplicate rendering info in account->content.
2541    unset($account->content);
2542  
2543    $build += array(
2544      '#theme' => 'user_profile',
2545      '#account' => $account,
2546      '#view_mode' => $view_mode,
2547      '#language' => $langcode,
2548    );
2549  
2550    // Allow modules to modify the structured user.
2551    $type = 'user';
2552    drupal_alter(array('user_view', 'entity_view'), $build, $type);
2553  
2554    return $build;
2555  }
2556  
2557  /**
2558   * Builds a structured array representing the profile content.
2559   *
2560   * @param $account
2561   *   A user object.
2562   * @param $view_mode
2563   *   View mode, e.g. 'full'.
2564   * @param $langcode
2565   *   (optional) A language code to use for rendering. Defaults to the global
2566   *   content language of the current request.
2567   */
2568  function user_build_content($account, $view_mode = 'full', $langcode = NULL) {
2569    if (!isset($langcode)) {
2570      $langcode = $GLOBALS['language_content']->language;
2571    }
2572  
2573    // Remove previously built content, if exists.
2574    $account->content = array();
2575  
2576    // Allow modules to change the view mode.
2577    $context = array(
2578      'entity_type' => 'user',
2579      'entity' => $account,
2580      'langcode' => $langcode,
2581    );
2582    drupal_alter('entity_view_mode', $view_mode, $context);
2583  
2584    // Build fields content.
2585    field_attach_prepare_view('user', array($account->uid => $account), $view_mode, $langcode);
2586    entity_prepare_view('user', array($account->uid => $account), $langcode);
2587    $account->content += field_attach_view('user', $account, $view_mode, $langcode);
2588  
2589    // Populate $account->content with a render() array.
2590    module_invoke_all('user_view', $account, $view_mode, $langcode);
2591    module_invoke_all('entity_view', $account, 'user', $view_mode, $langcode);
2592  
2593    // Make sure the current view mode is stored if no module has already
2594    // populated the related key.
2595    $account->content += array('#view_mode' => $view_mode);
2596  }
2597  
2598  /**
2599   * Implements hook_mail().
2600   */
2601  function user_mail($key, &$message, $params) {
2602    $language = $message['language'];
2603    $variables = array('user' => $params['account']);
2604    $message['subject'] .= _user_mail_text($key . '_subject', $language, $variables);
2605    $message['body'][] = _user_mail_text($key . '_body', $language, $variables);
2606  }
2607  
2608  /**
2609   * Returns a mail string for a variable name.
2610   *
2611   * Used by user_mail() and the settings forms to retrieve strings.
2612   */
2613  function _user_mail_text($key, $language = NULL, $variables = array(), $replace = TRUE) {
2614    $langcode = isset($language) ? $language->language : NULL;
2615  
2616    if ($admin_setting = variable_get('user_mail_' . $key, FALSE)) {
2617      // An admin setting overrides the default string.
2618      $text = $admin_setting;
2619    }
2620    else {
2621      // No override, return default string.
2622      switch ($key) {
2623        case 'register_no_approval_required_subject':
2624          $text = t('Account details for [user:name] at [site:name]', array(), array('langcode' => $langcode));
2625          break;
2626        case 'register_no_approval_required_body':
2627          $text = t("[user:name],
2628  
2629  Thank you for registering at [site:name]. You may now log in by clicking this link or copying and pasting it to your browser:
2630  
2631  [user:one-time-login-url]
2632  
2633  This link can only be used once to log in and will lead you to a page where you can set your password.
2634  
2635  After setting your password, you will be able to log in at [site:login-url] in the future using:
2636  
2637  username: [user:name]
2638  password: Your password
2639  
2640  --  [site:name] team", array(), array('langcode' => $langcode));
2641          break;
2642  
2643        case 'register_admin_created_subject':
2644          $text = t('An administrator created an account for you at [site:name]', array(), array('langcode' => $langcode));
2645          break;
2646        case 'register_admin_created_body':
2647          $text = t("[user:name],
2648  
2649  A site administrator at [site:name] has created an account for you. You may now log in by clicking this link or copying and pasting it to your browser:
2650  
2651  [user:one-time-login-url]
2652  
2653  This link can only be used once to log in and will lead you to a page where you can set your password.
2654  
2655  After setting your password, you will be able to log in at [site:login-url] in the future using:
2656  
2657  username: [user:name]
2658  password: Your password
2659  
2660  --  [site:name] team", array(), array('langcode' => $langcode));
2661          break;
2662  
2663        case 'register_pending_approval_subject':
2664        case 'register_pending_approval_admin_subject':
2665          $text = t('Account details for [user:name] at [site:name] (pending admin approval)', array(), array('langcode' => $langcode));
2666          break;
2667        case 'register_pending_approval_body':
2668          $text = t("[user:name],
2669  
2670  Thank you for registering at [site:name]. Your application for an account is currently pending approval. Once it has been approved, you will receive another e-mail containing information about how to log in, set your password, and other details.
2671  
2672  
2673  --  [site:name] team", array(), array('langcode' => $langcode));
2674          break;
2675        case 'register_pending_approval_admin_body':
2676          $text = t("[user:name] has applied for an account.
2677  
2678  [user:edit-url]", array(), array('langcode' => $langcode));
2679          break;
2680  
2681        case 'password_reset_subject':
2682          $text = t('Replacement login information for [user:name] at [site:name]', array(), array('langcode' => $langcode));
2683          break;
2684        case 'password_reset_body':
2685          $text = t("[user:name],
2686  
2687  A request to reset the password for your account has been made at [site:name].
2688  
2689  You may now log in by clicking this link or copying and pasting it to your browser:
2690  
2691  [user:one-time-login-url]
2692  
2693  This link can only be used once to log in and will lead you to a page where you can set your password. It expires after one day and nothing will happen if it's not used.
2694  
2695  --  [site:name] team", array(), array('langcode' => $langcode));
2696          break;
2697  
2698        case 'status_activated_subject':
2699          $text = t('Account details for [user:name] at [site:name] (approved)', array(), array('langcode' => $langcode));
2700          break;
2701        case 'status_activated_body':
2702          $text = t("[user:name],
2703  
2704  Your account at [site:name] has been activated.
2705  
2706  You may now log in by clicking this link or copying and pasting it into your browser:
2707  
2708  [user:one-time-login-url]
2709  
2710  This link can only be used once to log in and will lead you to a page where you can set your password.
2711  
2712  After setting your password, you will be able to log in at [site:login-url] in the future using:
2713  
2714  username: [user:name]
2715  password: Your password
2716  
2717  --  [site:name] team", array(), array('langcode' => $langcode));
2718          break;
2719  
2720        case 'status_blocked_subject':
2721          $text = t('Account details for [user:name] at [site:name] (blocked)', array(), array('langcode' => $langcode));
2722          break;
2723        case 'status_blocked_body':
2724          $text = t("[user:name],
2725  
2726  Your account on [site:name] has been blocked.
2727  
2728  --  [site:name] team", array(), array('langcode' => $langcode));
2729          break;
2730  
2731        case 'cancel_confirm_subject':
2732          $text = t('Account cancellation request for [user:name] at [site:name]', array(), array('langcode' => $langcode));
2733          break;
2734        case 'cancel_confirm_body':
2735          $text = t("[user:name],
2736  
2737  A request to cancel your account has been made at [site:name].
2738  
2739  You may now cancel your account on [site:url-brief] by clicking this link or copying and pasting it into your browser:
2740  
2741  [user:cancel-url]
2742  
2743  NOTE: The cancellation of your account is not reversible.
2744  
2745  This link expires in one day and nothing will happen if it is not used.
2746  
2747  --  [site:name] team", array(), array('langcode' => $langcode));
2748          break;
2749  
2750        case 'status_canceled_subject':
2751          $text = t('Account details for [user:name] at [site:name] (canceled)', array(), array('langcode' => $langcode));
2752          break;
2753        case 'status_canceled_body':
2754          $text = t("[user:name],
2755  
2756  Your account on [site:name] has been canceled.
2757  
2758  --  [site:name] team", array(), array('langcode' => $langcode));
2759          break;
2760      }
2761    }
2762  
2763    if ($replace) {
2764      // We do not sanitize the token replacement, since the output of this
2765      // replacement is intended for an e-mail message, not a web browser.
2766      return token_replace($text, $variables, array('language' => $language, 'callback' => 'user_mail_tokens', 'sanitize' => FALSE, 'clear' => TRUE));
2767    }
2768  
2769    return $text;
2770  }
2771  
2772  /**
2773   * Token callback to add unsafe tokens for user mails.
2774   *
2775   * This function is used by the token_replace() call at the end of
2776   * _user_mail_text() to set up some additional tokens that can be
2777   * used in email messages generated by user_mail().
2778   *
2779   * @param $replacements
2780   *   An associative array variable containing mappings from token names to
2781   *   values (for use with strtr()).
2782   * @param $data
2783   *   An associative array of token replacement values. If the 'user' element
2784   *   exists, it must contain a user account object with the following
2785   *   properties:
2786   *   - login: The account login name.
2787   *   - pass: The hashed account login password.
2788   * @param $options
2789   *   Unused parameter required by the token_replace() function.
2790   */
2791  function user_mail_tokens(&$replacements, $data, $options) {
2792    if (isset($data['user'])) {
2793      $replacements['[user:one-time-login-url]'] = user_pass_reset_url($data['user']);
2794      $replacements['[user:cancel-url]'] = user_cancel_url($data['user']);
2795    }
2796  }
2797  
2798  /*** Administrative features ***********************************************/
2799  
2800  /**
2801   * Retrieve an array of roles matching specified conditions.
2802   *
2803   * @param $membersonly
2804   *   Set this to TRUE to exclude the 'anonymous' role.
2805   * @param $permission
2806   *   A string containing a permission. If set, only roles containing that
2807   *   permission are returned.
2808   *
2809   * @return
2810   *   An associative array with the role id as the key and the role name as
2811   *   value.
2812   */
2813  function user_roles($membersonly = FALSE, $permission = NULL) {
2814    $query = db_select('role', 'r');
2815    $query->addTag('translatable');
2816    $query->fields('r', array('rid', 'name'));
2817    $query->orderBy('weight');
2818    $query->orderBy('name');
2819    if (!empty($permission)) {
2820      $query->innerJoin('role_permission', 'p', 'r.rid = p.rid');
2821      $query->condition('p.permission', $permission);
2822    }
2823    $result = $query->execute();
2824  
2825    $roles = array();
2826    foreach ($result as $role) {
2827      switch ($role->rid) {
2828        // We only translate the built in role names
2829        case DRUPAL_ANONYMOUS_RID:
2830          if (!$membersonly) {
2831            $roles[$role->rid] = t($role->name);
2832          }
2833          break;
2834        case DRUPAL_AUTHENTICATED_RID:
2835          $roles[$role->rid] = t($role->name);
2836          break;
2837        default:
2838          $roles[$role->rid] = $role->name;
2839      }
2840    }
2841  
2842    return $roles;
2843  }
2844  
2845  /**
2846   * Fetches a user role by role ID.
2847   *
2848   * @param $rid
2849   *   An integer representing the role ID.
2850   *
2851   * @return
2852   *   A fully-loaded role object if a role with the given ID exists, or FALSE
2853   *   otherwise.
2854   *
2855   * @see user_role_load_by_name()
2856   */
2857  function user_role_load($rid) {
2858    return db_select('role', 'r')
2859      ->fields('r')
2860      ->condition('rid', $rid)
2861      ->execute()
2862      ->fetchObject();
2863  }
2864  
2865  /**
2866   * Fetches a user role by role name.
2867   *
2868   * @param $role_name
2869   *   A string representing the role name.
2870   *
2871   * @return
2872   *   A fully-loaded role object if a role with the given name exists, or FALSE
2873   *   otherwise.
2874   *
2875   * @see user_role_load()
2876   */
2877  function user_role_load_by_name($role_name) {
2878    return db_select('role', 'r')
2879      ->fields('r')
2880      ->condition('name', $role_name)
2881      ->execute()
2882      ->fetchObject();
2883  }
2884  
2885  /**
2886   * Save a user role to the database.
2887   *
2888   * @param $role
2889   *   A role object to modify or add. If $role->rid is not specified, a new
2890   *   role will be created.
2891   * @return
2892   *   Status constant indicating if role was created or updated.
2893   *   Failure to write the user role record will return FALSE. Otherwise.
2894   *   SAVED_NEW or SAVED_UPDATED is returned depending on the operation
2895   *   performed.
2896   */
2897  function user_role_save($role) {
2898    if ($role->name) {
2899      // Prevent leading and trailing spaces in role names.
2900      $role->name = trim($role->name);
2901    }
2902    if (!isset($role->weight)) {
2903      // Set a role weight to make this new role last.
2904      $query = db_select('role');
2905      $query->addExpression('MAX(weight)');
2906      $role->weight = $query->execute()->fetchField() + 1;
2907    }
2908  
2909    // Let modules modify the user role before it is saved to the database.
2910    module_invoke_all('user_role_presave', $role);
2911  
2912    if (!empty($role->rid) && $role->name) {
2913      $status = drupal_write_record('role', $role, 'rid');
2914      module_invoke_all('user_role_update', $role);
2915    }
2916    else {
2917      $status = drupal_write_record('role', $role);
2918      module_invoke_all('user_role_insert', $role);
2919    }
2920  
2921    // Clear the user access cache.
2922    drupal_static_reset('user_access');
2923    drupal_static_reset('user_role_permissions');
2924  
2925    return $status;
2926  }
2927  
2928  /**
2929   * Delete a user role from database.
2930   *
2931   * @param $role
2932   *   A string with the role name, or an integer with the role ID.
2933   */
2934  function user_role_delete($role) {
2935    if (is_int($role)) {
2936      $role = user_role_load($role);
2937    }
2938    else {
2939      $role = user_role_load_by_name($role);
2940    }
2941  
2942    db_delete('role')
2943      ->condition('rid', $role->rid)
2944      ->execute();
2945    db_delete('role_permission')
2946      ->condition('rid', $role->rid)
2947      ->execute();
2948    // Update the users who have this role set:
2949    db_delete('users_roles')
2950      ->condition('rid', $role->rid)
2951      ->execute();
2952  
2953    module_invoke_all('user_role_delete', $role);
2954  
2955    // Clear the user access cache.
2956    drupal_static_reset('user_access');
2957    drupal_static_reset('user_role_permissions');
2958  }
2959  
2960  /**
2961   * Menu access callback for user role editing.
2962   */
2963  function user_role_edit_access($role) {
2964    // Prevent the system-defined roles from being altered or removed.
2965    if ($role->rid == DRUPAL_ANONYMOUS_RID || $role->rid == DRUPAL_AUTHENTICATED_RID) {
2966      return FALSE;
2967    }
2968  
2969    return user_access('administer permissions');
2970  }
2971  
2972  /**
2973   * Determine the modules that permissions belong to.
2974   *
2975   * @return
2976   *   An associative array in the format $permission => $module.
2977   */
2978  function user_permission_get_modules() {
2979    $permissions = array();
2980    foreach (module_implements('permission') as $module) {
2981      $perms = module_invoke($module, 'permission');
2982      foreach ($perms as $key => $value) {
2983        $permissions[$key] = $module;
2984      }
2985    }
2986    return $permissions;
2987  }
2988  
2989  /**
2990   * Change permissions for a user role.
2991   *
2992   * This function may be used to grant and revoke multiple permissions at once.
2993   * For example, when a form exposes checkboxes to configure permissions for a
2994   * role, the form submit handler may directly pass the submitted values for the
2995   * checkboxes form element to this function.
2996   *
2997   * @param $rid
2998   *   The ID of a user role to alter.
2999   * @param $permissions
3000   *   An associative array, where the key holds the permission name and the value
3001   *   determines whether to grant or revoke that permission. Any value that
3002   *   evaluates to TRUE will cause the permission to be granted. Any value that
3003   *   evaluates to FALSE will cause the permission to be revoked.
3004   *   @code
3005   *     array(
3006   *       'administer nodes' => 0,                // Revoke 'administer nodes'
3007   *       'administer blocks' => FALSE,           // Revoke 'administer blocks'
3008   *       'access user profiles' => 1,            // Grant 'access user profiles'
3009   *       'access content' => TRUE,               // Grant 'access content'
3010   *       'access comments' => 'access comments', // Grant 'access comments'
3011   *     )
3012   *   @endcode
3013   *   Existing permissions are not changed, unless specified in $permissions.
3014   *
3015   * @see user_role_grant_permissions()
3016   * @see user_role_revoke_permissions()
3017   */
3018  function user_role_change_permissions($rid, array $permissions = array()) {
3019    // Grant new permissions for the role.
3020    $grant = array_filter($permissions);
3021    if (!empty($grant)) {
3022      user_role_grant_permissions($rid, array_keys($grant));
3023    }
3024    // Revoke permissions for the role.
3025    $revoke = array_diff_assoc($permissions, $grant);
3026    if (!empty($revoke)) {
3027      user_role_revoke_permissions($rid, array_keys($revoke));
3028    }
3029  }
3030  
3031  /**
3032   * Grant permissions to a user role.
3033   *
3034   * @param $rid
3035   *   The ID of a user role to alter.
3036   * @param $permissions
3037   *   A list of permission names to grant.
3038   *
3039   * @see user_role_change_permissions()
3040   * @see user_role_revoke_permissions()
3041   */
3042  function user_role_grant_permissions($rid, array $permissions = array()) {
3043    $modules = user_permission_get_modules();
3044    // Grant new permissions for the role.
3045    foreach ($permissions as $name) {
3046      db_merge('role_permission')
3047        ->key(array(
3048          'rid' => $rid,
3049          'permission' => $name,
3050        ))
3051        ->fields(array(
3052          'module' => $modules[$name],
3053        ))
3054        ->execute();
3055    }
3056  
3057    // Clear the user access cache.
3058    drupal_static_reset('user_access');
3059    drupal_static_reset('user_role_permissions');
3060  }
3061  
3062  /**
3063   * Revoke permissions from a user role.
3064   *
3065   * @param $rid
3066   *   The ID of a user role to alter.
3067   * @param $permissions
3068   *   A list of permission names to revoke.
3069   *
3070   * @see user_role_change_permissions()
3071   * @see user_role_grant_permissions()
3072   */
3073  function user_role_revoke_permissions($rid, array $permissions = array()) {
3074    // Revoke permissions for the role.
3075    db_delete('role_permission')
3076      ->condition('rid', $rid)
3077      ->condition('permission', $permissions, 'IN')
3078      ->execute();
3079  
3080    // Clear the user access cache.
3081    drupal_static_reset('user_access');
3082    drupal_static_reset('user_role_permissions');
3083  }
3084  
3085  /**
3086   * Implements hook_user_operations().
3087   */
3088  function user_user_operations($form = array(), $form_state = array()) {
3089    $operations = array(
3090      'unblock' => array(
3091        'label' => t('Unblock the selected users'),
3092        'callback' => 'user_user_operations_unblock',
3093      ),
3094      'block' => array(
3095        'label' => t('Block the selected users'),
3096        'callback' => 'user_user_operations_block',
3097      ),
3098      'cancel' => array(
3099        'label' => t('Cancel the selected user accounts'),
3100      ),
3101    );
3102  
3103    if (user_access('administer permissions')) {
3104      $roles = user_roles(TRUE);
3105      unset($roles[DRUPAL_AUTHENTICATED_RID]);  // Can't edit authenticated role.
3106  
3107      $add_roles = array();
3108      foreach ($roles as $key => $value) {
3109        $add_roles['add_role-' . $key] = $value;
3110      }
3111  
3112      $remove_roles = array();
3113      foreach ($roles as $key => $value) {
3114        $remove_roles['remove_role-' . $key] = $value;
3115      }
3116  
3117      if (count($roles)) {
3118        $role_operations = array(
3119          t('Add a role to the selected users') => array(
3120            'label' => $add_roles,
3121          ),
3122          t('Remove a role from the selected users') => array(
3123            'label' => $remove_roles,
3124          ),
3125        );
3126  
3127        $operations += $role_operations;
3128      }
3129    }
3130  
3131    // If the form has been posted, we need to insert the proper data for
3132    // role editing if necessary.
3133    if (!empty($form_state['submitted'])) {
3134      $operation_rid = explode('-', $form_state['values']['operation']);
3135      $operation = $operation_rid[0];
3136      if ($operation == 'add_role' || $operation == 'remove_role') {
3137        $rid = $operation_rid[1];
3138        if (user_access('administer permissions')) {
3139          $operations[$form_state['values']['operation']] = array(
3140            'callback' => 'user_multiple_role_edit',
3141            'callback arguments' => array($operation, $rid),
3142          );
3143        }
3144        else {
3145          watchdog('security', 'Detected malicious attempt to alter protected user fields.', array(), WATCHDOG_WARNING);
3146          return;
3147        }
3148      }
3149    }
3150  
3151    return $operations;
3152  }
3153  
3154  /**
3155   * Callback function for admin mass unblocking users.
3156   */
3157  function user_user_operations_unblock($accounts) {
3158    $accounts = user_load_multiple($accounts);
3159    foreach ($accounts as $account) {
3160      // Skip unblocking user if they are already unblocked.
3161      if ($account !== FALSE && $account->status == 0) {
3162        user_save($account, array('status' => 1));
3163      }
3164    }
3165  }
3166  
3167  /**
3168   * Callback function for admin mass blocking users.
3169   */
3170  function user_user_operations_block($accounts) {
3171    $accounts = user_load_multiple($accounts);
3172    foreach ($accounts as $account) {
3173      // Skip blocking user if they are already blocked.
3174      if ($account !== FALSE && $account->status == 1) {
3175        // For efficiency manually save the original account before applying any
3176        // changes.
3177        $account->original = clone $account;
3178        user_save($account, array('status' => 0));
3179      }
3180    }
3181  }
3182  
3183  /**
3184   * Callback function for admin mass adding/deleting a user role.
3185   */
3186  function user_multiple_role_edit($accounts, $operation, $rid) {
3187    // The role name is not necessary as user_save() will reload the user
3188    // object, but some modules' hook_user() may look at this first.
3189    $role_name = db_query('SELECT name FROM {role} WHERE rid = :rid', array(':rid' => $rid))->fetchField();
3190  
3191    switch ($operation) {
3192      case 'add_role':
3193        $accounts = user_load_multiple($accounts);
3194        foreach ($accounts as $account) {
3195          // Skip adding the role to the user if they already have it.
3196          if ($account !== FALSE && !isset($account->roles[$rid])) {
3197            $roles = $account->roles + array($rid => $role_name);
3198            // For efficiency manually save the original account before applying
3199            // any changes.
3200            $account->original = clone $account;
3201            user_save($account, array('roles' => $roles));
3202          }
3203        }
3204        break;
3205      case 'remove_role':
3206        $accounts = user_load_multiple($accounts);
3207        foreach ($accounts as $account) {
3208          // Skip removing the role from the user if they already don't have it.
3209          if ($account !== FALSE && isset($account->roles[$rid])) {
3210            $roles = array_diff($account->roles, array($rid => $role_name));
3211            // For efficiency manually save the original account before applying
3212            // any changes.
3213            $account->original = clone $account;
3214            user_save($account, array('roles' => $roles));
3215          }
3216        }
3217        break;
3218    }
3219  }
3220  
3221  function user_multiple_cancel_confirm($form, &$form_state) {
3222    $edit = $form_state['input'];
3223  
3224    $form['accounts'] = array('#prefix' => '<ul>', '#suffix' => '</ul>', '#tree' => TRUE);
3225    $accounts = user_load_multiple(array_keys(array_filter($edit['accounts'])));
3226    foreach ($accounts as $uid => $account) {
3227      // Prevent user 1 from being canceled.
3228      if ($uid <= 1) {
3229        continue;
3230      }
3231      $form['accounts'][$uid] = array(
3232        '#type' => 'hidden',
3233        '#value' => $uid,
3234        '#prefix' => '<li>',
3235        '#suffix' => check_plain($account->name) . "</li>\n",
3236      );
3237    }
3238  
3239    // Output a notice that user 1 cannot be canceled.
3240    if (isset($accounts[1])) {
3241      $redirect = (count($accounts) == 1);
3242      $message = t('The user account %name cannot be cancelled.', array('%name' => $accounts[1]->name));
3243      drupal_set_message($message, $redirect ? 'error' : 'warning');
3244      // If only user 1 was selected, redirect to the overview.
3245      if ($redirect) {
3246        drupal_goto('admin/people');
3247      }
3248    }
3249  
3250    $form['operation'] = array('#type' => 'hidden', '#value' => 'cancel');
3251  
3252    module_load_include('inc', 'user', 'user.pages');
3253    $form['user_cancel_method'] = array(
3254      '#type' => 'item',
3255      '#title' => t('When cancelling these accounts'),
3256    );
3257    $form['user_cancel_method'] += user_cancel_methods();
3258    // Remove method descriptions.
3259    foreach (element_children($form['user_cancel_method']) as $element) {
3260      unset($form['user_cancel_method'][$element]['#description']);
3261    }
3262  
3263    // Allow to send the account cancellation confirmation mail.
3264    $form['user_cancel_confirm'] = array(
3265      '#type' => 'checkbox',
3266      '#title' => t('Require e-mail confirmation to cancel account.'),
3267      '#default_value' => FALSE,
3268      '#description' => t('When enabled, the user must confirm the account cancellation via e-mail.'),
3269    );
3270    // Also allow to send account canceled notification mail, if enabled.
3271    $form['user_cancel_notify'] = array(
3272      '#type' => 'checkbox',
3273      '#title' => t('Notify user when account is canceled.'),
3274      '#default_value' => FALSE,
3275      '#access' => variable_get('user_mail_status_canceled_notify', FALSE),
3276      '#description' => t('When enabled, the user will receive an e-mail notification after the account has been cancelled.'),
3277    );
3278  
3279    return confirm_form($form,
3280                        t('Are you sure you want to cancel these user accounts?'),
3281                        'admin/people', t('This action cannot be undone.'),
3282                        t('Cancel accounts'), t('Cancel'));
3283  }
3284  
3285  /**
3286   * Submit handler for mass-account cancellation form.
3287   *
3288   * @see user_multiple_cancel_confirm()
3289   * @see user_cancel_confirm_form_submit()
3290   */
3291  function user_multiple_cancel_confirm_submit($form, &$form_state) {
3292    global $user;
3293  
3294    if ($form_state['values']['confirm']) {
3295      foreach ($form_state['values']['accounts'] as $uid => $value) {
3296        // Prevent programmatic form submissions from cancelling user 1.
3297        if ($uid <= 1) {
3298          continue;
3299        }
3300        // Prevent user administrators from deleting themselves without confirmation.
3301        if ($uid == $user->uid) {
3302          $admin_form_state = $form_state;
3303          unset($admin_form_state['values']['user_cancel_confirm']);
3304          $admin_form_state['values']['_account'] = $user;
3305          user_cancel_confirm_form_submit(array(), $admin_form_state);
3306        }
3307        else {
3308          user_cancel($form_state['values'], $uid, $form_state['values']['user_cancel_method']);
3309        }
3310      }
3311    }
3312    $form_state['redirect'] = 'admin/people';
3313  }
3314  
3315  /**
3316   * Retrieve a list of all user setting/information categories and sort them by weight.
3317   */
3318  function _user_categories() {
3319    $categories = module_invoke_all('user_categories');
3320    usort($categories, '_user_sort');
3321  
3322    return $categories;
3323  }
3324  
3325  function _user_sort($a, $b) {
3326    $a = (array) $a + array('weight' => 0, 'title' => '');
3327    $b = (array) $b + array('weight' => 0, 'title' => '');
3328    return $a['weight'] < $b['weight'] ? -1 : ($a['weight'] > $b['weight'] ? 1 : ($a['title'] < $b['title'] ? -1 : 1));
3329  }
3330  
3331  /**
3332   * List user administration filters that can be applied.
3333   */
3334  function user_filters() {
3335    // Regular filters
3336    $filters = array();
3337    $roles = user_roles(TRUE);
3338    unset($roles[DRUPAL_AUTHENTICATED_RID]); // Don't list authorized role.
3339    if (count($roles)) {
3340      $filters['role'] = array(
3341        'title' => t('role'),
3342        'field' => 'ur.rid',
3343        'options' => array(
3344          '[any]' => t('any'),
3345        ) + $roles,
3346      );
3347    }
3348  
3349    $options = array();
3350    foreach (module_implements('permission') as $module) {
3351      $function = $module . '_permission';
3352      if ($permissions = $function('permission')) {
3353        asort($permissions);
3354        foreach ($permissions as $permission => $description) {
3355          $options[t('@module module', array('@module' => $module))][$permission] = t($permission);
3356        }
3357      }
3358    }
3359    ksort($options);
3360    $filters['permission'] = array(
3361      'title' => t('permission'),
3362      'options' => array(
3363        '[any]' => t('any'),
3364      ) + $options,
3365    );
3366  
3367    $filters['status'] = array(
3368      'title' => t('status'),
3369      'field' => 'u.status',
3370      'options' => array(
3371        '[any]' => t('any'),
3372        1 => t('active'),
3373        0 => t('blocked'),
3374      ),
3375    );
3376    return $filters;
3377  }
3378  
3379  /**
3380   * Extends a query object for user administration filters based on session.
3381   *
3382   * @param $query
3383   *   Query object that should be filtered.
3384   */
3385  function user_build_filter_query(SelectQuery $query) {
3386    $filters = user_filters();
3387    // Extend Query with filter conditions.
3388    foreach (isset($_SESSION['user_overview_filter']) ? $_SESSION['user_overview_filter'] : array() as $filter) {
3389      list($key, $value) = $filter;
3390      // This checks to see if this permission filter is an enabled permission for
3391      // the authenticated role. If so, then all users would be listed, and we can
3392      // skip adding it to the filter query.
3393      if ($key == 'permission') {
3394        $account = new stdClass();
3395        $account->uid = 'user_filter';
3396        $account->roles = array(DRUPAL_AUTHENTICATED_RID => 1);
3397        if (user_access($value, $account)) {
3398          continue;
3399        }
3400        $users_roles_alias = $query->join('users_roles', 'ur', '%alias.uid = u.uid');
3401        $permission_alias = $query->join('role_permission', 'p', $users_roles_alias . '.rid = %alias.rid');
3402        $query->condition($permission_alias . '.permission', $value);
3403      }
3404      elseif ($key == 'role') {
3405        $users_roles_alias = $query->join('users_roles', 'ur', '%alias.uid = u.uid');
3406        $query->condition($users_roles_alias . '.rid' , $value);
3407      }
3408      else {
3409        $query->condition($filters[$key]['field'], $value);
3410      }
3411    }
3412  }
3413  
3414  /**
3415   * Implements hook_comment_view().
3416   */
3417  function user_comment_view($comment) {
3418    if (variable_get('user_signatures', 0) && !empty($comment->signature)) {
3419      // @todo This alters and replaces the original object value, so a
3420      //   hypothetical process of loading, viewing, and saving will hijack the
3421      //   stored data. Consider renaming to $comment->signature_safe or similar
3422      //   here and elsewhere in Drupal 8.
3423      $comment->signature = check_markup($comment->signature, $comment->signature_format, '', TRUE);
3424    }
3425    else {
3426      $comment->signature = '';
3427    }
3428  }
3429  
3430  /**
3431   * Returns HTML for a user signature.
3432   *
3433   * @param $variables
3434   *   An associative array containing:
3435   *   - signature: The user's signature.
3436   *
3437   * @ingroup themeable
3438   */
3439  function theme_user_signature($variables) {
3440    $signature = $variables['signature'];
3441    $output = '';
3442  
3443    if ($signature) {
3444      $output .= '<div class="clear">';
3445      $output .= '<div>—</div>';
3446      $output .= $signature;
3447      $output .= '</div>';
3448    }
3449  
3450    return $output;
3451  }
3452  
3453  /**
3454   * Get the language object preferred by the user. This user preference can
3455   * be set on the user account editing page, and is only available if there
3456   * are more than one languages enabled on the site. If the user did not
3457   * choose a preferred language, or is the anonymous user, the $default
3458   * value, or if it is not set, the site default language will be returned.
3459   *
3460   * @param $account
3461   *   User account to look up language for.
3462   * @param $default
3463   *   Optional default language object to return if the account
3464   *   has no valid language.
3465   */
3466  function user_preferred_language($account, $default = NULL) {
3467    $language_list = language_list();
3468    if (!empty($account->language) && isset($language_list[$account->language])) {
3469      return $language_list[$account->language];
3470    }
3471    else {
3472      return $default ? $default : language_default();
3473    }
3474  }
3475  
3476  /**
3477   * Conditionally create and send a notification email when a certain
3478   * operation happens on the given user account.
3479   *
3480   * @see user_mail_tokens()
3481   * @see drupal_mail()
3482   *
3483   * @param $op
3484   *   The operation being performed on the account. Possible values:
3485   *   - 'register_admin_created': Welcome message for user created by the admin.
3486   *   - 'register_no_approval_required': Welcome message when user
3487   *     self-registers.
3488   *   - 'register_pending_approval': Welcome message, user pending admin
3489   *     approval.
3490   *   - 'password_reset': Password recovery request.
3491   *   - 'status_activated': Account activated.
3492   *   - 'status_blocked': Account blocked.
3493   *   - 'cancel_confirm': Account cancellation request.
3494   *   - 'status_canceled': Account canceled.
3495   *
3496   * @param $account
3497   *   The user object of the account being notified. Must contain at
3498   *   least the fields 'uid', 'name', and 'mail'.
3499   * @param $language
3500   *   Optional language to use for the notification, overriding account language.
3501   *
3502   * @return
3503   *   The return value from drupal_mail_system()->mail(), if ends up being
3504   *   called.
3505   */
3506  function _user_mail_notify($op, $account, $language = NULL) {
3507    // By default, we always notify except for canceled and blocked.
3508    $default_notify = ($op != 'status_canceled' && $op != 'status_blocked');
3509    $notify = variable_get('user_mail_' . $op . '_notify', $default_notify);
3510    if ($notify) {
3511      $params['account'] = $account;
3512      $language = $language ? $language : user_preferred_language($account);
3513      $mail = drupal_mail('user', $op, $account->mail, $language, $params);
3514      if ($op == 'register_pending_approval') {
3515        // If a user registered requiring admin approval, notify the admin, too.
3516        // We use the site default language for this.
3517        drupal_mail('user', 'register_pending_approval_admin', variable_get('site_mail', ini_get('sendmail_from')), language_default(), $params);
3518      }
3519    }
3520    return empty($mail) ? NULL : $mail['result'];
3521  }
3522  
3523  /**
3524   * Form element process handler for client-side password validation.
3525   *
3526   * This #process handler is automatically invoked for 'password_confirm' form
3527   * elements to add the JavaScript and string translations for dynamic password
3528   * validation.
3529   *
3530   * @see system_element_info()
3531   */
3532  function user_form_process_password_confirm($element) {
3533    global $user;
3534  
3535    $js_settings = array(
3536      'password' => array(
3537        'strengthTitle' => t('Password strength:'),
3538        'hasWeaknesses' => t('To make your password stronger:'),
3539        'tooShort' => t('Make it at least 6 characters'),
3540        'addLowerCase' => t('Add lowercase letters'),
3541        'addUpperCase' => t('Add uppercase letters'),
3542        'addNumbers' => t('Add numbers'),
3543        'addPunctuation' => t('Add punctuation'),
3544        'sameAsUsername' => t('Make it different from your username'),
3545        'confirmSuccess' => t('yes'),
3546        'confirmFailure' => t('no'),
3547        'weak' => t('Weak'),
3548        'fair' => t('Fair'),
3549        'good' => t('Good'),
3550        'strong' => t('Strong'),
3551        'confirmTitle' => t('Passwords match:'),
3552        'username' => (isset($user->name) ? $user->name : ''),
3553      ),
3554    );
3555  
3556    $element['#attached']['js'][] = drupal_get_path('module', 'user') . '/user.js';
3557    // Ensure settings are only added once per page.
3558    static $already_added = FALSE;
3559    if (!$already_added) {
3560      $already_added = TRUE;
3561      $element['#attached']['js'][] = array('data' => $js_settings, 'type' => 'setting');
3562    }
3563  
3564    return $element;
3565  }
3566  
3567  /**
3568   * Implements hook_node_load().
3569   */
3570  function user_node_load($nodes, $types) {
3571    // Build an array of all uids for node authors, keyed by nid.
3572    $uids = array();
3573    foreach ($nodes as $nid => $node) {
3574      $uids[$nid] = $node->uid;
3575    }
3576  
3577    // Fetch name, picture, and data for these users.
3578    $user_fields = db_query("SELECT uid, name, picture, data FROM {users} WHERE uid IN (:uids)", array(':uids' => $uids))->fetchAllAssoc('uid');
3579  
3580    // Add these values back into the node objects.
3581    foreach ($uids as $nid => $uid) {
3582      $nodes[$nid]->name = $user_fields[$uid]->name;
3583      $nodes[$nid]->picture = $user_fields[$uid]->picture;
3584      $nodes[$nid]->data = $user_fields[$uid]->data;
3585    }
3586  }
3587  
3588  /**
3589   * Implements hook_image_style_delete().
3590   */
3591  function user_image_style_delete($style) {
3592    // If a style is deleted, update the variables.
3593    // Administrators choose a replacement style when deleting.
3594    user_image_style_save($style);
3595  }
3596  
3597  /**
3598   * Implements hook_image_style_save().
3599   */
3600  function user_image_style_save($style) {
3601    // If a style is renamed, update the variables that use it.
3602    if (isset($style['old_name']) && $style['old_name'] == variable_get('user_picture_style', '')) {
3603      variable_set('user_picture_style', $style['name']);
3604    }
3605  }
3606  
3607  /**
3608   * Implements hook_action_info().
3609   */
3610  function user_action_info() {
3611    return array(
3612      'user_block_user_action' => array(
3613        'label' => t('Block current user'),
3614        'type' => 'user',
3615        'configurable' => FALSE,
3616        'triggers' => array('any'),
3617      ),
3618    );
3619  }
3620  
3621  /**
3622   * Blocks the current user.
3623   *
3624   * @ingroup actions
3625   */
3626  function user_block_user_action(&$entity, $context = array()) {
3627    // First priority: If there is a $entity->uid, block that user.
3628    // This is most likely a user object or the author if a node or comment.
3629    if (isset($entity->uid)) {
3630      $uid = $entity->uid;
3631    }
3632    elseif (isset($context['uid'])) {
3633      $uid = $context['uid'];
3634    }
3635    // If neither of those are valid, then block the current user.
3636    else {
3637      $uid = $GLOBALS['user']->uid;
3638    }
3639    $account = user_load($uid);
3640    $account = user_save($account, array('status' => 0));
3641    watchdog('action', 'Blocked user %name.', array('%name' => $account->name));
3642  }
3643  
3644  /**
3645   * Implements hook_form_FORM_ID_alter().
3646   *
3647   * Add a checkbox for the 'user_register_form' instance settings on the 'Edit
3648   * field instance' form.
3649   */
3650  function user_form_field_ui_field_edit_form_alter(&$form, &$form_state, $form_id) {
3651    $instance = $form['#instance'];
3652  
3653    if ($instance['entity_type'] == 'user') {
3654      $form['instance']['settings']['user_register_form'] = array(
3655        '#type' => 'checkbox',
3656        '#title' => t('Display on user registration form.'),
3657        '#description' => t("This is compulsory for 'required' fields."),
3658        // Field instances created in D7 beta releases before the setting was
3659        // introduced might be set as 'required' and 'not shown on user_register
3660        // form'. We make sure the checkbox comes as 'checked' for those.
3661        '#default_value' => $instance['settings']['user_register_form'] || $instance['required'],
3662        // Display just below the 'required' checkbox.
3663        '#weight' => $form['instance']['required']['#weight'] + .1,
3664        // Disabled when the 'required' checkbox is checked.
3665        '#states' => array(
3666          'enabled' => array('input[name="instance[required]"]' => array('checked' => FALSE)),
3667        ),
3668        // Checked when the 'required' checkbox is checked. This is done through
3669        // a custom behavior, since the #states system would also synchronize on
3670        // uncheck.
3671        '#attached' => array(
3672          'js' => array(drupal_get_path('module', 'user') . '/user.js'),
3673        ),
3674      );
3675  
3676      array_unshift($form['#submit'], 'user_form_field_ui_field_edit_form_submit');
3677    }
3678  }
3679  
3680  /**
3681   * Additional submit handler for the 'Edit field instance' form.
3682   *
3683   * Make sure the 'user_register_form' setting is set for required fields.
3684   */
3685  function user_form_field_ui_field_edit_form_submit($form, &$form_state) {
3686    $instance = $form_state['values']['instance'];
3687  
3688    if (!empty($instance['required'])) {
3689      form_set_value($form['instance']['settings']['user_register_form'], 1, $form_state);
3690    }
3691  }
3692  
3693  /**
3694   * Form builder; the user registration form.
3695   *
3696   * @ingroup forms
3697   * @see user_account_form()
3698   * @see user_account_form_validate()
3699   * @see user_register_submit()
3700   */
3701  function user_register_form($form, &$form_state) {
3702    global $user;
3703  
3704    $admin = user_access('administer users');
3705  
3706    // Pass access information to the submit handler. Running an access check
3707    // inside the submit function interferes with form processing and breaks
3708    // hook_form_alter().
3709    $form['administer_users'] = array(
3710       '#type' => 'value',
3711       '#value' => $admin,
3712    );
3713  
3714    // If we aren't admin but already logged on, go to the user page instead.
3715    if (!$admin && $user->uid) {
3716      drupal_goto('user/' . $user->uid);
3717    }
3718  
3719    $form['#user'] = drupal_anonymous_user();
3720    $form['#user_category'] = 'register';
3721  
3722    $form['#attached']['library'][] = array('system', 'jquery.cookie');
3723    $form['#attributes']['class'][] = 'user-info-from-cookie';
3724  
3725    // Start with the default user account fields.
3726    user_account_form($form, $form_state);
3727  
3728    // Attach field widgets, and hide the ones where the 'user_register_form'
3729    // setting is not on.
3730    $langcode = entity_language('user', $form['#user']);
3731    field_attach_form('user', $form['#user'], $form, $form_state, $langcode);
3732    foreach (field_info_instances('user', 'user') as $field_name => $instance) {
3733      if (empty($instance['settings']['user_register_form'])) {
3734        $form[$field_name]['#access'] = FALSE;
3735      }
3736    }
3737  
3738    if ($admin) {
3739      // Redirect back to page which initiated the create request;
3740      // usually admin/people/create.
3741      $form_state['redirect'] = $_GET['q'];
3742    }
3743  
3744    $form['actions'] = array('#type' => 'actions');
3745    $form['actions']['submit'] = array(
3746      '#type' => 'submit',
3747      '#value' => t('Create new account'),
3748    );
3749  
3750    $form['#validate'][] = 'user_register_validate';
3751    // Add the final user registration form submit handler.
3752    $form['#submit'][] = 'user_register_submit';
3753  
3754    return $form;
3755  }
3756  
3757  /**
3758   * Validation function for the user registration form.
3759   */
3760  function user_register_validate($form, &$form_state) {
3761    entity_form_field_validate('user', $form, $form_state);
3762  }
3763  
3764  /**
3765   * Submit handler for the user registration form.
3766   *
3767   * This function is shared by the installation form and the normal registration form,
3768   * which is why it can't be in the user.pages.inc file.
3769   *
3770   * @see user_register_form()
3771   */
3772  function user_register_submit($form, &$form_state) {
3773    $admin = $form_state['values']['administer_users'];
3774  
3775    if (!variable_get('user_email_verification', TRUE) || $admin) {
3776      $pass = $form_state['values']['pass'];
3777    }
3778    else {
3779      $pass = user_password();
3780    }
3781    $notify = !empty($form_state['values']['notify']);
3782  
3783    // Remove unneeded values.
3784    form_state_values_clean($form_state);
3785  
3786    $form_state['values']['pass'] = $pass;
3787    $form_state['values']['init'] = $form_state['values']['mail'];
3788  
3789    $account = $form['#user'];
3790  
3791    entity_form_submit_build_entity('user', $account, $form, $form_state);
3792  
3793    // Populate $edit with the properties of $account, which have been edited on
3794    // this form by taking over all values, which appear in the form values too.
3795    $edit = array_intersect_key((array) $account, $form_state['values']);
3796    $account = user_save($account, $edit);
3797  
3798    // Terminate if an error occurred during user_save().
3799    if (!$account) {
3800      drupal_set_message(t("Error saving user account."), 'error');
3801      $form_state['redirect'] = '';
3802      return;
3803    }
3804    $form_state['user'] = $account;
3805    $form_state['values']['uid'] = $account->uid;
3806  
3807    watchdog('user', 'New user: %name (%email).', array('%name' => $form_state['values']['name'], '%email' => $form_state['values']['mail']), WATCHDOG_NOTICE, l(t('edit'), 'user/' . $account->uid . '/edit'));
3808  
3809    // Add plain text password into user account to generate mail tokens.
3810    $account->password = $pass;
3811  
3812    // New administrative account without notification.
3813    $uri = entity_uri('user', $account);
3814    if ($admin && !$notify) {
3815      drupal_set_message(t('Created a new user account for <a href="@url">%name</a>. No e-mail has been sent.', array('@url' => url($uri['path'], $uri['options']), '%name' => $account->name)));
3816    }
3817    // No e-mail verification required; log in user immediately.
3818    elseif (!$admin && !variable_get('user_email_verification', TRUE) && $account->status) {
3819      _user_mail_notify('register_no_approval_required', $account);
3820      $form_state['uid'] = $account->uid;
3821      user_login_submit(array(), $form_state);
3822      drupal_set_message(t('Registration successful. You are now logged in.'));
3823      $form_state['redirect'] = '';
3824    }
3825    // No administrator approval required.
3826    elseif ($account->status || $notify) {
3827      $op = $notify ? 'register_admin_created' : 'register_no_approval_required';
3828      _user_mail_notify($op, $account);
3829      if ($notify) {
3830        drupal_set_message(t('A welcome message with further instructions has been e-mailed to the new user <a href="@url">%name</a>.', array('@url' => url($uri['path'], $uri['options']), '%name' => $account->name)));
3831      }
3832      else {
3833        drupal_set_message(t('A welcome message with further instructions has been sent to your e-mail address.'));
3834        $form_state['redirect'] = '';
3835      }
3836    }
3837    // Administrator approval required.
3838    else {
3839      _user_mail_notify('register_pending_approval', $account);
3840      drupal_set_message(t('Thank you for applying for an account. Your account is currently pending approval by the site administrator.<br />In the meantime, a welcome message with further instructions has been sent to your e-mail address.'));
3841      $form_state['redirect'] = '';
3842    }
3843  }
3844  
3845  /**
3846   * Implements hook_modules_installed().
3847   */
3848  function user_modules_installed($modules) {
3849    // Assign all available permissions to the administrator role.
3850    $rid = variable_get('user_admin_role', 0);
3851    if ($rid) {
3852      $permissions = array();
3853      foreach ($modules as $module) {
3854        if ($module_permissions = module_invoke($module, 'permission')) {
3855          $permissions = array_merge($permissions, array_keys($module_permissions));
3856        }
3857      }
3858      if (!empty($permissions)) {
3859        user_role_grant_permissions($rid, $permissions);
3860      }
3861    }
3862  }
3863  
3864  /**
3865   * Implements hook_modules_uninstalled().
3866   */
3867  function user_modules_uninstalled($modules) {
3868     db_delete('role_permission')
3869       ->condition('module', $modules, 'IN')
3870       ->execute();
3871  }
3872  
3873  /**
3874   * Helper function to rewrite the destination to avoid redirecting to login page after login.
3875   *
3876   * Third-party authentication modules may use this function to determine the
3877   * proper destination after a user has been properly logged in.
3878   */
3879  function user_login_destination() {
3880    $destination = drupal_get_destination();
3881    if ($destination['destination'] == 'user/login') {
3882      $destination['destination'] = 'user';
3883    }
3884    return $destination;
3885  }
3886  
3887  /**
3888   * Saves visitor information as a cookie so it can be reused.
3889   *
3890   * @param $values
3891   *   An array of key/value pairs to be saved into a cookie.
3892   */
3893  function user_cookie_save(array $values) {
3894    foreach ($values as $field => $value) {
3895      // Set cookie for 365 days.
3896      setrawcookie('Drupal.visitor.' . $field, rawurlencode($value), REQUEST_TIME + 31536000, '/');
3897    }
3898  }
3899  
3900  /**
3901   * Delete a visitor information cookie.
3902   *
3903   * @param $cookie_name
3904   *   A cookie name such as 'homepage'.
3905   */
3906  function user_cookie_delete($cookie_name) {
3907    setrawcookie('Drupal.visitor.' . $cookie_name, '', REQUEST_TIME - 3600, '/');
3908  }
3909  
3910  /**
3911   * Implements hook_rdf_mapping().
3912   */
3913  function user_rdf_mapping() {
3914    return array(
3915      array(
3916        'type' => 'user',
3917        'bundle' => RDF_DEFAULT_BUNDLE,
3918        'mapping' => array(
3919          'rdftype' => array('sioc:UserAccount'),
3920          'name' => array(
3921            'predicates' => array('foaf:name'),
3922          ),
3923          'homepage' => array(
3924            'predicates' => array('foaf:page'),
3925            'type' => 'rel',
3926          ),
3927        ),
3928      ),
3929    );
3930  }
3931  
3932  /**
3933   * Implements hook_file_download_access().
3934   */
3935  function user_file_download_access($field, $entity_type, $entity) {
3936    if ($entity_type == 'user') {
3937      return user_view_access($entity);
3938    }
3939  }
3940  
3941  /**
3942   * Implements hook_system_info_alter().
3943   *
3944   * Drupal 7 ships with two methods to add additional fields to users: Profile
3945   * module, a legacy module dating back from 2002, and Field API integration
3946   * with users. While Field API support for users currently provides less end
3947   * user features, the inefficient data storage mechanism of Profile module, as
3948   * well as its lack of consistency with the rest of the entity / field based
3949   * systems in Drupal 7, make this a sub-optimal solution to those who were not
3950   * using it in previous releases of Drupal.
3951   *
3952   * To prevent new Drupal 7 sites from installing Profile module, and
3953   * unwittingly ending up with two completely different and incompatible methods
3954   * of extending users, only make the Profile module available if the profile_*
3955   * tables are present.
3956   *
3957   * @todo: Remove in D8, pending upgrade path.
3958   */
3959  function user_system_info_alter(&$info, $file, $type) {
3960    if ($type == 'module' && $file->name == 'profile' && db_table_exists('profile_field')) {
3961      $info['hidden'] = FALSE;
3962    }
3963  }

title

Description

title

Description

title

Description

title

title

Body