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