5 * Enables the user registration and login system.
9 * Maximum length of username text field.
11 define('USERNAME_MAX_LENGTH', 60);
14 * Maximum length of user e-mail text field.
16 define('EMAIL_MAX_LENGTH', 254);
19 * Only administrators can create user accounts.
21 define('USER_REGISTER_ADMINISTRATORS_ONLY', 0);
24 * Visitors can create their own accounts.
26 define('USER_REGISTER_VISITORS', 1);
29 * Visitors can create accounts, but they don't become active without
30 * administrative approval.
32 define('USER_REGISTER_VISITORS_ADMINISTRATIVE_APPROVAL', 2);
35 * Implement hook_help().
37 function user_help($path, $arg) {
41 case
'admin/help#user':
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>';
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>';
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>';
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>';
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>';
77 * Invokes a user hook in every module.
79 * We cannot use module_invoke() for this, because the arguments need to
80 * be passed by reference.
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().
90 * An associative array variable containing form values to be passed
91 * as the first parameter of the hook function.
93 * The user account object to be passed as the second parameter of the hook
96 * The category of user information being acted upon.
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);
106 * Implements hook_theme().
108 function user_theme() {
110 'user_picture' => array(
111 'variables' => array('account' => NULL
),
112 'template' => 'user-picture',
114 'user_profile' => array(
115 'render element' => 'elements',
116 'template' => 'user-profile',
117 'file' => 'user.pages.inc',
119 'user_profile_category' => array(
120 'render element' => 'element',
121 'template' => 'user-profile-category',
122 'file' => 'user.pages.inc',
124 'user_profile_item' => array(
125 'render element' => 'element',
126 'template' => 'user-profile-item',
127 'file' => 'user.pages.inc',
129 'user_list' => array(
130 'variables' => array('users' => NULL
, 'title' => NULL
),
132 'user_admin_permissions' => array(
133 'render element' => 'form',
134 'file' => 'user.admin.inc',
136 'user_admin_roles' => array(
137 'render element' => 'form',
138 'file' => 'user.admin.inc',
140 'user_permission_description' => array(
141 'variables' => array('permission_item' => NULL
, 'hide' => NULL
),
142 'file' => 'user.admin.inc',
144 'user_signature' => array(
145 'variables' => array('signature' => NULL
),
151 * Implements hook_entity_info().
153 function user_entity_info() {
156 'label' => t('User'),
157 'controller class' => 'UserController',
158 'base table' => 'users',
159 'uri callback' => 'user_uri',
160 'label callback' => 'format_username',
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
166 'entity keys' => array(
171 'label' => t('User'),
173 'path' => 'admin/config/people/accounts',
174 'access arguments' => array('administer users'),
178 'view modes' => array(
180 'label' => t('User account'),
181 'custom settings' => FALSE
,
190 * Implements callback_entity_info_uri().
192 function user_uri($user) {
194 'path' => 'user/' .
$user->uid
,
199 * Implements hook_field_info_alter().
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
,
212 * Implements hook_field_extra_fields().
214 function user_field_extra_fields() {
215 $return['user']['user'] = array(
218 'label' => t('User name and password'),
219 'description' => t('User module account form elements.'),
223 'label' => t('Timezone'),
224 'description' => t('User module timezone form element.'),
230 'label' => t('History'),
231 'description' => t('User module history view element.'),
241 * Fetches a user object based on an external authentication source.
243 * @param string $authname
244 * The external authentication username.
247 * A fully-loaded user object if the user is found or FALSE if not found.
249 function user_external_load($authname) {
250 $uid = db_query("SELECT uid FROM {authmap} WHERE authname = :authname", array(':authname' => $authname))->fetchField();
253 return user_load($uid);
261 * Load multiple users based on certain conditions.
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.
268 * An array of user IDs.
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
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.
280 * An array of user objects, indexed by uid.
284 * @see user_load_by_mail()
285 * @see user_load_by_name()
286 * @see EntityFieldQuery
288 * @todo Remove $conditions in Drupal 8.
290 function user_load_multiple($uids = array(), $conditions = array(), $reset = FALSE
) {
291 return entity_load('user', $uids, $conditions, $reset);
295 * Controller class for users.
297 * This extends the DrupalDefaultEntityController class, adding required
298 * special handling for user objects.
300 class UserController
extends DrupalDefaultEntityController
{
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();
310 $queried_users[$record->uid
]->roles
[DRUPAL_AUTHENTICATED_RID
] = 'authenticated user';
313 $queried_users[$record->uid
]->roles
[DRUPAL_ANONYMOUS_RID
] = 'anonymous user';
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
;
323 // Add the full file objects for user pictures if enabled.
324 if (!empty($picture_fids) && variable_get('user_pictures', 1) == 1) {
325 $pictures = file_load_multiple($picture_fids);
326 foreach ($queried_users as
$account) {
327 if (!empty($account->picture
) && isset($pictures[$account->picture
])) {
328 $account->picture
= $pictures[$account->picture
];
331 $account->picture
= NULL
;
335 // Call the default attachLoad() method. This will add fields and call
337 parent
::attachLoad($queried_users, $revision_id);
342 * Loads a user object.
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.
350 * @link http://drupal.org/node/218104 Safely impersonating another user @endlink
351 * for more information.
354 * Integer specifying the user ID to load.
356 * TRUE to reset the internal cache and load from the database; FALSE
357 * (default) to load from the internal cache, if set.
360 * A fully-loaded user object upon successful user load, or FALSE if the user
363 * @see user_load_multiple()
365 function user_load($uid, $reset = FALSE
) {
366 $users = user_load_multiple(array($uid), array(), $reset);
367 return reset($users);
371 * Fetch a user object by email address.
374 * String with the account's e-mail address.
376 * A fully-loaded $user object upon successful user load or FALSE if user
379 * @see user_load_multiple()
381 function user_load_by_mail($mail) {
382 $users = user_load_multiple(array(), array('mail' => $mail));
383 return reset($users);
387 * Fetch a user object by account name.
390 * String with the account's user name.
392 * A fully-loaded $user object upon successful user load or FALSE if user
395 * @see user_load_multiple()
397 function user_load_by_name($name) {
398 $users = user_load_multiple(array(), array('name' => $name));
399 return reset($users);
403 * Save changes to a user account or add a new user.
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.
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.
417 * (optional) The category for storing profile information in.
420 * A fully-loaded $user object upon successful save or FALSE if the save failed.
422 * @todo D8: Drop $edit and fix user_save() to be consistent with others.
424 function user_save($account, $edit = array(), $category = 'account') {
425 $transaction = db_transaction();
427 if (!empty($edit['pass'])) {
428 // Allow alternate password hashing schemes.
429 require_once DRUPAL_ROOT .
'/' .
variable_get('password_inc', 'includes/password.inc');
430 $edit['pass'] = user_hash_password(trim($edit['pass']));
431 // Abort if the hashing failed and returned FALSE.
432 if (!$edit['pass']) {
437 // Avoid overwriting an existing password with a blank password.
438 unset($edit['pass']);
440 if (isset($edit['mail'])) {
441 $edit['mail'] = trim($edit['mail']);
444 // Load the stored entity, if any.
445 if (!empty($account->uid
) && !isset($account->original
)) {
446 $account->original
= entity_load_unchanged('user', $account->uid
);
449 if (empty($account)) {
450 $account = new
stdClass();
452 if (!isset($account->is_new
)) {
453 $account->is_new
= empty($account->uid
);
455 // Prepopulate $edit['data'] with the current value of $account->data.
456 // Modules can add to or remove from this array in hook_user_presave().
457 if (!empty($account->data
)) {
458 $edit['data'] = !empty($edit['data']) ?
array_merge($account->data
, $edit['data']) : $account->data
;
461 // Invoke hook_user_presave() for all modules.
462 user_module_invoke('presave', $edit, $account, $category);
464 // Invoke presave operations of Field Attach API and Entity API. Those APIs
465 // require a fully-fledged and updated entity object. Therefore, we need to
466 // copy any new property values of $edit into it.
467 foreach ($edit as
$key => $value) {
468 $account->$key = $value;
470 field_attach_presave('user', $account);
471 module_invoke_all('entity_presave', $account, 'user');
473 if (is_object($account) && !$account->is_new
) {
474 // Process picture uploads.
475 if (!empty($account->picture
->fid
) && (!isset($account->original
->picture
->fid
) || $account->picture
->fid
!= $account->original
->picture
->fid
)) {
476 $picture = $account->picture
;
477 // If the picture is a temporary file move it to its final location and
478 // make it permanent.
479 if (!$picture->status
) {
480 $info = image_get_info($picture->uri
);
481 $picture_directory = file_default_scheme() .
'://' .
variable_get('user_picture_path', 'pictures');
483 // Prepare the pictures directory.
484 file_prepare_directory($picture_directory, FILE_CREATE_DIRECTORY
);
485 $destination = file_stream_wrapper_uri_normalize($picture_directory .
'/picture-' .
$account->uid .
'-' . REQUEST_TIME .
'.' .
$info['extension']);
487 // Move the temporary file into the final location.
488 if ($picture = file_move($picture, $destination, FILE_EXISTS_RENAME
)) {
489 $picture->status
= FILE_STATUS_PERMANENT
;
490 $account->picture
= file_save($picture);
491 file_usage_add($picture, 'user', 'user', $account->uid
);
494 // Delete the previous picture if it was deleted or replaced.
495 if (!empty($account->original
->picture
->fid
)) {
496 file_usage_delete($account->original
->picture
, 'user', 'user', $account->uid
);
497 file_delete($account->original
->picture
);
500 elseif (isset($edit['picture_delete']) && $edit['picture_delete']) {
501 file_usage_delete($account->original
->picture
, 'user', 'user', $account->uid
);
502 file_delete($account->original
->picture
);
504 $account->picture
= empty($account->picture
->fid
) ?
0 : $account->picture
->fid
;
506 // Do not allow 'uid' to be changed.
507 $account->uid
= $account->original
->uid
;
508 // Save changes to the user table.
509 $success = drupal_write_record('users', $account, 'uid');
510 if ($success === FALSE
) {
511 // The query failed - better to abort the save than risk further
516 // Reload user roles if provided.
517 if ($account->roles
!= $account->original
->roles
) {
518 db_delete('users_roles')
519 ->condition('uid', $account->uid
)
522 $query = db_insert('users_roles')->fields(array('uid', 'rid'));
523 foreach (array_keys($account->roles
) as
$rid) {
524 if (!in_array($rid, array(DRUPAL_ANONYMOUS_RID
, DRUPAL_AUTHENTICATED_RID
))) {
525 $query->values(array(
526 'uid' => $account->uid
,
534 // Delete a blocked user's sessions to kick them if they are online.
535 if ($account->original
->status
!= $account->status
&& $account->status
== 0) {
536 drupal_session_destroy_uid($account->uid
);
539 // If the password changed, delete all open sessions and recreate
541 if ($account->pass
!= $account->original
->pass
) {
542 drupal_session_destroy_uid($account->uid
);
543 if ($account->uid
== $GLOBALS['user']->uid
) {
544 drupal_session_regenerate();
549 field_attach_update('user', $account);
551 // Send emails after we have the new user object.
552 if ($account->status
!= $account->original
->status
) {
553 // The user's status is changing; conditionally send notification email.
554 $op = $account->status
== 1 ?
'status_activated' : 'status_blocked';
555 _user_mail_notify($op, $account);
558 // Update $edit with any interim changes to $account.
559 foreach ($account as
$key => $value) {
560 if (!property_exists($account->original
, $key) || $value !== $account->original
->$key) {
561 $edit[$key] = $value;
564 user_module_invoke('update', $edit, $account, $category);
565 module_invoke_all('entity_update', $account, 'user');
568 // Allow 'uid' to be set by the caller. There is no danger of writing an
569 // existing user as drupal_write_record will do an INSERT.
570 if (empty($account->uid
)) {
571 $account->uid
= db_next_id(db_query('SELECT MAX(uid) FROM {users}')->fetchField());
573 // Allow 'created' to be set by the caller.
574 if (!isset($account->created
)) {
575 $account->created
= REQUEST_TIME
;
577 $success = drupal_write_record('users', $account);
578 if ($success === FALSE
) {
579 // On a failed INSERT some other existing user's uid may be returned.
580 // We must abort to avoid overwriting their account.
584 // Make sure $account is properly initialized.
585 $account->roles
[DRUPAL_AUTHENTICATED_RID
] = 'authenticated user';
587 field_attach_insert('user', $account);
588 $edit = (array) $account;
589 user_module_invoke('insert', $edit, $account, $category);
590 module_invoke_all('entity_insert', $account, 'user');
593 if (count($account->roles
) > 1) {
594 $query = db_insert('users_roles')->fields(array('uid', 'rid'));
595 foreach (array_keys($account->roles
) as
$rid) {
596 if (!in_array($rid, array(DRUPAL_ANONYMOUS_RID
, DRUPAL_AUTHENTICATED_RID
))) {
597 $query->values(array(
598 'uid' => $account->uid
,
606 // Clear internal properties.
607 unset($account->is_new
);
608 unset($account->original
);
609 // Clear the static loading cache.
610 entity_get_controller('user')->resetCache(array($account->uid
));
614 catch (Exception
$e) {
615 $transaction->rollback();
616 watchdog_exception('user', $e);
622 * Verify the syntax of the given name.
624 function user_validate_name($name) {
626 return t('You must enter a username.');
628 if (substr($name, 0, 1) == ' ') {
629 return t('The username cannot begin with a space.');
631 if (substr($name, -1) == ' ') {
632 return t('The username cannot end with a space.');
634 if (strpos($name, ' ') !== FALSE
) {
635 return t('The username cannot contain multiple spaces in a row.');
637 if (preg_match('/[^\x{80}-\x{F7} a-z0-9@_.\'-]/i', $name)) {
638 return t('The username contains an illegal character.');
640 if (preg_match('/[\x{80}-\x{A0}' .
// Non-printable ISO-8859-1 + NBSP
641 '\x{AD}' .
// Soft-hyphen
642 '\x{2000}-\x{200F}' .
// Various space characters
643 '\x{2028}-\x{202F}' .
// Bidirectional text overrides
644 '\x{205F}-\x{206F}' .
// Various text hinting characters
645 '\x{FEFF}' .
// Byte order mark
646 '\x{FF01}-\x{FF60}' .
// Full-width latin
647 '\x{FFF9}-\x{FFFD}' .
// Replacement characters
648 '\x{0}-\x{1F}]/u', // NULL byte and control characters
650 return t('The username contains an illegal character.');
652 if (drupal_strlen($name) > USERNAME_MAX_LENGTH
) {
653 return t('The username %name is too long: it must be %max characters or less.', array('%name' => $name, '%max' => USERNAME_MAX_LENGTH
));
658 * Validates a user's email address.
660 * Checks that a user's email address exists and follows all standard
661 * validation rules. Returns error messages when the address is invalid.
664 * A user's email address.
667 * If the address is invalid, a human-readable error message is returned.
668 * If the address is valid, nothing is returned.
670 function user_validate_mail($mail) {
672 return t('You must enter an e-mail address.');
674 if (!valid_email_address($mail)) {
675 return t('The e-mail address %mail is not valid.', array('%mail' => $mail));
680 * Validates an image uploaded by a user.
682 * @see user_account_form()
684 function user_validate_picture(&$form, &$form_state) {
685 // If required, validate the uploaded picture.
687 'file_validate_is_image' => array(),
688 'file_validate_image_resolution' => array(variable_get('user_picture_dimensions', '85x85')),
689 'file_validate_size' => array(variable_get('user_picture_file_size', '30') * 1024),
692 // Save the file as a temporary file.
693 $file = file_save_upload('picture_upload', $validators);
694 if ($file === FALSE
) {
695 form_set_error('picture_upload', t("Failed to upload the picture image; the %directory directory doesn't exist or is not writable.", array('%directory' => variable_get('user_picture_path', 'pictures'))));
697 elseif ($file !== NULL
) {
698 $form_state['values']['picture_upload'] = $file;
703 * Generate a random alphanumeric password.
705 function user_password($length = 10) {
706 // This variable contains the list of allowable characters for the
707 // password. Note that the number 0 and the letter 'O' have been
708 // removed to avoid confusion between the two. The same is true
709 // of 'I', 1, and 'l'.
710 $allowable_characters = 'abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789';
712 // Zero-based count of characters in the allowable list:
713 $len = strlen($allowable_characters) - 1;
715 // Declare the password as a blank string.
718 // Loop the number of times specified by $length.
719 for ($i = 0; $i < $length; $i++) {
721 // Each iteration, pick a random character from the
722 // allowable string and append it to the password:
723 $pass .
= $allowable_characters[mt_rand(0, $len)];
730 * Determine the permissions for one or more roles.
733 * An array whose keys are the role IDs of interest, such as $user->roles.
736 * An array indexed by role ID. Each value is an array whose keys are the
737 * permission strings for the given role ID.
739 function user_role_permissions($roles = array()) {
740 $cache = &drupal_static(__FUNCTION__
, array());
742 $role_permissions = $fetch = array();
745 foreach ($roles as
$rid => $name) {
746 if (isset($cache[$rid])) {
747 $role_permissions[$rid] = $cache[$rid];
750 // Add this rid to the list of those needing to be fetched.
752 // Prepare in case no permissions are returned.
753 $cache[$rid] = array();
758 // Get from the database permissions that were not in the static variable.
759 // Only role IDs with at least one permission assigned will return rows.
760 $result = db_query("SELECT rid, permission FROM {role_permission} WHERE rid IN (:fetch)", array(':fetch' => $fetch));
762 foreach ($result as
$row) {
763 $cache[$row->rid
][$row->permission
] = TRUE
;
765 foreach ($fetch as
$rid) {
766 // For every rid, we know we at least assigned an empty array.
767 $role_permissions[$rid] = $cache[$rid];
772 return $role_permissions;
776 * Determine whether the user has a given privilege.
779 * The permission, such as "administer nodes", being checked for.
781 * (optional) The account to check, if not given use currently logged in user.
784 * Boolean TRUE if the current user has the requested permission.
786 * All permission checks in Drupal should go through this function. This
787 * way, we guarantee consistent behavior, and ensure that the superuser
788 * can perform all actions.
790 function user_access($string, $account = NULL
) {
793 if (!isset($account)) {
797 // User #1 has all privileges:
798 if ($account->uid
== 1) {
802 // To reduce the number of SQL queries, we cache the user's permissions
803 // in a static variable.
804 // Use the advanced drupal_static() pattern, since this is called very often.
805 static
$drupal_static_fast;
806 if (!isset($drupal_static_fast)) {
807 $drupal_static_fast['perm'] = &drupal_static(__FUNCTION__
);
809 $perm = &$drupal_static_fast['perm'];
810 if (!isset($perm[$account->uid
])) {
811 $role_permissions = user_role_permissions($account->roles
);
814 foreach ($role_permissions as
$one_role) {
817 $perm[$account->uid
] = $perms;
820 return isset($perm[$account->uid
][$string]);
824 * Checks for usernames blocked by user administration.
827 * A string containing a name of the user.
830 * Object with property 'name' (the user name), if the user is blocked;
831 * FALSE if the user is not blocked.
833 function user_is_blocked($name) {
834 return db_select('users')
835 ->fields('users', array('name'))
836 ->condition('name', db_like($name), 'LIKE')
837 ->condition('status', 0)
838 ->execute()->fetchObject();
842 * Implements hook_permission().
844 function user_permission() {
846 'administer permissions' => array(
847 'title' => t('Administer permissions'),
848 'restrict access' => TRUE
,
850 'administer users' => array(
851 'title' => t('Administer users'),
852 'restrict access' => TRUE
,
854 'access user profiles' => array(
855 'title' => t('View user profiles'),
857 'change own username' => array(
858 'title' => t('Change own username'),
860 'cancel account' => array(
861 'title' => t('Cancel own user account'),
862 'description' => t('Note: content may be kept, unpublished, deleted or transferred to the %anonymous-name user depending on the configured <a href="@user-settings-url">user settings</a>.', array('%anonymous-name' => variable_get('anonymous', t('Anonymous')), '@user-settings-url' => url('admin/config/people/accounts'))),
864 'select account cancellation method' => array(
865 'title' => t('Select method for cancelling own account'),
866 'restrict access' => TRUE
,
872 * Implements hook_file_download().
874 * Ensure that user pictures (avatars) are always downloadable.
876 function user_file_download($uri) {
877 if (strpos(file_uri_target($uri), variable_get('user_picture_path', 'pictures') .
'/picture-') === 0) {
878 $info = image_get_info($uri);
879 return array('Content-Type' => $info['mime_type']);
884 * Implements hook_file_move().
886 function user_file_move($file, $source) {
887 // If a user's picture is replaced with a new one, update the record in
889 if (isset($file->fid
) && isset($source->fid
) && $file->fid
!= $source->fid
) {
892 'picture' => $file->fid
,
894 ->condition('picture', $source->fid
)
900 * Implements hook_file_delete().
902 function user_file_delete($file) {
903 // Remove any references to the file.
905 ->fields(array('picture' => 0))
906 ->condition('picture', $file->fid
)
911 * Implements hook_search_info().
913 function user_search_info() {
920 * Implements hook_search_access().
922 function user_search_access() {
923 return user_access('access user profiles');
927 * Implements hook_search_execute().
929 function user_search_execute($keys = NULL
, $conditions = NULL
) {
931 // Replace wildcards with MySQL/PostgreSQL wildcards.
932 $keys = preg_replace('!\*+!', '%', $keys);
933 $query = db_select('users')->extend('PagerDefault');
934 $query->fields('users', array('uid'));
935 if (user_access('administer users')) {
936 // Administrators can also search in the otherwise private email field,
937 // and they don't need to be restricted to only active users.
938 $query->fields('users', array('mail'));
939 $query->condition(db_or()->
940 condition('name', '%' .
db_like($keys) .
'%', 'LIKE')->
941 condition('mail', '%' .
db_like($keys) .
'%', 'LIKE'));
944 // Regular users can only search via usernames, and we do not show them
946 $query->condition('name', '%' .
db_like($keys) .
'%', 'LIKE')
947 ->condition('status', 1);
953 $accounts = user_load_multiple($uids);
956 foreach ($accounts as
$account) {
958 'title' => format_username($account),
959 'link' => url('user/' .
$account->uid
, array('absolute' => TRUE
)),
961 if (user_access('administer users')) {
962 $result['title'] .
= ' (' .
$account->mail .
')';
964 $results[] = $result;
971 * Implements hook_element_info().
973 function user_element_info() {
974 $types['user_profile_category'] = array(
975 '#theme_wrappers' => array('user_profile_category'),
977 $types['user_profile_item'] = array(
978 '#theme' => 'user_profile_item',
984 * Implements hook_user_view().
986 function user_user_view($account) {
987 $account->content
['user_picture'] = array(
988 '#markup' => theme('user_picture', array('account' => $account)),
991 if (!isset($account->content
['summary'])) {
992 $account->content
['summary'] = array();
994 $account->content
['summary'] += array(
995 '#type' => 'user_profile_category',
996 '#attributes' => array('class' => array('user-member')),
998 '#title' => t('History'),
1000 $account->content
['summary']['member_for'] = array(
1001 '#type' => 'user_profile_item',
1002 '#title' => t('Member for'),
1003 '#markup' => format_interval(REQUEST_TIME
- $account->created
),
1008 * Helper function to add default user account fields to user registration and edit form.
1010 * @see user_account_form_validate()
1011 * @see user_validate_current_pass()
1012 * @see user_validate_picture()
1013 * @see user_validate_mail()
1015 function user_account_form(&$form, &$form_state) {
1018 $account = $form['#user'];
1019 $register = ($form['#user']->uid
> 0 ? FALSE
: TRUE
);
1021 $admin = user_access('administer users');
1023 $form['#validate'][] = 'user_account_form_validate';
1025 // Account information.
1026 $form['account'] = array(
1027 '#type' => 'container',
1030 // Only show name field on registration form or user can change own username.
1031 $form['account']['name'] = array(
1032 '#type' => 'textfield',
1033 '#title' => t('Username'),
1034 '#maxlength' => USERNAME_MAX_LENGTH
,
1035 '#description' => t('Spaces are allowed; punctuation is not allowed except for periods, hyphens, apostrophes, and underscores.'),
1036 '#required' => TRUE
,
1037 '#attributes' => array('class' => array('username')),
1038 '#default_value' => (!$register ?
$account->name
: ''),
1039 '#access' => ($register || ($user->uid
== $account->uid
&& user_access('change own username')) || $admin),
1043 $form['account']['mail'] = array(
1044 '#type' => 'textfield',
1045 '#title' => t('E-mail address'),
1046 '#maxlength' => EMAIL_MAX_LENGTH
,
1047 '#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.'),
1048 '#required' => TRUE
,
1049 '#default_value' => (!$register ?
$account->mail : ''),
1052 // Display password field only for existing users or when user is allowed to
1053 // assign a password during registration.
1055 $form['account']['pass'] = array(
1056 '#type' => 'password_confirm',
1058 '#description' => t('To change the current user password, enter the new password in both fields.'),
1060 // To skip the current password field, the user must have logged in via a
1061 // one-time link and have the token in the URL.
1062 $pass_reset = isset($_SESSION['pass_reset_' .
$account->uid
]) && isset($_GET['pass-reset-token']) && ($_GET['pass-reset-token'] == $_SESSION['pass_reset_' .
$account->uid
]);
1063 $protected_values = array();
1064 $current_pass_description = '';
1065 // The user may only change their own password without their current
1066 // password if they logged in via a one-time login link.
1068 $protected_values['mail'] = $form['account']['mail']['#title'];
1069 $protected_values['pass'] = t('Password');
1070 $request_new = l(t('Request new password'), 'user/password', array('attributes' => array('title' => t('Request new password via e-mail.'))));
1071 $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));
1073 // The user must enter their current password to change to a new one.
1074 if ($user->uid
== $account->uid
) {
1075 $form['account']['current_pass_required_values'] = array(
1077 '#value' => $protected_values,
1079 $form['account']['current_pass'] = array(
1080 '#type' => 'password',
1081 '#title' => t('Current password'),
1083 '#access' => !empty($protected_values),
1084 '#description' => $current_pass_description,
1086 // Do not let web browsers remember this password, since we are trying
1087 // to confirm that the person submitting the form actually knows the
1089 '#attributes' => array('autocomplete' => 'off'),
1091 $form['#validate'][] = 'user_validate_current_pass';
1094 elseif (!variable_get('user_email_verification', TRUE
) || $admin) {
1095 $form['account']['pass'] = array(
1096 '#type' => 'password_confirm',
1098 '#description' => t('Provide a password for the new account in both fields.'),
1099 '#required' => TRUE
,
1104 $status = isset($account->status
) ?
$account->status
: 1;
1107 $status = $register ?
variable_get('user_register', USER_REGISTER_VISITORS_ADMINISTRATIVE_APPROVAL
) == USER_REGISTER_VISITORS
: $account->status
;
1109 $form['account']['status'] = array(
1110 '#type' => 'radios',
1111 '#title' => t('Status'),
1112 '#default_value' => $status,
1113 '#options' => array(t('Blocked'), t('Active')),
1114 '#access' => $admin,
1117 $roles = array_map('check_plain', user_roles(TRUE
));
1118 // The disabled checkbox subelement for the 'authenticated user' role
1119 // must be generated separately and added to the checkboxes element,
1120 // because of a limitation in Form API not supporting a single disabled
1121 // checkbox within a set of checkboxes.
1122 // @todo This should be solved more elegantly. See issue #119038.
1123 $checkbox_authenticated = array(
1124 '#type' => 'checkbox',
1125 '#title' => $roles[DRUPAL_AUTHENTICATED_RID
],
1126 '#default_value' => TRUE
,
1127 '#disabled' => TRUE
,
1129 unset($roles[DRUPAL_AUTHENTICATED_RID
]);
1130 $form['account']['roles'] = array(
1131 '#type' => 'checkboxes',
1132 '#title' => t('Roles'),
1133 '#default_value' => (!$register && isset($account->roles
) ?
array_keys($account->roles
) : array()),
1134 '#options' => $roles,
1135 '#access' => $roles && user_access('administer permissions'),
1136 DRUPAL_AUTHENTICATED_RID
=> $checkbox_authenticated,
1139 $form['account']['notify'] = array(
1140 '#type' => 'checkbox',
1141 '#title' => t('Notify user of new account'),
1142 '#access' => $register && $admin,
1146 $form['signature_settings'] = array(
1147 '#type' => 'fieldset',
1148 '#title' => t('Signature settings'),
1150 '#access' => (!$register && variable_get('user_signatures', 0)),
1153 $form['signature_settings']['signature'] = array(
1154 '#type' => 'text_format',
1155 '#title' => t('Signature'),
1156 '#default_value' => isset($account->signature
) ?
$account->signature
: '',
1157 '#description' => t('Your signature will be publicly displayed at the end of your comments.'),
1158 '#format' => isset($account->signature_format
) ?
$account->signature_format
: NULL
,
1162 $form['picture'] = array(
1163 '#type' => 'fieldset',
1164 '#title' => t('Picture'),
1166 '#access' => (!$register && variable_get('user_pictures', 0)),
1168 $form['picture']['picture'] = array(
1170 '#value' => isset($account->picture
) ?
$account->picture
: NULL
,
1172 $form['picture']['picture_current'] = array(
1173 '#markup' => theme('user_picture', array('account' => $account)),
1175 $form['picture']['picture_delete'] = array(
1176 '#type' => 'checkbox',
1177 '#title' => t('Delete picture'),
1178 '#access' => !empty($account->picture
->fid
),
1179 '#description' => t('Check this box to delete your current picture.'),
1181 $form['picture']['picture_upload'] = array(
1183 '#title' => t('Upload picture'),
1185 '#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', '')),
1187 $form['#validate'][] = 'user_validate_picture';
1191 * Form validation handler for the current password on the user_account_form().
1193 * @see user_account_form()
1195 function user_validate_current_pass(&$form, &$form_state) {
1196 $account = $form['#user'];
1197 foreach ($form_state['values']['current_pass_required_values'] as
$key => $name) {
1198 // This validation only works for required textfields (like mail) or
1199 // form values like password_confirm that have their own validation
1200 // that prevent them from being empty if they are changed.
1201 if ((strlen(trim($form_state['values'][$key])) > 0) && ($form_state['values'][$key] != $account->$key)) {
1202 require_once DRUPAL_ROOT .
'/' .
variable_get('password_inc', 'includes/password.inc');
1203 $current_pass_failed = empty($form_state['values']['current_pass']) || !user_check_password($form_state['values']['current_pass'], $account);
1204 if ($current_pass_failed) {
1205 form_set_error('current_pass', t("Your current password is missing or incorrect; it's required to change the %name.", array('%name' => $name)));
1206 form_set_error($key);
1208 // We only need to check the password once.
1215 * Form validation handler for user_account_form().
1217 * @see user_account_form()
1219 function user_account_form_validate($form, &$form_state) {
1220 if ($form['#user_category'] == 'account' || $form['#user_category'] == 'register') {
1221 $account = $form['#user'];
1222 // Validate new or changing username.
1223 if (isset($form_state['values']['name'])) {
1224 if ($error = user_validate_name($form_state['values']['name'])) {
1225 form_set_error('name', $error);
1227 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()) {
1228 form_set_error('name', t('The name %name is already taken.', array('%name' => $form_state['values']['name'])));
1232 // Trim whitespace from mail, to prevent confusing 'e-mail not valid'
1233 // warnings often caused by cutting and pasting.
1234 $mail = trim($form_state['values']['mail']);
1235 form_set_value($form['account']['mail'], $mail, $form_state);
1237 // Validate the e-mail address, and check if it is taken by an existing user.
1238 if ($error = user_validate_mail($form_state['values']['mail'])) {
1239 form_set_error('mail', $error);
1241 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()) {
1242 // Format error message dependent on whether the user is logged in or not.
1243 if ($GLOBALS['user']->uid
) {
1244 form_set_error('mail', t('The e-mail address %email is already taken.', array('%email' => $form_state['values']['mail'])));
1247 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'))));
1251 // Make sure the signature isn't longer than the size of the database field.
1252 // Signatures are disabled by default, so make sure it exists first.
1253 if (isset($form_state['values']['signature'])) {
1254 // Move text format for user signature into 'signature_format'.
1255 $form_state['values']['signature_format'] = $form_state['values']['signature']['format'];
1256 // Move text value for user signature into 'signature'.
1257 $form_state['values']['signature'] = $form_state['values']['signature']['value'];
1259 $user_schema = drupal_get_schema('users');
1260 if (drupal_strlen($form_state['values']['signature']) > $user_schema['fields']['signature']['length']) {
1261 form_set_error('signature', t('The signature is too long: it must be %max characters or less.', array('%max' => $user_schema['fields']['signature']['length'])));
1268 * Implements hook_user_presave().
1270 function user_user_presave(&$edit, $account, $category) {
1271 if ($category == 'account' || $category == 'register') {
1272 if (!empty($edit['picture_upload'])) {
1273 $edit['picture'] = $edit['picture_upload'];
1275 // Delete picture if requested, and if no replacement picture was given.
1276 elseif (!empty($edit['picture_delete'])) {
1277 $edit['picture'] = NULL
;
1279 // Prepare user roles.
1280 if (isset($edit['roles'])) {
1281 $edit['roles'] = array_filter($edit['roles']);
1285 // Move account cancellation information into $user->data.
1286 foreach (array('user_cancel_method', 'user_cancel_notify') as
$key) {
1287 if (isset($edit[$key])) {
1288 $edit['data'][$key] = $edit[$key];
1294 * Implements hook_user_categories().
1296 function user_user_categories() {
1298 'name' => 'account',
1299 'title' => t('Account settings'),
1304 function user_login_block($form) {
1305 $form['#action'] = url(current_path(), array('query' => drupal_get_destination(), 'external' => FALSE
));
1306 $form['#id'] = 'user-login-form';
1307 $form['#validate'] = user_login_default_validators();
1308 $form['#submit'][] = 'user_login_submit';
1309 $form['name'] = array('#type' => 'textfield',
1310 '#title' => t('Username'),
1311 '#maxlength' => USERNAME_MAX_LENGTH
,
1313 '#required' => TRUE
,
1315 $form['pass'] = array('#type' => 'password',
1316 '#title' => t('Password'),
1318 '#required' => TRUE
,
1320 $form['actions'] = array('#type' => 'actions');
1321 $form['actions']['submit'] = array('#type' => 'submit',
1322 '#value' => t('Log in'),
1325 if (variable_get('user_register', USER_REGISTER_VISITORS_ADMINISTRATIVE_APPROVAL
)) {
1326 $items[] = l(t('Create new account'), 'user/register', array('attributes' => array('title' => t('Create a new user account.'))));
1328 $items[] = l(t('Request new password'), 'user/password', array('attributes' => array('title' => t('Request new password via e-mail.'))));
1329 $form['links'] = array('#markup' => theme('item_list', array('items' => $items)));
1334 * Implements hook_block_info().
1336 function user_block_info() {
1339 $blocks['login']['info'] = t('User login');
1340 // Not worth caching.
1341 $blocks['login']['cache'] = DRUPAL_NO_CACHE
;
1343 $blocks['new']['info'] = t('Who\'s new');
1344 $blocks['new']['properties']['administrative'] = TRUE
;
1346 // Too dynamic to cache.
1347 $blocks['online']['info'] = t('Who\'s online');
1348 $blocks['online']['cache'] = DRUPAL_NO_CACHE
;
1349 $blocks['online']['properties']['administrative'] = TRUE
;
1355 * Implements hook_block_configure().
1357 function user_block_configure($delta = '') {
1362 $form['user_block_whois_new_count'] = array(
1363 '#type' => 'select',
1364 '#title' => t('Number of users to display'),
1365 '#default_value' => variable_get('user_block_whois_new_count', 5),
1366 '#options' => drupal_map_assoc(array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)),
1371 $period = drupal_map_assoc(array(30, 60, 120, 180, 300, 600, 900, 1800, 2700, 3600, 5400, 7200, 10800, 21600, 43200, 86400), 'format_interval');
1372 $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.'));
1373 $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.'));
1379 * Implements hook_block_save().
1381 function user_block_save($delta = '', $edit = array()) {
1386 variable_set('user_block_whois_new_count', $edit['user_block_whois_new_count']);
1390 variable_set('user_block_seconds_online', $edit['user_block_seconds_online']);
1391 variable_set('user_block_max_list_count', $edit['user_block_max_list_count']);
1397 * Implements hook_block_view().
1399 function user_block_view($delta = '') {
1406 // For usability's sake, avoid showing two login forms on one page.
1407 if (!$user->uid
&& !(arg(0) == 'user' && !is_numeric(arg(1)))) {
1409 $block['subject'] = t('User login');
1410 $block['content'] = drupal_get_form('user_login_block');
1415 if (user_access('access content')) {
1416 // Retrieve a list of new users who have subsequently accessed the site successfully.
1417 $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();
1418 $output = theme('user_list', array('users' => $items));
1420 $block['subject'] = t('Who\'s new');
1421 $block['content'] = $output;
1426 if (user_access('access content')) {
1427 // Count users active within the defined period.
1428 $interval = REQUEST_TIME
- variable_get('user_block_seconds_online', 900);
1430 // Perform database queries to gather online user lists. We use s.timestamp
1431 // rather than u.access because it is much faster.
1432 $authenticated_count = db_query("SELECT COUNT(DISTINCT s.uid) FROM {sessions} s WHERE s.timestamp >= :timestamp AND s.uid > 0", array(':timestamp' => $interval))->fetchField();
1434 $output = '<p>' .
format_plural($authenticated_count, 'There is currently 1 user online.', 'There are currently @count users online.') .
'</p>';
1436 // Display a list of currently online users.
1437 $max_users = variable_get('user_block_max_list_count', 10);
1438 if ($authenticated_count && $max_users) {
1439 $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();
1440 $output .
= theme('user_list', array('users' => $items));
1443 $block['subject'] = t('Who\'s online');
1444 $block['content'] = $output;
1451 * Process variables for user-picture.tpl.php.
1453 * The $variables array contains the following arguments:
1454 * - $account: A user, node or comment object with 'name', 'uid' and 'picture'
1457 * @see user-picture.tpl.php
1459 function template_preprocess_user_picture(&$variables) {
1460 $variables['user_picture'] = '';
1461 if (variable_get('user_pictures', 0)) {
1462 $account = $variables['account'];
1463 if (!empty($account->picture
)) {
1464 // @TODO: Ideally this function would only be passed file objects, but
1465 // since there's a lot of legacy code that JOINs the {users} table to
1466 // {node} or {comments} and passes the results into this function if we
1467 // a numeric value in the picture field we'll assume it's a file id
1468 // and load it for them. Once we've got user_load_multiple() and
1469 // comment_load_multiple() functions the user module will be able to load
1470 // the picture files in mass during the object's load process.
1471 if (is_numeric($account->picture
)) {
1472 $account->picture
= file_load($account->picture
);
1474 if (!empty($account->picture
->uri
)) {
1475 $filepath = $account->picture
->uri
;
1478 elseif (variable_get('user_picture_default', '')) {
1479 $filepath = variable_get('user_picture_default', '');
1481 if (isset($filepath)) {
1482 $alt = t("@user's picture", array('@user' => format_username($account)));
1483 // If the image does not have a valid Drupal scheme (for eg. HTTP),
1484 // don't load image styles.
1485 if (module_exists('image') && file_valid_uri($filepath) && $style = variable_get('user_picture_style', '')) {
1486 $variables['user_picture'] = theme('image_style', array('style_name' => $style, 'path' => $filepath, 'alt' => $alt, 'title' => $alt));
1489 $variables['user_picture'] = theme('image', array('path' => $filepath, 'alt' => $alt, 'title' => $alt));
1491 if (!empty($account->uid
) && user_access('access user profiles')) {
1492 $attributes = array('attributes' => array('title' => t('View user profile.')), 'html' => TRUE
);
1493 $variables['user_picture'] = l($variables['user_picture'], "user/$account->uid", $attributes);
1500 * Returns HTML for a list of users.
1503 * An associative array containing:
1504 * - users: An array with user objects. Should contain at least the name and
1506 * - title: (optional) Title to pass on to theme_item_list().
1508 * @ingroup themeable
1510 function theme_user_list($variables) {
1511 $users = $variables['users'];
1512 $title = $variables['title'];
1515 if (!empty($users)) {
1516 foreach ($users as
$user) {
1517 $items[] = theme('username', array('account' => $user));
1520 return theme('item_list', array('items' => $items, 'title' => $title));
1524 * Determines if the current user is anonymous.
1527 * TRUE if the user is anonymous, FALSE if the user is authenticated.
1529 function user_is_anonymous() {
1530 // Menu administrators can see items for anonymous when administering.
1531 return !$GLOBALS['user']->uid
|| !empty($GLOBALS['menu_admin']);
1535 * Determines if the current user is logged in.
1538 * TRUE if the user is logged in, FALSE if the user is anonymous.
1540 function user_is_logged_in() {
1541 return (bool
) $GLOBALS['user']->uid
;
1545 * Determines if the current user has access to the user registration page.
1548 * TRUE if the user is not already logged in and can register for an account.
1550 function user_register_access() {
1551 return user_is_anonymous() && variable_get('user_register', USER_REGISTER_VISITORS_ADMINISTRATIVE_APPROVAL
);
1555 * User view access callback.
1558 * Can either be a full user object or a $uid.
1560 function user_view_access($account) {
1561 $uid = is_object($account) ?
$account->uid
: (int) $account;
1563 // Never allow access to view the anonymous user account.
1565 // Admins can view all, users can view own profiles at all times.
1566 if ($GLOBALS['user']->uid
== $uid || user_access('administer users')) {
1569 elseif (user_access('access user profiles')) {
1570 // At this point, load the complete account object.
1571 if (!is_object($account)) {
1572 $account = user_load($uid);
1574 return (is_object($account) && $account->status
);
1581 * Access callback for user account editing.
1583 function user_edit_access($account) {
1584 return (($GLOBALS['user']->uid
== $account->uid
) || user_access('administer users')) && $account->uid
> 0;
1588 * Menu access callback; limit access to account cancellation pages.
1590 * Limit access to users with the 'cancel account' permission or administrative
1591 * users, and prevent the anonymous user from cancelling the account.
1593 function user_cancel_access($account) {
1594 return ((($GLOBALS['user']->uid
== $account->uid
) && user_access('cancel account')) || user_access('administer users')) && $account->uid
> 0;
1598 * Implements hook_menu().
1600 function user_menu() {
1601 $items['user/autocomplete'] = array(
1602 'title' => 'User autocomplete',
1603 'page callback' => 'user_autocomplete',
1604 'access callback' => 'user_access',
1605 'access arguments' => array('access user profiles'),
1606 'type' => MENU_CALLBACK
,
1607 'file' => 'user.pages.inc',
1610 // Registration and login pages.
1611 $items['user'] = array(
1612 'title' => 'User account',
1613 'title callback' => 'user_menu_title',
1614 'page callback' => 'user_page',
1615 'access callback' => TRUE
,
1616 'file' => 'user.pages.inc',
1618 'menu_name' => 'user-menu',
1621 $items['user/login'] = array(
1622 'title' => 'Log in',
1623 'access callback' => 'user_is_anonymous',
1624 'type' => MENU_DEFAULT_LOCAL_TASK
,
1627 $items['user/register'] = array(
1628 'title' => 'Create new account',
1629 'page callback' => 'drupal_get_form',
1630 'page arguments' => array('user_register_form'),
1631 'access callback' => 'user_register_access',
1632 'type' => MENU_LOCAL_TASK
,
1635 $items['user/password'] = array(
1636 'title' => 'Request new password',
1637 'page callback' => 'drupal_get_form',
1638 'page arguments' => array('user_pass'),
1639 'access callback' => TRUE
,
1640 'type' => MENU_LOCAL_TASK
,
1641 'file' => 'user.pages.inc',
1643 $items['user/reset/%/%/%'] = array(
1644 'title' => 'Reset password',
1645 'page callback' => 'drupal_get_form',
1646 'page arguments' => array('user_pass_reset', 2, 3, 4),
1647 'access callback' => TRUE
,
1648 'type' => MENU_CALLBACK
,
1649 'file' => 'user.pages.inc',
1652 $items['user/logout'] = array(
1653 'title' => 'Log out',
1654 'access callback' => 'user_is_logged_in',
1655 'page callback' => 'user_logout',
1657 'menu_name' => 'user-menu',
1658 'file' => 'user.pages.inc',
1661 // User listing pages.
1662 $items['admin/people'] = array(
1663 'title' => 'People',
1664 'description' => 'Manage user accounts, roles, and permissions.',
1665 'page callback' => 'user_admin',
1666 'page arguments' => array('list'),
1667 'access arguments' => array('administer users'),
1668 'position' => 'left',
1670 'file' => 'user.admin.inc',
1672 $items['admin/people/people'] = array(
1674 'description' => 'Find and manage people interacting with your site.',
1675 'access arguments' => array('administer users'),
1676 'type' => MENU_DEFAULT_LOCAL_TASK
,
1678 'file' => 'user.admin.inc',
1681 // Permissions and role forms.
1682 $items['admin/people/permissions'] = array(
1683 'title' => 'Permissions',
1684 'description' => 'Determine access to features by selecting permissions for roles.',
1685 'page callback' => 'drupal_get_form',
1686 'page arguments' => array('user_admin_permissions'),
1687 'access arguments' => array('administer permissions'),
1688 'file' => 'user.admin.inc',
1689 'type' => MENU_LOCAL_TASK
,
1691 $items['admin/people/permissions/list'] = array(
1692 'title' => 'Permissions',
1693 'description' => 'Determine access to features by selecting permissions for roles.',
1694 'type' => MENU_DEFAULT_LOCAL_TASK
,
1697 $items['admin/people/permissions/roles'] = array(
1699 'description' => 'List, edit, or add user roles.',
1700 'page callback' => 'drupal_get_form',
1701 'page arguments' => array('user_admin_roles'),
1702 'access arguments' => array('administer permissions'),
1703 'file' => 'user.admin.inc',
1704 'type' => MENU_LOCAL_TASK
,
1707 $items['admin/people/permissions/roles/edit/%user_role'] = array(
1708 'title' => 'Edit role',
1709 'page arguments' => array('user_admin_role', 5),
1710 'access callback' => 'user_role_edit_access',
1711 'access arguments' => array(5),
1713 $items['admin/people/permissions/roles/delete/%user_role'] = array(
1714 'title' => 'Delete role',
1715 'page callback' => 'drupal_get_form',
1716 'page arguments' => array('user_admin_role_delete_confirm', 5),
1717 'access callback' => 'user_role_edit_access',
1718 'access arguments' => array(5),
1719 'file' => 'user.admin.inc',
1722 $items['admin/people/create'] = array(
1723 'title' => 'Add user',
1724 'page arguments' => array('create'),
1725 'access arguments' => array('administer users'),
1726 'type' => MENU_LOCAL_ACTION
,
1729 // Administration pages.
1730 $items['admin/config/people'] = array(
1731 'title' => 'People',
1732 'description' => 'Configure user accounts.',
1733 'position' => 'left',
1735 'page callback' => 'system_admin_menu_block_page',
1736 'access arguments' => array('access administration pages'),
1737 'file' => 'system.admin.inc',
1738 'file path' => drupal_get_path('module', 'system'),
1740 $items['admin/config/people/accounts'] = array(
1741 'title' => 'Account settings',
1742 'description' => 'Configure default behavior of users, including registration requirements, e-mails, fields, and user pictures.',
1743 'page callback' => 'drupal_get_form',
1744 'page arguments' => array('user_admin_settings'),
1745 'access arguments' => array('administer users'),
1746 'file' => 'user.admin.inc',
1749 $items['admin/config/people/accounts/settings'] = array(
1750 'title' => 'Settings',
1751 'type' => MENU_DEFAULT_LOCAL_TASK
,
1755 $items['user/%user'] = array(
1756 'title' => 'My account',
1757 'title callback' => 'user_page_title',
1758 'title arguments' => array(1),
1759 'page callback' => 'user_view_page',
1760 'page arguments' => array(1),
1761 'access callback' => 'user_view_access',
1762 'access arguments' => array(1),
1763 // By assigning a different menu name, this item (and all registered child
1764 // paths) are no longer considered as children of 'user'. When accessing the
1765 // user account pages, the preferred menu link that is used to build the
1766 // active trail (breadcrumb) will be found in this menu (unless there is
1767 // more specific link), so the link to 'user' will not be in the breadcrumb.
1768 'menu_name' => 'navigation',
1771 $items['user/%user/view'] = array(
1773 'type' => MENU_DEFAULT_LOCAL_TASK
,
1777 $items['user/%user/cancel'] = array(
1778 'title' => 'Cancel account',
1779 'page callback' => 'drupal_get_form',
1780 'page arguments' => array('user_cancel_confirm_form', 1),
1781 'access callback' => 'user_cancel_access',
1782 'access arguments' => array(1),
1783 'file' => 'user.pages.inc',
1786 $items['user/%user/cancel/confirm/%/%'] = array(
1787 'title' => 'Confirm account cancellation',
1788 'page callback' => 'user_cancel_confirm',
1789 'page arguments' => array(1, 4, 5),
1790 'access callback' => 'user_cancel_access',
1791 'access arguments' => array(1),
1792 'file' => 'user.pages.inc',
1795 $items['user/%user/edit'] = array(
1797 'page callback' => 'drupal_get_form',
1798 'page arguments' => array('user_profile_form', 1),
1799 'access callback' => 'user_edit_access',
1800 'access arguments' => array(1),
1801 'type' => MENU_LOCAL_TASK
,
1802 'file' => 'user.pages.inc',
1805 $items['user/%user_category/edit/account'] = array(
1806 'title' => 'Account',
1807 'type' => MENU_DEFAULT_LOCAL_TASK
,
1808 'load arguments' => array('%map', '%index'),
1811 if (($categories = _user_categories()) && (count($categories) > 1)) {
1812 foreach ($categories as
$key => $category) {
1813 // 'account' is already handled by the MENU_DEFAULT_LOCAL_TASK.
1814 if ($category['name'] != 'account') {
1815 $items['user/%user_category/edit/' .
$category['name']] = array(
1816 'title callback' => 'check_plain',
1817 'title arguments' => array($category['title']),
1818 'page callback' => 'drupal_get_form',
1819 'page arguments' => array('user_profile_form', 1, 3),
1820 'access callback' => isset($category['access callback']) ?
$category['access callback'] : 'user_edit_access',
1821 'access arguments' => isset($category['access arguments']) ?
$category['access arguments'] : array(1),
1822 'type' => MENU_LOCAL_TASK
,
1823 'weight' => $category['weight'],
1824 'load arguments' => array('%map', '%index'),
1825 'tab_parent' => 'user/%/edit',
1826 'file' => 'user.pages.inc',
1835 * Implements hook_menu_site_status_alter().
1837 function user_menu_site_status_alter(&$menu_site_status, $path) {
1838 if ($menu_site_status == MENU_SITE_OFFLINE
) {
1839 // If the site is offline, log out unprivileged users.
1840 if (user_is_logged_in() && !user_access('access site in maintenance mode')) {
1841 module_load_include('pages.inc', 'user', 'user');
1845 if (user_is_anonymous()) {
1848 // Forward anonymous user to login page.
1849 drupal_goto('user/login');
1851 case
'user/password':
1852 // Disable offline mode.
1853 $menu_site_status = MENU_SITE_ONLINE
;
1856 if (strpos($path, 'user/reset/') === 0) {
1857 // Disable offline mode.
1858 $menu_site_status = MENU_SITE_ONLINE
;
1864 if (user_is_logged_in()) {
1865 if ($path == 'user/login') {
1866 // If user is logged in, redirect to 'user' instead of giving 403.
1867 drupal_goto('user');
1869 if ($path == 'user/register') {
1870 // Authenticated user should be redirected to user edit page.
1871 drupal_goto('user/' .
$GLOBALS['user']->uid .
'/edit');
1877 * Implements hook_menu_link_alter().
1879 function user_menu_link_alter(&$link) {
1880 // The path 'user' must be accessible for anonymous users, but only visible
1881 // for authenticated users. Authenticated users should see "My account", but
1882 // anonymous users should not see it at all. Therefore, invoke
1883 // user_translated_menu_link_alter() to conditionally hide the link.
1884 if ($link['link_path'] == 'user' && $link['module'] == 'system') {
1885 $link['options']['alter'] = TRUE
;
1888 // Force the Logout link to appear on the top-level of 'user-menu' menu by
1889 // default (i.e., unless it has been customized).
1890 if ($link['link_path'] == 'user/logout' && $link['module'] == 'system' && empty($link['customized'])) {
1896 * Implements hook_translated_menu_link_alter().
1898 function user_translated_menu_link_alter(&$link) {
1899 // Hide the "User account" link for anonymous users.
1900 if ($link['link_path'] == 'user' && $link['module'] == 'system' && !$GLOBALS['user']->uid
) {
1901 $link['hidden'] = 1;
1906 * Implements hook_admin_paths().
1908 function user_admin_paths() {
1910 'user/*/cancel' => TRUE
,
1911 'user/*/edit' => TRUE
,
1912 'user/*/edit/*' => TRUE
,
1918 * Returns $arg or the user ID of the current user if $arg is '%' or empty.
1920 * Deprecated. Use %user_uid_optional instead.
1924 function user_uid_only_optional_to_arg($arg) {
1925 return user_uid_optional_to_arg($arg);
1929 * Load either a specified or the current user account.
1932 * An optional user ID of the user to load. If not provided, the current
1933 * user's ID will be used.
1935 * A fully-loaded $user object upon successful user load, FALSE if user
1939 * @todo rethink the naming of this in Drupal 8.
1941 function user_uid_optional_load($uid = NULL
) {
1943 $uid = $GLOBALS['user']->uid
;
1945 return user_load($uid);
1949 * Return a user object after checking if any profile category in the path exists.
1951 function user_category_load($uid, &$map, $index) {
1952 static
$user_categories, $accounts;
1954 // Cache $account - this load function will get called for each profile tab.
1955 if (!isset($accounts[$uid])) {
1956 $accounts[$uid] = user_load($uid);
1959 if ($account = $accounts[$uid]) {
1960 // Since the path is like user/%/edit/category_name, the category name will
1961 // be at a position 2 beyond the index corresponding to the % wildcard.
1962 $category_index = $index + 2;
1963 // Valid categories may contain slashes, and hence need to be imploded.
1964 $category_path = implode('/', array_slice($map, $category_index));
1965 if ($category_path) {
1966 // Check that the requested category exists.
1968 if (!isset($user_categories)) {
1969 $user_categories = _user_categories();
1971 foreach ($user_categories as
$category) {
1972 if ($category['name'] == $category_path) {
1974 // Truncate the map array in case the category name had slashes.
1975 $map = array_slice($map, 0, $category_index);
1976 // Assign the imploded category name to the last map element.
1977 $map[$category_index] = $category_path;
1983 return $valid ?
$account : FALSE
;
1987 * Returns $arg or the user ID of the current user if $arg is '%' or empty.
1989 * @todo rethink the naming of this in Drupal 8.
1991 function user_uid_optional_to_arg($arg) {
1992 // Give back the current user uid when called from eg. tracker, aka.
1993 // with an empty arg. Also use the current user uid when called from
1994 // the menu with a % for the current account link.
1995 return empty($arg) || $arg == '%' ?
$GLOBALS['user']->uid
: $arg;
1999 * Menu item title callback for the 'user' path.
2001 * Anonymous users should see "User account", but authenticated users are
2002 * expected to see "My account".
2004 function user_menu_title() {
2005 return user_is_logged_in() ?
t('My account') : t('User account');
2009 * Menu item title callback - use the user name.
2011 function user_page_title($account) {
2012 return is_object($account) ?
format_username($account) : '';
2016 * Discover which external authentication module(s) authenticated a username.
2019 * A username used by an external authentication module.
2021 * An associative array with module as key and username as value.
2023 function user_get_authmaps($authname = NULL
) {
2024 $authmaps = db_query("SELECT module, authname FROM {authmap} WHERE authname = :authname", array(':authname' => $authname))->fetchAllKeyed();
2025 return count($authmaps) ?
$authmaps : 0;
2029 * Save mappings of which external authentication module(s) authenticated
2030 * a user. Maps external usernames to user ids in the users table.
2035 * An associative array with a compound key and the username as the value.
2036 * The key is made up of 'authname_' plus the name of the external authentication
2038 * @see user_external_login_register()
2040 function user_set_authmaps($account, $authmaps) {
2041 foreach ($authmaps as
$key => $value) {
2042 $module = explode('_', $key, 2);
2046 'uid' => $account->uid
,
2047 'module' => $module[1],
2049 ->fields(array('authname' => $value))
2053 db_delete('authmap')
2054 ->condition('uid', $account->uid
)
2055 ->condition('module', $module[1])
2062 * Form builder; the main user login form.
2066 function user_login($form, &$form_state) {
2069 // If we are already logged on, go to the user page instead.
2071 drupal_goto('user/' .
$user->uid
);
2074 // Display login form:
2075 $form['name'] = array('#type' => 'textfield',
2076 '#title' => t('Username'),
2078 '#maxlength' => USERNAME_MAX_LENGTH
,
2079 '#required' => TRUE
,
2082 $form['name']['#description'] = t('Enter your @s username.', array('@s' => variable_get('site_name', 'Drupal')));
2083 $form['pass'] = array('#type' => 'password',
2084 '#title' => t('Password'),
2085 '#description' => t('Enter the password that accompanies your username.'),
2086 '#required' => TRUE
,
2088 $form['#validate'] = user_login_default_validators();
2089 $form['actions'] = array('#type' => 'actions');
2090 $form['actions']['submit'] = array('#type' => 'submit', '#value' => t('Log in'));
2096 * Set up a series for validators which check for blocked users,
2097 * then authenticate against local database, then return an error if
2098 * authentication fails. Distributed authentication modules are welcome
2099 * to use hook_form_alter() to change this series in order to
2100 * authenticate against their user database instead of the local users
2101 * table. If a distributed authentication module is successful, it
2102 * should set $form_state['uid'] to a user ID.
2104 * We use three validators instead of one since external authentication
2105 * modules usually only need to alter the second validator.
2107 * @see user_login_name_validate()
2108 * @see user_login_authenticate_validate()
2109 * @see user_login_final_validate()
2111 * A simple list of validate functions.
2113 function user_login_default_validators() {
2114 return array('user_login_name_validate', 'user_login_authenticate_validate', 'user_login_final_validate');
2118 * A FAPI validate handler. Sets an error if supplied username has been blocked.
2120 function user_login_name_validate($form, &$form_state) {
2121 if (isset($form_state['values']['name']) && user_is_blocked($form_state['values']['name'])) {
2122 // Blocked in user administration.
2123 form_set_error('name', t('The username %name has not been activated or is blocked.', array('%name' => $form_state['values']['name'])));
2128 * A validate handler on the login form. Check supplied username/password
2129 * against local users table. If successful, $form_state['uid']
2130 * is set to the matching user ID.
2132 function user_login_authenticate_validate($form, &$form_state) {
2133 $password = trim($form_state['values']['pass']);
2134 if (!empty($form_state['values']['name']) && !empty($password)) {
2135 // Do not allow any login from the current user's IP if the limit has been
2136 // reached. Default is 50 failed attempts allowed in one hour. This is
2137 // independent of the per-user limit to catch attempts from one IP to log
2138 // in to many different user accounts. We have a reasonably high limit
2139 // since there may be only one apparent IP for all users at an institution.
2140 if (!flood_is_allowed('failed_login_attempt_ip', variable_get('user_failed_login_ip_limit', 50), variable_get('user_failed_login_ip_window', 3600))) {
2141 $form_state['flood_control_triggered'] = 'ip';
2144 $account = db_query("SELECT * FROM {users} WHERE name = :name AND status = 1", array(':name' => $form_state['values']['name']))->fetchObject();
2146 if (variable_get('user_failed_login_identifier_uid_only', FALSE
)) {
2147 // Register flood events based on the uid only, so they apply for any
2148 // IP address. This is the most secure option.
2149 $identifier = $account->uid
;
2152 // The default identifier is a combination of uid and IP address. This
2153 // is less secure but more resistant to denial-of-service attacks that
2154 // could lock out all users with public user names.
2155 $identifier = $account->uid .
'-' .
ip_address();
2157 $form_state['flood_control_user_identifier'] = $identifier;
2159 // Don't allow login if the limit for this user has been reached.
2160 // Default is to allow 5 failed attempts every 6 hours.
2161 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)) {
2162 $form_state['flood_control_triggered'] = 'user';
2166 // We are not limited by flood control, so try to authenticate.
2167 // Set $form_state['uid'] as a flag for user_login_final_validate().
2168 $form_state['uid'] = user_authenticate($form_state['values']['name'], $password);
2173 * The final validation handler on the login form.
2175 * Sets a form error if user has not been authenticated, or if too many
2176 * logins have been attempted. This validation function should always
2179 function user_login_final_validate($form, &$form_state) {
2180 if (empty($form_state['uid'])) {
2181 // Always register an IP-based failed login event.
2182 flood_register_event('failed_login_attempt_ip', variable_get('user_failed_login_ip_window', 3600));
2183 // Register a per-user failed login event.
2184 if (isset($form_state['flood_control_user_identifier'])) {
2185 flood_register_event('failed_login_attempt_user', variable_get('user_failed_login_user_window', 21600), $form_state['flood_control_user_identifier']);
2188 if (isset($form_state['flood_control_triggered'])) {
2189 if ($form_state['flood_control_triggered'] == 'user') {
2190 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'))));
2193 // We did not find a uid, so the limit is IP-based.
2194 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'))));
2198 form_set_error('name', t('Sorry, unrecognized username or password. <a href="@password">Have you forgotten your password?</a>', array('@password' => url('user/password'))));
2199 watchdog('user', 'Login attempt failed for %user.', array('%user' => $form_state['values']['name']));
2202 elseif (isset($form_state['flood_control_user_identifier'])) {
2203 // Clear past failures for this user so as not to block a user who might
2204 // log in and out more than once in an hour.
2205 flood_clear_event('failed_login_attempt_user', $form_state['flood_control_user_identifier']);
2210 * Try to validate the user's login credentials locally.
2213 * User name to authenticate.
2215 * A plain-text password, such as trimmed text from form values.
2217 * The user's uid on success, or FALSE on failure to authenticate.
2219 function user_authenticate($name, $password) {
2221 if (!empty($name) && !empty($password)) {
2222 $account = user_load_by_name($name);
2224 // Allow alternate password hashing schemes.
2225 require_once DRUPAL_ROOT .
'/' .
variable_get('password_inc', 'includes/password.inc');
2226 if (user_check_password($password, $account)) {
2227 // Successful authentication.
2228 $uid = $account->uid
;
2230 // Update user to new password scheme if needed.
2231 if (user_needs_new_hash($account)) {
2232 user_save($account, array('pass' => $password));
2241 * Finalize the login process. Must be called when logging in a user.
2243 * The function records a watchdog message about the new session, saves the
2244 * login timestamp, calls hook_user_login(), and generates a new session.
2246 * @param array $edit
2247 * The array of form values submitted by the user.
2249 * @see hook_user_login()
2251 function user_login_finalize(&$edit = array()) {
2253 watchdog('user', 'Session opened for %name.', array('%name' => $user->name
));
2254 // Update the user table timestamp noting user has logged in.
2255 // This is also used to invalidate one-time login links.
2256 $user->login
= REQUEST_TIME
;
2258 ->fields(array('login' => $user->login
))
2259 ->condition('uid', $user->uid
)
2262 // Regenerate the session ID to prevent against session fixation attacks.
2263 // This is called before hook_user in case one of those functions fails
2264 // or incorrectly does a redirect which would leave the old session in place.
2265 drupal_session_regenerate();
2267 user_module_invoke('login', $edit, $user);
2271 * Submit handler for the login form. Load $user object and perform standard login
2272 * tasks. The user is then redirected to the My Account page. Setting the
2273 * destination in the query string overrides the redirect.
2275 function user_login_submit($form, &$form_state) {
2277 $user = user_load($form_state['uid']);
2278 $form_state['redirect'] = 'user/' .
$user->uid
;
2280 user_login_finalize($form_state);
2284 * Helper function for authentication modules. Either logs in or registers
2285 * the current user, based on username. Either way, the global $user object is
2286 * populated and login tasks are performed.
2288 function user_external_login_register($name, $module) {
2289 $account = user_external_load($name);
2291 // Register this new user.
2294 'pass' => user_password(),
2297 'access' => REQUEST_TIME
2299 $account = user_save(drupal_anonymous_user(), $userinfo);
2300 // Terminate if an error occurred during user_save().
2302 drupal_set_message(t("Error saving user account."), 'error');
2305 user_set_authmaps($account, array("authname_$module" => $name));
2309 $form_state['uid'] = $account->uid
;
2310 user_login_submit(array(), $form_state);
2314 * Generates a unique URL for a user to login and reset their password.
2316 * @param object $account
2317 * An object containing the user account.
2320 * A unique URL that provides a one-time log in for the user, from which
2321 * they can change their password.
2323 function user_pass_reset_url($account) {
2324 $timestamp = REQUEST_TIME
;
2325 return url("user/reset/$account->uid/$timestamp/" .
user_pass_rehash($account->pass
, $timestamp, $account->login
), array('absolute' => TRUE
));
2329 * Generates a URL to confirm an account cancellation request.
2331 * @param object $account
2332 * The user account object, which must contain at least the following
2334 * - uid: The user uid number.
2335 * - pass: The hashed user password string.
2336 * - login: The user login name.
2339 * A unique URL that may be used to confirm the cancellation of the user
2342 * @see user_mail_tokens()
2343 * @see user_cancel_confirm()
2345 function user_cancel_url($account) {
2346 $timestamp = REQUEST_TIME
;
2347 return url("user/$account->uid/cancel/confirm/$timestamp/" .
user_pass_rehash($account->pass
, $timestamp, $account->login
), array('absolute' => TRUE
));
2351 * Creates a unique hash value for use in time-dependent per-user URLs.
2353 * This hash is normally used to build a unique and secure URL that is sent to
2354 * the user by email for purposes such as resetting the user's password. In
2355 * order to validate the URL, the same hash can be generated again, from the
2356 * same information, and compared to the hash value from the URL. The URL
2357 * normally contains both the time stamp and the numeric user ID. The login
2358 * name and hashed password are retrieved from the database as necessary. For a
2359 * usage example, see user_cancel_url() and user_cancel_confirm().
2362 * The hashed user account password value.
2366 * The user account login name.
2369 * A string that is safe for use in URLs and SQL statements.
2371 function user_pass_rehash($password, $timestamp, $login) {
2372 return drupal_hmac_base64($timestamp .
$login, drupal_get_hash_salt() .
$password);
2376 * Cancel a user account.
2378 * Since the user cancellation process needs to be run in a batch, either
2379 * Form API will invoke it, or batch_process() needs to be invoked after calling
2380 * this function and should define the path to redirect to.
2383 * An array of submitted form values.
2385 * The user ID of the user account to cancel.
2387 * The account cancellation method to use.
2389 * @see _user_cancel()
2391 function user_cancel($edit, $uid, $method) {
2394 $account = user_load($uid);
2397 drupal_set_message(t('The user account %id does not exist.', array('%id' => $uid)), 'error');
2398 watchdog('user', 'Attempted to cancel non-existing user account: %id.', array('%id' => $uid), WATCHDOG_ERROR
);
2402 // Initialize batch (to set title).
2404 'title' => t('Cancelling account'),
2405 'operations' => array(),
2409 // Modules use hook_user_delete() to respond to deletion.
2410 if ($method != 'user_cancel_delete') {
2411 // Allow modules to add further sets to this batch.
2412 module_invoke_all('user_cancel', $edit, $account, $method);
2415 // Finish the batch and actually cancel the account.
2417 'title' => t('Cancelling user account'),
2418 'operations' => array(
2419 array('_user_cancel', array($edit, $account, $method)),
2424 // Batch processing is either handled via Form API or has to be invoked
2429 * Last batch processing step for cancelling a user account.
2431 * Since batch and session API require a valid user account, the actual
2432 * cancellation of a user account needs to happen last.
2434 * @see user_cancel()
2436 function _user_cancel($edit, $account, $method) {
2440 case
'user_cancel_block':
2441 case
'user_cancel_block_unpublish':
2443 // Send account blocked notification if option was checked.
2444 if (!empty($edit['user_cancel_notify'])) {
2445 _user_mail_notify('status_blocked', $account);
2447 user_save($account, array('status' => 0));
2448 drupal_set_message(t('%name has been disabled.', array('%name' => $account->name
)));
2449 watchdog('user', 'Blocked user: %name %email.', array('%name' => $account->name
, '%email' => '<' .
$account->mail .
'>'), WATCHDOG_NOTICE
);
2452 case
'user_cancel_reassign':
2453 case
'user_cancel_delete':
2454 // Send account canceled notification if option was checked.
2455 if (!empty($edit['user_cancel_notify'])) {
2456 _user_mail_notify('status_canceled', $account);
2458 user_delete($account->uid
);
2459 drupal_set_message(t('%name has been deleted.', array('%name' => $account->name
)));
2460 watchdog('user', 'Deleted user: %name %email.', array('%name' => $account->name
, '%email' => '<' .
$account->mail .
'>'), WATCHDOG_NOTICE
);
2464 // After cancelling account, ensure that user is logged out.
2465 if ($account->uid
== $user->uid
) {
2466 // Destroy the current session, and reset $user to the anonymous user.
2470 // Clear the cache for anonymous users.
2480 function user_delete($uid) {
2481 user_delete_multiple(array($uid));
2485 * Delete multiple user accounts.
2488 * An array of user IDs.
2490 function user_delete_multiple(array $uids) {
2491 if (!empty($uids)) {
2492 $accounts = user_load_multiple($uids, array());
2494 $transaction = db_transaction();
2496 foreach ($accounts as
$uid => $account) {
2497 module_invoke_all('user_delete', $account);
2498 module_invoke_all('entity_delete', $account, 'user');
2499 field_attach_delete('user', $account);
2500 drupal_session_destroy_uid($account->uid
);
2504 ->condition('uid', $uids, 'IN')
2506 db_delete('users_roles')
2507 ->condition('uid', $uids, 'IN')
2509 db_delete('authmap')
2510 ->condition('uid', $uids, 'IN')
2513 catch (Exception
$e) {
2514 $transaction->rollback();
2515 watchdog_exception('user', $e);
2518 entity_get_controller('user')->resetCache();
2523 * Page callback wrapper for user_view().
2525 function user_view_page($account) {
2526 // An administrator may try to view a non-existent account,
2527 // so we give them a 404 (versus a 403 for non-admins).
2528 return is_object($account) ?
user_view($account) : MENU_NOT_FOUND
;
2532 * Generate an array for rendering the given user.
2534 * When viewing a user profile, the $page array contains:
2536 * - $page['content']['Profile Category']:
2537 * Profile categories keyed by their human-readable names.
2538 * - $page['content']['Profile Category']['profile_machine_name']:
2539 * Profile fields keyed by their machine-readable names.
2540 * - $page['content']['user_picture']:
2541 * User's rendered picture.
2542 * - $page['content']['summary']:
2543 * Contains the default "History" profile data for a user.
2544 * - $page['content']['#account']:
2545 * The user account of the profile being viewed.
2547 * To theme user profiles, copy modules/user/user-profile.tpl.php
2548 * to your theme directory, and edit it as instructed in that file's comments.
2553 * View mode, e.g. 'full'.
2555 * (optional) A language code to use for rendering. Defaults to the global
2556 * content language of the current request.
2559 * An array as expected by drupal_render().
2561 function user_view($account, $view_mode = 'full', $langcode = NULL
) {
2562 if (!isset($langcode)) {
2563 $langcode = $GLOBALS['language_content']->language
;
2566 // Retrieve all profile fields and attach to $account->content.
2567 user_build_content($account, $view_mode, $langcode);
2569 $build = $account->content
;
2570 // We don't need duplicate rendering info in account->content.
2571 unset($account->content
);
2574 '#theme' => 'user_profile',
2575 '#account' => $account,
2576 '#view_mode' => $view_mode,
2577 '#language' => $langcode,
2580 // Allow modules to modify the structured user.
2582 drupal_alter(array('user_view', 'entity_view'), $build, $type);
2588 * Builds a structured array representing the profile content.
2593 * View mode, e.g. 'full'.
2595 * (optional) A language code to use for rendering. Defaults to the global
2596 * content language of the current request.
2598 function user_build_content($account, $view_mode = 'full', $langcode = NULL
) {
2599 if (!isset($langcode)) {
2600 $langcode = $GLOBALS['language_content']->language
;
2603 // Remove previously built content, if exists.
2604 $account->content
= array();
2606 // Allow modules to change the view mode.
2608 'entity_type' => 'user',
2609 'entity' => $account,
2610 'langcode' => $langcode,
2612 drupal_alter('entity_view_mode', $view_mode, $context);
2614 // Build fields content.
2615 field_attach_prepare_view('user', array($account->uid
=> $account), $view_mode, $langcode);
2616 entity_prepare_view('user', array($account->uid
=> $account), $langcode);
2617 $account->content
+= field_attach_view('user', $account, $view_mode, $langcode);
2619 // Populate $account->content with a render() array.
2620 module_invoke_all('user_view', $account, $view_mode, $langcode);
2621 module_invoke_all('entity_view', $account, 'user', $view_mode, $langcode);
2623 // Make sure the current view mode is stored if no module has already
2624 // populated the related key.
2625 $account->content
+= array('#view_mode' => $view_mode);
2629 * Implements hook_mail().
2631 function user_mail($key, &$message, $params) {
2632 $language = $message['language'];
2633 $variables = array('user' => $params['account']);
2634 $message['subject'] .
= _user_mail_text($key .
'_subject', $language, $variables);
2635 $message['body'][] = _user_mail_text($key .
'_body', $language, $variables);
2639 * Returns a mail string for a variable name.
2641 * Used by user_mail() and the settings forms to retrieve strings.
2643 function _user_mail_text($key, $language = NULL
, $variables = array(), $replace = TRUE
) {
2644 $langcode = isset($language) ?
$language->language
: NULL
;
2646 if ($admin_setting = variable_get('user_mail_' .
$key, FALSE
)) {
2647 // An admin setting overrides the default string.
2648 $text = $admin_setting;
2651 // No override, return default string.
2653 case
'register_no_approval_required_subject':
2654 $text = t('Account details for [user:name] at [site:name]', array(), array('langcode' => $langcode));
2656 case
'register_no_approval_required_body':
2657 $text = t("[user:name],
2659 Thank you for registering at [site:name]. You may now log in by clicking this link or copying and pasting it to your browser:
2661 [user:one-time-login-url]
2663 This link can only be used once to log in and will lead you to a page where you can set your password.
2665 After setting your password, you will be able to log in at [site:login-url] in the future using:
2667 username: [user:name]
2668 password: Your password
2670 -- [site:name] team", array(), array('langcode' => $langcode));
2673 case
'register_admin_created_subject':
2674 $text = t('An administrator created an account for you at [site:name]', array(), array('langcode' => $langcode));
2676 case
'register_admin_created_body':
2677 $text = t("[user:name],
2679 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:
2681 [user:one-time-login-url]
2683 This link can only be used once to log in and will lead you to a page where you can set your password.
2685 After setting your password, you will be able to log in at [site:login-url] in the future using:
2687 username: [user:name]
2688 password: Your password
2690 -- [site:name] team", array(), array('langcode' => $langcode));
2693 case
'register_pending_approval_subject':
2694 case
'register_pending_approval_admin_subject':
2695 $text = t('Account details for [user:name] at [site:name] (pending admin approval)', array(), array('langcode' => $langcode));
2697 case
'register_pending_approval_body':
2698 $text = t("[user:name],
2700 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.
2703 -- [site:name] team", array(), array('langcode' => $langcode));
2705 case
'register_pending_approval_admin_body':
2706 $text = t("[user:name] has applied for an account.
2708 [user:edit-url]", array(), array('langcode' => $langcode));
2711 case
'password_reset_subject':
2712 $text = t('Replacement login information for [user:name] at [site:name]', array(), array('langcode' => $langcode));
2714 case
'password_reset_body':
2715 $text = t("[user:name],
2717 A request to reset the password for your account has been made at [site:name].
2719 You may now log in by clicking this link or copying and pasting it to your browser:
2721 [user:one-time-login-url]
2723 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.
2725 -- [site:name] team", array(), array('langcode' => $langcode));
2728 case
'status_activated_subject':
2729 $text = t('Account details for [user:name] at [site:name] (approved)', array(), array('langcode' => $langcode));
2731 case
'status_activated_body':
2732 $text = t("[user:name],
2734 Your account at [site:name] has been activated.
2736 You may now log in by clicking this link or copying and pasting it into your browser:
2738 [user:one-time-login-url]
2740 This link can only be used once to log in and will lead you to a page where you can set your password.
2742 After setting your password, you will be able to log in at [site:login-url] in the future using:
2744 username: [user:name]
2745 password: Your password
2747 -- [site:name] team", array(), array('langcode' => $langcode));
2750 case
'status_blocked_subject':
2751 $text = t('Account details for [user:name] at [site:name] (blocked)', array(), array('langcode' => $langcode));
2753 case
'status_blocked_body':
2754 $text = t("[user:name],
2756 Your account on [site:name] has been blocked.
2758 -- [site:name] team", array(), array('langcode' => $langcode));
2761 case
'cancel_confirm_subject':
2762 $text = t('Account cancellation request for [user:name] at [site:name]', array(), array('langcode' => $langcode));
2764 case
'cancel_confirm_body':
2765 $text = t("[user:name],
2767 A request to cancel your account has been made at [site:name].
2769 You may now cancel your account on [site:url-brief] by clicking this link or copying and pasting it into your browser:
2773 NOTE: The cancellation of your account is not reversible.
2775 This link expires in one day and nothing will happen if it is not used.
2777 -- [site:name] team", array(), array('langcode' => $langcode));
2780 case
'status_canceled_subject':
2781 $text = t('Account details for [user:name] at [site:name] (canceled)', array(), array('langcode' => $langcode));
2783 case
'status_canceled_body':
2784 $text = t("[user:name],
2786 Your account on [site:name] has been canceled.
2788 -- [site:name] team", array(), array('langcode' => $langcode));
2794 // We do not sanitize the token replacement, since the output of this
2795 // replacement is intended for an e-mail message, not a web browser.
2796 return token_replace($text, $variables, array('language' => $language, 'callback' => 'user_mail_tokens', 'sanitize' => FALSE
, 'clear' => TRUE
));
2803 * Token callback to add unsafe tokens for user mails.
2805 * This function is used by the token_replace() call at the end of
2806 * _user_mail_text() to set up some additional tokens that can be
2807 * used in email messages generated by user_mail().
2809 * @param $replacements
2810 * An associative array variable containing mappings from token names to
2811 * values (for use with strtr()).
2813 * An associative array of token replacement values. If the 'user' element
2814 * exists, it must contain a user account object with the following
2816 * - login: The account login name.
2817 * - pass: The hashed account login password.
2819 * Unused parameter required by the token_replace() function.
2821 function user_mail_tokens(&$replacements, $data, $options) {
2822 if (isset($data['user'])) {
2823 $replacements['[user:one-time-login-url]'] = user_pass_reset_url($data['user']);
2824 $replacements['[user:cancel-url]'] = user_cancel_url($data['user']);
2828 /*** Administrative features ***********************************************/
2831 * Retrieve an array of roles matching specified conditions.
2833 * @param $membersonly
2834 * Set this to TRUE to exclude the 'anonymous' role.
2835 * @param $permission
2836 * A string containing a permission. If set, only roles containing that
2837 * permission are returned.
2840 * An associative array with the role id as the key and the role name as
2843 function user_roles($membersonly = FALSE
, $permission = NULL
) {
2844 $query = db_select('role', 'r');
2845 $query->addTag('translatable');
2846 $query->fields('r', array('rid', 'name'));
2847 $query->orderBy('weight');
2848 $query->orderBy('name');
2849 if (!empty($permission)) {
2850 $query->innerJoin('role_permission', 'p', 'r.rid = p.rid');
2851 $query->condition('p.permission', $permission);
2853 $result = $query->execute();
2856 foreach ($result as
$role) {
2857 switch ($role->rid
) {
2858 // We only translate the built in role names
2859 case DRUPAL_ANONYMOUS_RID
:
2860 if (!$membersonly) {
2861 $roles[$role->rid
] = t($role->name
);
2864 case DRUPAL_AUTHENTICATED_RID
:
2865 $roles[$role->rid
] = t($role->name
);
2868 $roles[$role->rid
] = $role->name
;
2876 * Fetches a user role by role ID.
2879 * An integer representing the role ID.
2882 * A fully-loaded role object if a role with the given ID exists, or FALSE
2885 * @see user_role_load_by_name()
2887 function user_role_load($rid) {
2888 return db_select('role', 'r')
2890 ->condition('rid', $rid)
2896 * Fetches a user role by role name.
2899 * A string representing the role name.
2902 * A fully-loaded role object if a role with the given name exists, or FALSE
2905 * @see user_role_load()
2907 function user_role_load_by_name($role_name) {
2908 return db_select('role', 'r')
2910 ->condition('name', $role_name)
2916 * Save a user role to the database.
2919 * A role object to modify or add. If $role->rid is not specified, a new
2920 * role will be created.
2922 * Status constant indicating if role was created or updated.
2923 * Failure to write the user role record will return FALSE. Otherwise.
2924 * SAVED_NEW or SAVED_UPDATED is returned depending on the operation
2927 function user_role_save($role) {
2929 // Prevent leading and trailing spaces in role names.
2930 $role->name
= trim($role->name
);
2932 if (!isset($role->weight
)) {
2933 // Set a role weight to make this new role last.
2934 $query = db_select('role');
2935 $query->addExpression('MAX(weight)');
2936 $role->weight
= $query->execute()->fetchField() + 1;
2939 // Let modules modify the user role before it is saved to the database.
2940 module_invoke_all('user_role_presave', $role);
2942 if (!empty($role->rid
) && $role->name
) {
2943 $status = drupal_write_record('role', $role, 'rid');
2944 module_invoke_all('user_role_update', $role);
2947 $status = drupal_write_record('role', $role);
2948 module_invoke_all('user_role_insert', $role);
2951 // Clear the user access cache.
2952 drupal_static_reset('user_access');
2953 drupal_static_reset('user_role_permissions');
2959 * Delete a user role from database.
2962 * A string with the role name, or an integer with the role ID.
2964 function user_role_delete($role) {
2965 if (is_int($role)) {
2966 $role = user_role_load($role);
2969 $role = user_role_load_by_name($role);
2973 ->condition('rid', $role->rid
)
2975 db_delete('role_permission')
2976 ->condition('rid', $role->rid
)
2978 // Update the users who have this role set:
2979 db_delete('users_roles')
2980 ->condition('rid', $role->rid
)
2983 module_invoke_all('user_role_delete', $role);
2985 // Clear the user access cache.
2986 drupal_static_reset('user_access');
2987 drupal_static_reset('user_role_permissions');
2991 * Menu access callback for user role editing.
2993 function user_role_edit_access($role) {
2994 // Prevent the system-defined roles from being altered or removed.
2995 if ($role->rid
== DRUPAL_ANONYMOUS_RID
|| $role->rid
== DRUPAL_AUTHENTICATED_RID
) {
2999 return user_access('administer permissions');
3003 * Determine the modules that permissions belong to.
3006 * An associative array in the format $permission => $module.
3008 function user_permission_get_modules() {
3009 $permissions = array();
3010 foreach (module_implements('permission') as
$module) {
3011 $perms = module_invoke($module, 'permission');
3012 foreach ($perms as
$key => $value) {
3013 $permissions[$key] = $module;
3016 return $permissions;
3020 * Change permissions for a user role.
3022 * This function may be used to grant and revoke multiple permissions at once.
3023 * For example, when a form exposes checkboxes to configure permissions for a
3024 * role, the form submit handler may directly pass the submitted values for the
3025 * checkboxes form element to this function.
3028 * The ID of a user role to alter.
3029 * @param $permissions
3030 * An associative array, where the key holds the permission name and the value
3031 * determines whether to grant or revoke that permission. Any value that
3032 * evaluates to TRUE will cause the permission to be granted. Any value that
3033 * evaluates to FALSE will cause the permission to be revoked.
3036 * 'administer nodes' => 0, // Revoke 'administer nodes'
3037 * 'administer blocks' => FALSE, // Revoke 'administer blocks'
3038 * 'access user profiles' => 1, // Grant 'access user profiles'
3039 * 'access content' => TRUE, // Grant 'access content'
3040 * 'access comments' => 'access comments', // Grant 'access comments'
3043 * Existing permissions are not changed, unless specified in $permissions.
3045 * @see user_role_grant_permissions()
3046 * @see user_role_revoke_permissions()
3048 function user_role_change_permissions($rid, array $permissions = array()) {
3049 // Grant new permissions for the role.
3050 $grant = array_filter($permissions);
3051 if (!empty($grant)) {
3052 user_role_grant_permissions($rid, array_keys($grant));
3054 // Revoke permissions for the role.
3055 $revoke = array_diff_assoc($permissions, $grant);
3056 if (!empty($revoke)) {
3057 user_role_revoke_permissions($rid, array_keys($revoke));
3062 * Grant permissions to a user role.
3065 * The ID of a user role to alter.
3066 * @param $permissions
3067 * A list of permission names to grant.
3069 * @see user_role_change_permissions()
3070 * @see user_role_revoke_permissions()
3072 function user_role_grant_permissions($rid, array $permissions = array()) {
3073 $modules = user_permission_get_modules();
3074 // Grant new permissions for the role.
3075 foreach ($permissions as
$name) {
3076 db_merge('role_permission')
3079 'permission' => $name,
3082 'module' => $modules[$name],
3087 // Clear the user access cache.
3088 drupal_static_reset('user_access');
3089 drupal_static_reset('user_role_permissions');
3093 * Revoke permissions from a user role.
3096 * The ID of a user role to alter.
3097 * @param $permissions
3098 * A list of permission names to revoke.
3100 * @see user_role_change_permissions()
3101 * @see user_role_grant_permissions()
3103 function user_role_revoke_permissions($rid, array $permissions = array()) {
3104 // Revoke permissions for the role.
3105 db_delete('role_permission')
3106 ->condition('rid', $rid)
3107 ->condition('permission', $permissions, 'IN')
3110 // Clear the user access cache.
3111 drupal_static_reset('user_access');
3112 drupal_static_reset('user_role_permissions');
3116 * Implements hook_user_operations().
3118 function user_user_operations($form = array(), $form_state = array()) {
3119 $operations = array(
3121 'label' => t('Unblock the selected users'),
3122 'callback' => 'user_user_operations_unblock',
3125 'label' => t('Block the selected users'),
3126 'callback' => 'user_user_operations_block',
3129 'label' => t('Cancel the selected user accounts'),
3133 if (user_access('administer permissions')) {
3134 $roles = user_roles(TRUE
);
3135 unset($roles[DRUPAL_AUTHENTICATED_RID
]); // Can't edit authenticated role.
3137 $add_roles = array();
3138 foreach ($roles as
$key => $value) {
3139 $add_roles['add_role-' .
$key] = $value;
3142 $remove_roles = array();
3143 foreach ($roles as
$key => $value) {
3144 $remove_roles['remove_role-' .
$key] = $value;
3147 if (count($roles)) {
3148 $role_operations = array(
3149 t('Add a role to the selected users') => array(
3150 'label' => $add_roles,
3152 t('Remove a role from the selected users') => array(
3153 'label' => $remove_roles,
3157 $operations += $role_operations;
3161 // If the form has been posted, we need to insert the proper data for
3162 // role editing if necessary.
3163 if (!empty($form_state['submitted'])) {
3164 $operation_rid = explode('-', $form_state['values']['operation']);
3165 $operation = $operation_rid[0];
3166 if ($operation == 'add_role' || $operation == 'remove_role') {
3167 $rid = $operation_rid[1];
3168 if (user_access('administer permissions')) {
3169 $operations[$form_state['values']['operation']] = array(
3170 'callback' => 'user_multiple_role_edit',
3171 'callback arguments' => array($operation, $rid),
3175 watchdog('security', 'Detected malicious attempt to alter protected user fields.', array(), WATCHDOG_WARNING
);
3185 * Callback function for admin mass unblocking users.
3187 function user_user_operations_unblock($accounts) {
3188 $accounts = user_load_multiple($accounts);
3189 foreach ($accounts as
$account) {
3190 // Skip unblocking user if they are already unblocked.
3191 if ($account !== FALSE
&& $account->status
== 0) {
3192 user_save($account, array('status' => 1));
3198 * Callback function for admin mass blocking users.
3200 function user_user_operations_block($accounts) {
3201 $accounts = user_load_multiple($accounts);
3202 foreach ($accounts as
$account) {
3203 // Skip blocking user if they are already blocked.
3204 if ($account !== FALSE
&& $account->status
== 1) {
3205 // For efficiency manually save the original account before applying any
3207 $account->original
= clone
$account;
3208 user_save($account, array('status' => 0));
3214 * Callback function for admin mass adding/deleting a user role.
3216 function user_multiple_role_edit($accounts, $operation, $rid) {
3217 // The role name is not necessary as user_save() will reload the user
3218 // object, but some modules' hook_user() may look at this first.
3219 $role_name = db_query('SELECT name FROM {role} WHERE rid = :rid', array(':rid' => $rid))->fetchField();
3221 switch ($operation) {
3223 $accounts = user_load_multiple($accounts);
3224 foreach ($accounts as
$account) {
3225 // Skip adding the role to the user if they already have it.
3226 if ($account !== FALSE
&& !isset($account->roles
[$rid])) {
3227 $roles = $account->roles
+ array($rid => $role_name);
3228 // For efficiency manually save the original account before applying
3230 $account->original
= clone
$account;
3231 user_save($account, array('roles' => $roles));
3236 $accounts = user_load_multiple($accounts);
3237 foreach ($accounts as
$account) {
3238 // Skip removing the role from the user if they already don't have it.
3239 if ($account !== FALSE
&& isset($account->roles
[$rid])) {
3240 $roles = array_diff($account->roles
, array($rid => $role_name));
3241 // For efficiency manually save the original account before applying
3243 $account->original
= clone
$account;
3244 user_save($account, array('roles' => $roles));
3251 function user_multiple_cancel_confirm($form, &$form_state) {
3252 $edit = $form_state['input'];
3254 $form['accounts'] = array('#prefix' => '<ul>', '#suffix' => '</ul>', '#tree' => TRUE
);
3255 $accounts = user_load_multiple(array_keys(array_filter($edit['accounts'])));
3256 foreach ($accounts as
$uid => $account) {
3257 // Prevent user 1 from being canceled.
3261 $form['accounts'][$uid] = array(
3262 '#type' => 'hidden',
3264 '#prefix' => '<li>',
3265 '#suffix' => check_plain($account->name
) .
"</li>\n",
3269 // Output a notice that user 1 cannot be canceled.
3270 if (isset($accounts[1])) {
3271 $redirect = (count($accounts) == 1);
3272 $message = t('The user account %name cannot be cancelled.', array('%name' => $accounts[1]->name
));
3273 drupal_set_message($message, $redirect ?
'error' : 'warning');
3274 // If only user 1 was selected, redirect to the overview.
3276 drupal_goto('admin/people');
3280 $form['operation'] = array('#type' => 'hidden', '#value' => 'cancel');
3282 module_load_include('inc', 'user', 'user.pages');
3283 $form['user_cancel_method'] = array(
3285 '#title' => t('When cancelling these accounts'),
3287 $form['user_cancel_method'] += user_cancel_methods();
3288 // Remove method descriptions.
3289 foreach (element_children($form['user_cancel_method']) as
$element) {
3290 unset($form['user_cancel_method'][$element]['#description']);
3293 // Allow to send the account cancellation confirmation mail.
3294 $form['user_cancel_confirm'] = array(
3295 '#type' => 'checkbox',
3296 '#title' => t('Require e-mail confirmation to cancel account.'),
3297 '#default_value' => FALSE
,
3298 '#description' => t('When enabled, the user must confirm the account cancellation via e-mail.'),
3300 // Also allow to send account canceled notification mail, if enabled.
3301 $form['user_cancel_notify'] = array(
3302 '#type' => 'checkbox',
3303 '#title' => t('Notify user when account is canceled.'),
3304 '#default_value' => FALSE
,
3305 '#access' => variable_get('user_mail_status_canceled_notify', FALSE
),
3306 '#description' => t('When enabled, the user will receive an e-mail notification after the account has been cancelled.'),
3309 return confirm_form($form,
3310 t('Are you sure you want to cancel these user accounts?'),
3311 'admin/people', t('This action cannot be undone.'),
3312 t('Cancel accounts'), t('Cancel'));
3316 * Submit handler for mass-account cancellation form.
3318 * @see user_multiple_cancel_confirm()
3319 * @see user_cancel_confirm_form_submit()
3321 function user_multiple_cancel_confirm_submit($form, &$form_state) {
3324 if ($form_state['values']['confirm']) {
3325 foreach ($form_state['values']['accounts'] as
$uid => $value) {
3326 // Prevent programmatic form submissions from cancelling user 1.
3330 // Prevent user administrators from deleting themselves without confirmation.
3331 if ($uid == $user->uid
) {
3332 $admin_form_state = $form_state;
3333 unset($admin_form_state['values']['user_cancel_confirm']);
3334 $admin_form_state['values']['_account'] = $user;
3335 user_cancel_confirm_form_submit(array(), $admin_form_state);
3338 user_cancel($form_state['values'], $uid, $form_state['values']['user_cancel_method']);
3342 $form_state['redirect'] = 'admin/people';
3346 * Retrieve a list of all user setting/information categories and sort them by weight.
3348 function _user_categories() {
3349 $categories = module_invoke_all('user_categories');
3350 usort($categories, '_user_sort');
3355 function _user_sort($a, $b) {
3356 $a = (array) $a + array('weight' => 0, 'title' => '');
3357 $b = (array) $b + array('weight' => 0, 'title' => '');
3358 return $a['weight'] < $b['weight'] ?
-1 : ($a['weight'] > $b['weight'] ?
1 : ($a['title'] < $b['title'] ?
-1 : 1));
3362 * List user administration filters that can be applied.
3364 function user_filters() {
3367 $roles = user_roles(TRUE
);
3368 unset($roles[DRUPAL_AUTHENTICATED_RID
]); // Don't list authorized role.
3369 if (count($roles)) {
3370 $filters['role'] = array(
3371 'title' => t('role'),
3372 'field' => 'ur.rid',
3374 '[any]' => t('any'),
3380 foreach (module_implements('permission') as
$module) {
3381 $function = $module .
'_permission';
3382 if ($permissions = $function()) {
3383 asort($permissions);
3384 foreach ($permissions as
$permission => $description) {
3385 $options[t('@module module', array('@module' => $module))][$permission] = t($permission);
3390 $filters['permission'] = array(
3391 'title' => t('permission'),
3393 '[any]' => t('any'),
3397 $filters['status'] = array(
3398 'title' => t('status'),
3399 'field' => 'u.status',
3401 '[any]' => t('any'),
3410 * Extends a query object for user administration filters based on session.
3413 * Query object that should be filtered.
3415 function user_build_filter_query(SelectQuery
$query) {
3416 $filters = user_filters();
3417 // Extend Query with filter conditions.
3418 foreach (isset($_SESSION['user_overview_filter']) ?
$_SESSION['user_overview_filter'] : array() as
$filter) {
3419 list($key, $value) = $filter;
3420 // This checks to see if this permission filter is an enabled permission for
3421 // the authenticated role. If so, then all users would be listed, and we can
3422 // skip adding it to the filter query.
3423 if ($key == 'permission') {
3424 $account = new
stdClass();
3425 $account->uid
= 'user_filter';
3426 $account->roles
= array(DRUPAL_AUTHENTICATED_RID
=> 1);
3427 if (user_access($value, $account)) {
3430 $users_roles_alias = $query->join('users_roles', 'ur', '%alias.uid = u.uid');
3431 $permission_alias = $query->join('role_permission', 'p', $users_roles_alias .
'.rid = %alias.rid');
3432 $query->condition($permission_alias .
'.permission', $value);
3434 elseif ($key == 'role') {
3435 $users_roles_alias = $query->join('users_roles', 'ur', '%alias.uid = u.uid');
3436 $query->condition($users_roles_alias .
'.rid' , $value);
3439 $query->condition($filters[$key]['field'], $value);
3445 * Implements hook_comment_view().
3447 function user_comment_view($comment) {
3448 if (variable_get('user_signatures', 0) && !empty($comment->signature
)) {
3449 // @todo This alters and replaces the original object value, so a
3450 // hypothetical process of loading, viewing, and saving will hijack the
3451 // stored data. Consider renaming to $comment->signature_safe or similar
3452 // here and elsewhere in Drupal 8.
3453 $comment->signature
= check_markup($comment->signature
, $comment->signature_format
, '', TRUE
);
3456 $comment->signature
= '';
3461 * Returns HTML for a user signature.
3464 * An associative array containing:
3465 * - signature: The user's signature.
3467 * @ingroup themeable
3469 function theme_user_signature($variables) {
3470 $signature = $variables['signature'];
3474 $output .
= '<div class="clear">';
3475 $output .
= '<div>—</div>';
3476 $output .
= $signature;
3477 $output .
= '</div>';
3484 * Get the language object preferred by the user. This user preference can
3485 * be set on the user account editing page, and is only available if there
3486 * are more than one languages enabled on the site. If the user did not
3487 * choose a preferred language, or is the anonymous user, the $default
3488 * value, or if it is not set, the site default language will be returned.
3491 * User account to look up language for.
3493 * Optional default language object to return if the account
3494 * has no valid language.
3496 function user_preferred_language($account, $default = NULL
) {
3497 $language_list = language_list();
3498 if (!empty($account->language
) && isset($language_list[$account->language
])) {
3499 return $language_list[$account->language
];
3502 return $default ?
$default : language_default();
3507 * Conditionally create and send a notification email when a certain
3508 * operation happens on the given user account.
3510 * @see user_mail_tokens()
3511 * @see drupal_mail()
3514 * The operation being performed on the account. Possible values:
3515 * - 'register_admin_created': Welcome message for user created by the admin.
3516 * - 'register_no_approval_required': Welcome message when user
3518 * - 'register_pending_approval': Welcome message, user pending admin
3520 * - 'password_reset': Password recovery request.
3521 * - 'status_activated': Account activated.
3522 * - 'status_blocked': Account blocked.
3523 * - 'cancel_confirm': Account cancellation request.
3524 * - 'status_canceled': Account canceled.
3527 * The user object of the account being notified. Must contain at
3528 * least the fields 'uid', 'name', and 'mail'.
3530 * Optional language to use for the notification, overriding account language.
3533 * The return value from drupal_mail_system()->mail(), if ends up being
3536 function _user_mail_notify($op, $account, $language = NULL
) {
3537 // By default, we always notify except for canceled and blocked.
3538 $default_notify = ($op != 'status_canceled' && $op != 'status_blocked');
3539 $notify = variable_get('user_mail_' .
$op .
'_notify', $default_notify);
3541 $params['account'] = $account;
3542 $language = $language ?
$language : user_preferred_language($account);
3543 $mail = drupal_mail('user',