2 // $Id: user.module,v 1.745.2.23 2007/12/06 19:49:14 drumm Exp $
6 * Enables the user registration and login system.
9 define('USERNAME_MAX_LENGTH', 60);
10 define('EMAIL_MAX_LENGTH', 64);
13 * Invokes hook_user() in every module.
15 * We cannot use module_invoke() for this, because the arguments need to
16 * be passed by reference.
18 function user_module_invoke($type, &$array, &$user, $category = NULL) {
19 foreach (module_list() as $module) {
20 $function = $module .'_user';
21 if (function_exists($function)) {
22 $function($type, $array, $user, $category);
27 function user_external_load($authname) {
28 $result = db_query("SELECT uid FROM {authmap} WHERE authname = '%s'", $authname);
30 if ($user = db_fetch_array($result)) {
31 return user_load($user);
39 * Fetch a user object.
42 * An associative array of attributes to search for in selecting the
43 * user, such as user name or e-mail address.
46 * A fully-loaded $user object upon successful user load or FALSE if user cannot be loaded.
48 function user_load($array = array()) {
49 // Dynamically compose a SQL query:
53 foreach ($array as $key => $value) {
54 if ($key == 'uid' || $key == 'status') {
55 $query[] = "$key = %d";
58 else if ($key == 'pass') {
59 $query[] = "pass = '%s'";
60 $params[] = md5($value);
63 $query[]= "LOWER($key) = LOWER('%s')";
67 $result = db_query('SELECT * FROM {users} u WHERE '. implode(' AND ', $query), $params);
69 if (db_num_rows($result)) {
70 $user = db_fetch_object($result);
71 $user = drupal_unpack($user);
73 $user->roles = array();
75 $user->roles[DRUPAL_AUTHENTICATED_RID] = 'authenticated user';
78 $user->roles[DRUPAL_ANONYMOUS_RID] = 'anonymous user';
80 $result = db_query('SELECT r.rid, r.name FROM {role} r INNER JOIN {users_roles} ur ON ur.rid = r.rid WHERE ur.uid = %d', $user->uid);
81 while ($role = db_fetch_object($result)) {
82 $user->roles[$role->rid] = $role->name;
84 user_module_invoke('load', $array, $user);
94 * Save changes to a user account or add a new user.
97 * The $user object for the user to modify or add. If $user->uid is
98 * omitted, a new user will be added.
101 * An array of fields and values to save. For example array('name' => 'My name');
102 * Setting a field to NULL deletes it from the data column.
105 * (optional) The category for storing profile information in.
107 function user_save($account, $array = array(), $category = 'account') {
108 // Dynamically compose a SQL query:
109 $user_fields = user_fields();
111 user_module_invoke('update', $array, $account, $category);
113 $data = unserialize(db_result(db_query('SELECT data FROM {users} WHERE uid = %d', $account->uid)));
114 // Consider users edited by an administrator as logged in, if they haven't
115 // already, so anonymous users can view the profile (if allowed).
116 if (empty($array['access']) && empty($account->access) && user_access('administer users')) {
117 $array['access'] = time();
119 foreach ($array as $key => $value) {
120 if ($key == 'pass' && !empty($value)) {
121 $query .= "$key = '%s', ";
124 else if ((substr($key, 0, 4) !== 'auth') && ($key != 'pass')) {
125 if (in_array($key, $user_fields)) {
126 // Save standard fields
127 $query .= "$key = '%s', ";
130 else if ($key != 'roles') {
131 // Roles is a special case: it used below.
132 if ($value === NULL) {
136 $data[$key] = $value;
141 $query .= "data = '%s' ";
142 $v[] = serialize($data);
144 db_query("UPDATE {users} SET $query WHERE uid = %d", array_merge($v, array($account->uid)));
146 // Reload user roles if provided
147 if (is_array($array['roles'])) {
148 db_query('DELETE FROM {users_roles} WHERE uid = %d', $account->uid);
150 foreach (array_keys($array['roles']) as $rid) {
151 if (!in_array($rid, array(DRUPAL_ANONYMOUS_RID, DRUPAL_AUTHENTICATED_RID))) {
152 db_query('INSERT INTO {users_roles} (uid, rid) VALUES (%d, %d)', $account->uid, $rid);
157 // Delete a blocked user's sessions to kick them if they are online.
158 if (isset($array['status']) && $array['status'] == 0) {
159 sess_destroy_uid($account->uid);
162 // If the password changed, delete all open sessions and recreate
164 if (!empty($array['pass'])) {
165 sess_destroy_uid($account->uid);
169 // Refresh user object
170 $user = user_load(array('uid' => $account->uid));
171 user_module_invoke('after_update', $array, $user, $category);
174 $array['uid'] = db_next_id('{users}_uid');
176 if (!isset($array['created'])) { // Allow 'created' to be set by hook_auth
177 $array['created'] = time();
179 // Consider users created by an administrator as already logged in, so
180 // anonymous users can view the profile (if allowed).
181 if (empty($array['access']) && user_access('administer users')) {
182 $array['access'] = time();
185 // Note, we wait with saving the data column to prevent module-handled
186 // fields from being saved there. We cannot invoke hook_user('insert') here
187 // because we don't have a fully initialized user object yet.
188 foreach ($array as $key => $value) {
192 $values[] = md5($value);
195 case 'uid': case 'mode': case 'sort':
196 case 'threshold': case 'created': case 'access':
197 case 'login': case 'status':
203 if (substr($key, 0, 4) !== 'auth' && in_array($key, $user_fields)) {
211 db_query('INSERT INTO {users} ('. implode(', ', $fields) .') VALUES ('. implode(', ', $s) .')', $values);
213 // Build the initial user object.
214 $user = user_load(array('uid' => $array['uid']));
216 user_module_invoke('insert', $array, $user, $category);
218 // Build and save the serialized data field now
220 foreach ($array as $key => $value) {
221 if ((substr($key, 0, 4) !== 'auth') && ($key != 'roles') && (!in_array($key, $user_fields)) && ($value !== NULL)) {
222 $data[$key] = $value;
225 db_query("UPDATE {users} SET data = '%s' WHERE uid = %d", serialize($data), $user->uid);
227 // Save user roles (delete just to be safe).
228 if (is_array($array['roles'])) {
229 db_query('DELETE FROM {users_roles} WHERE uid = %d', $array['uid']);
230 foreach (array_keys($array['roles']) as $rid) {
231 if (!in_array($rid, array(DRUPAL_ANONYMOUS_RID, DRUPAL_AUTHENTICATED_RID))) {
232 db_query('INSERT INTO {users_roles} (uid, rid) VALUES (%d, %d)', $array['uid'], $rid);
237 // Build the finished user object.
238 $user = user_load(array('uid' => $array['uid']));
241 // Save distributed authentication mappings
243 foreach ($array as $key => $value) {
244 if (substr($key, 0, 4) == 'auth') {
245 $authmaps[$key] = $value;
248 if (sizeof($authmaps) > 0) {
249 user_set_authmaps($user, $authmaps);
256 * Verify the syntax of the given name.
258 function user_validate_name($name) {
259 if (!strlen($name)) return t('You must enter a username.');
260 if (substr($name, 0, 1) == ' ') return t('The username cannot begin with a space.');
261 if (substr($name, -1) == ' ') return t('The username cannot end with a space.');
262 if (strpos($name, ' ') !== FALSE) return t('The username cannot contain multiple spaces in a row.');
263 if (ereg("[^\x80-\xF7 [:alnum:]@_.-]", $name)) return t('The username contains an illegal character.');
264 if (preg_match('/[\x{80}-\x{A0}'. // Non-printable ISO-8859-1 + NBSP
265 '\x{AD}'. // Soft-hyphen
266 '\x{2000}-\x{200F}'. // Various space characters
267 '\x{2028}-\x{202F}'. // Bidirectional text overrides
268 '\x{205F}-\x{206F}'. // Various text hinting characters
269 '\x{FEFF}'. // Byte order mark
270 '\x{FF01}-\x{FF60}'. // Full-width latin
271 '\x{FFF9}-\x{FFFD}'. // Replacement characters
272 '\x{0}]/u', // NULL byte
274 return t('The username contains an illegal character.');
276 if (strpos($name, '@') !== FALSE && !eregi('@([0-9a-z](-?[0-9a-z])*.)+[a-z]{2}([zmuvtg]|fo|me)?$', $name)) return t('The username is not a valid authentication ID.');
277 if (strlen($name) > USERNAME_MAX_LENGTH) return t('The username %name is too long: it must be %max characters or less.', array('%name' => $name, '%max' => USERNAME_MAX_LENGTH));
280 function user_validate_mail($mail) {
281 if (!$mail) return t('You must enter an e-mail address.');
282 if (!valid_email_address($mail)) {
283 return t('The e-mail address %mail is not valid.', array('%mail' => $mail));
287 function user_validate_picture($file, &$edit, $user) {
289 // Initialize the picture:
290 $form_values['picture'] = $user->picture;
292 // Check that uploaded file is an image, with a maximum file size
293 // and maximum height/width.
294 $info = image_get_info($file->filepath);
295 list($maxwidth, $maxheight) = explode('x', variable_get('user_picture_dimensions', '85x85'));
297 if (!$info || !$info['extension']) {
298 form_set_error('picture_upload', t('The uploaded file was not an image.'));
300 else if (image_get_toolkit()) {
301 image_scale($file->filepath, $file->filepath, $maxwidth, $maxheight);
303 else if (filesize($file->filepath) > (variable_get('user_picture_file_size', '30') * 1000)) {
304 form_set_error('picture_upload', t('The uploaded image is too large; the maximum file size is %size kB.', array('%size' => variable_get('user_picture_file_size', '30'))));
306 else if ($info['width'] > $maxwidth || $info['height'] > $maxheight) {
307 form_set_error('picture_upload', t('The uploaded image is too large; the maximum dimensions are %dimensions pixels.', array('%dimensions' => variable_get('user_picture_dimensions', '85x85'))));
310 if (!form_get_errors()) {
311 if ($file = file_save_upload('picture_upload', variable_get('user_picture_path', 'pictures') .'/picture-'. $user->uid .'.'. $info['extension'], 1)) {
312 $form_values['picture'] = $file->filepath;
315 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'))));
321 * Generate a random alphanumeric password.
323 function user_password($length = 10) {
324 // This variable contains the list of allowable characters for the
325 // password. Note that the number 0 and the letter 'O' have been
326 // removed to avoid confusion between the two. The same is true
328 $allowable_characters = 'abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789';
330 // Zero-based count of characters in the allowable list:
331 $len = strlen($allowable_characters) - 1;
333 // Declare the password as a blank string.
336 // Loop the number of times specified by $length.
337 for ($i = 0; $i < $length; $i++) {
339 // Each iteration, pick a random character from the
340 // allowable string and append it to the password:
341 $pass .= $allowable_characters[mt_rand(0, $len)];
348 * Determine whether the user has a given privilege.
351 * The permission, such as "administer nodes", being checked for.
353 * (optional) The account to check, if not given use currently logged in user.
356 * boolean TRUE if the current user has the requested permission.
358 * All permission checks in Drupal should go through this function. This
359 * way, we guarantee consistent behavior, and ensure that the superuser
360 * can perform all actions.
362 function user_access($string, $account = NULL) {
364 static $perm = array();
366 if (is_null($account)) {
370 // User #1 has all privileges:
371 if ($account->uid == 1) {
375 // To reduce the number of SQL queries, we cache the user's permissions
376 // in a static variable.
377 if (!isset($perm[$account->uid])) {
378 $rids = array_keys($account->roles);
379 $placeholders = implode(',', array_fill(0, count($rids), '%d'));
380 $result = db_query("SELECT DISTINCT(p.perm) FROM {role} r INNER JOIN {permission} p ON p.rid = r.rid WHERE r.rid IN ($placeholders)", $rids);
381 $perm[$account->uid] = '';
382 while ($row = db_fetch_object($result)) {
383 $perm[$account->uid] .= "$row->perm, ";
387 if (isset($perm[$account->uid])) {
388 return strpos($perm[$account->uid], "$string, ") !== FALSE;
395 * Checks for usernames blocked by user administration
397 * @return boolean TRUE for blocked users, FALSE for active
399 function user_is_blocked($name) {
400 $deny = db_fetch_object(db_query("SELECT name FROM {users} WHERE status = 0 AND name = LOWER('%s')", $name));
405 function user_fields() {
409 $result = db_query('SELECT * FROM {users} WHERE uid = 1');
410 if (db_num_rows($result)) {
411 $fields = array_keys(db_fetch_array($result));
414 // Make sure we return the default fields at least
415 $fields = array('uid', 'name', 'pass', 'mail', 'picture', 'mode', 'sort', 'threshold', 'theme', 'signature', 'created', 'access', 'login', 'status', 'timezone', 'language', 'init', 'data');
423 * Implementation of hook_perm().
425 function user_perm() {
426 return array('administer access control', 'administer users', 'access user profiles', 'change own username');
430 * Implementation of hook_file_download().
432 * Ensure that user pictures (avatars) are always downloadable.
434 function user_file_download($file) {
435 if (strpos($file, variable_get('user_picture_path', 'pictures') .'/picture-') === 0) {
436 $info = image_get_info(file_create_path($file));
437 return array('Content-type: '. $info['mime_type']);
442 * Implementation of hook_search().
444 function user_search($op = 'search', $keys = NULL) {
447 if (user_access('access user profiles')) {
451 if (user_access('access user profiles')) {
453 // Replace wildcards with MySQL/PostgreSQL wildcards.
454 $keys = preg_replace('!\*+!', '%', $keys);
455 $result = pager_query("SELECT name, uid FROM {users} WHERE LOWER(name) LIKE LOWER('%%%s%%')", 15, 0, NULL, $keys);
456 while ($account = db_fetch_object($result)) {
457 $find[] = array('title' => $account->name, 'link' => url('user/'. $account->uid, NULL, NULL, TRUE));
465 * Implementation of hook_user().
467 function user_user($type, &$edit, &$user, $category = NULL) {
468 if ($type == 'view') {
469 $items['history'] = array('title' => t('Member for'),
470 'value' => format_interval(time() - $user->created),
474 return array(t('History') => $items);
476 if ($type == 'form' && $category == 'account') {
477 return user_edit_form(arg(1), $edit);
480 if ($type == 'validate' && $category == 'account') {
481 return _user_edit_validate(arg(1), $edit);
484 if ($type == 'submit' && $category == 'account') {
485 return _user_edit_submit(arg(1), $edit);
488 if ($type == 'categories') {
489 return array(array('name' => 'account', 'title' => t('Account settings'), 'weight' => 1));
493 function user_login_block() {
495 '#action' => url($_GET['q'], drupal_get_destination()),
496 '#id' => 'user-login-form',
497 '#base' => 'user_login',
499 $form['name'] = array('#type' => 'textfield',
500 '#title' => t('Username'),
501 '#maxlength' => USERNAME_MAX_LENGTH,
505 $form['pass'] = array('#type' => 'password',
506 '#title' => t('Password'),
511 $form['submit'] = array('#type' => 'submit',
512 '#value' => t('Log in'),
515 if (variable_get('user_register', 1)) {
516 $items[] = l(t('Create new account'), 'user/register', array('title' => t('Create a new user account.')));
518 $items[] = l(t('Request new password'), 'user/password', array('title' => t('Request new password via e-mail.')));
519 $form['links'] = array('#value' => theme('item_list', $items));
524 * Implementation of hook_block().
526 function user_block($op = 'list', $delta = 0, $edit = array()) {
530 $blocks[0]['info'] = t('User login');
531 $blocks[1]['info'] = t('Navigation');
532 $blocks[2]['info'] = t('Who\'s new');
533 $blocks[3]['info'] = t('Who\'s online');
537 else if ($op == 'configure' && $delta == 2) {
538 $form['user_block_whois_new_count'] = array(
540 '#title' => t('Number of users to display'),
541 '#default_value' => variable_get('user_block_whois_new_count', 5),
542 '#options' => drupal_map_assoc(array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)),
546 else if ($op == 'configure' && $delta == 3) {
547 $period = drupal_map_assoc(array(30, 60, 120, 180, 300, 600, 900, 1800, 2700, 3600, 5400, 7200, 10800, 21600, 43200, 86400), 'format_interval');
548 $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.'));
549 $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.'));
553 else if ($op == 'save' && $delta == 2) {
554 variable_set('user_block_whois_new_count', $edit['user_block_whois_new_count']);
556 else if ($op == 'save' && $delta == 3) {
557 variable_set('user_block_seconds_online', $edit['user_block_seconds_online']);
558 variable_set('user_block_max_list_count', $edit['user_block_max_list_count']);
560 else if ($op == 'view') {
565 // For usability's sake, avoid showing two login forms on one page.
566 if (!$user->uid && !(arg(0) == 'user' && !is_numeric(arg(1)))) {
568 $block['subject'] = t('User login');
569 $block['content'] = drupal_get_form('user_login_block');
574 if ($menu = theme('menu_tree')) {
575 $block['subject'] = $user->uid ? check_plain($user->name) : t('Navigation');
576 $block['content'] = $menu;
581 if (user_access('access content')) {
582 // Retrieve a list of new users who have subsequently accessed the site successfully.
583 $result = 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));
584 while ($account = db_fetch_object($result)) {
587 $output = theme('user_list', $items);
589 $block['subject'] = t('Who\'s new');
590 $block['content'] = $output;
595 if (user_access('access content')) {
596 // Count users active within the defined period.
597 $interval = time() - variable_get('user_block_seconds_online', 900);
599 // Perform database queries to gather online user lists. We use s.timestamp
600 // rather than u.access because it is much faster.
601 $anonymous_count = sess_count($interval);
602 $authenticated_users = db_query('SELECT DISTINCT u.uid, u.name, s.timestamp FROM {users} u INNER JOIN {sessions} s ON u.uid = s.uid WHERE s.timestamp >= %d AND s.uid > 0 ORDER BY s.timestamp DESC', $interval);
603 $authenticated_count = db_num_rows($authenticated_users);
605 // Format the output with proper grammar.
606 if ($anonymous_count == 1 && $authenticated_count == 1) {
607 $output = t('There is currently %members and %visitors online.', array('%members' => format_plural($authenticated_count, '1 user', '@count users'), '%visitors' => format_plural($anonymous_count, '1 guest', '@count guests')));
610 $output = t('There are currently %members and %visitors online.', array('%members' => format_plural($authenticated_count, '1 user', '@count users'), '%visitors' => format_plural($anonymous_count, '1 guest', '@count guests')));
613 // Display a list of currently online users.
614 $max_users = variable_get('user_block_max_list_count', 10);
615 if ($authenticated_count && $max_users) {
618 while ($max_users-- && $account = db_fetch_object($authenticated_users)) {
622 $output .= theme('user_list', $items, t('Online users'));
625 $block['subject'] = t('Who\'s online');
626 $block['content'] = $output;
633 function theme_user_picture($account) {
634 if (variable_get('user_pictures', 0)) {
635 if ($account->picture && file_exists($account->picture)) {
636 $picture = file_create_url($account->picture);
638 else if (variable_get('user_picture_default', '')) {
639 $picture = variable_get('user_picture_default', '');
642 if (isset($picture)) {
643 $alt = t("@user's picture", array('@user' => $account->name ? $account->name : variable_get('anonymous', t('Anonymous'))));
644 $picture = theme('image', $picture, $alt, $alt, '', FALSE);
645 if (!empty($account->uid) && user_access('access user profiles')) {
646 $picture = l($picture, "user/$account->uid", array('title' => t('View user profile.')), NULL, NULL, FALSE, TRUE);
649 return "<div class=\"picture\">$picture</div>";
656 * @param $account the user object
657 * @param $fields a multidimensional array for the fields, in the form of array (
658 * 'category1' => array(item_array1, item_array2), 'category2' => array(item_array3,
659 * .. etc.). Item arrays are formatted as array(array('title' => 'item title',
660 * 'value' => 'item value', 'class' => 'class-name'), ... etc.). Module names are incorporated
661 * into the CSS class.
665 function theme_user_profile($account, $fields) {
666 $output = '<div class="profile">';
667 $output .= theme('user_picture', $account);
668 foreach ($fields as $category => $items) {
669 if (strlen($category) > 0) {
670 $output .= '<h2 class="title">'. check_plain($category) .'</h2>';
673 foreach ($items as $item) {
674 if (isset($item['title'])) {
675 $output .= '<dt class="'. $item['class'] .'">'. $item['title'] .'</dt>';
677 $output .= '<dd class="'. $item['class'] .'">'. $item['value'] .'</dd>';
687 * Make a list of users.
688 * @param $items an array with user objects. Should contain at least the name and uid
692 function theme_user_list($users, $title = NULL) {
693 if (!empty($users)) {
694 foreach ($users as $user) {
695 $items[] = theme('username', $user);
698 return theme('item_list', $items, $title);
702 * Implementation of hook_menu().
704 function user_menu($may_cache) {
709 $admin_access = user_access('administer users');
710 $access_access = user_access('administer access control');
711 $view_access = user_access('access user profiles');
714 $items[] = array('path' => 'user', 'title' => t('User account'),
715 'callback' => 'drupal_get_form', 'callback arguments' => array('user_login'),
716 'access' => !$user->uid, 'type' => MENU_CALLBACK);
718 $items[] = array('path' => 'user/autocomplete', 'title' => t('User autocomplete'),
719 'callback' => 'user_autocomplete', 'access' => $view_access, 'type' => MENU_CALLBACK);
721 // Registration and login pages.
722 $items[] = array('path' => 'user/login', 'title' => t('Log in'),
723 'callback' => 'drupal_get_form', 'callback arguments' => array('user_login'),
724 'access' => !$user->uid, 'type' => MENU_DEFAULT_LOCAL_TASK);
725 $items[] = array('path' => 'user/register', 'title' => t('Create new account'),
726 'callback' => 'drupal_get_form', 'callback arguments' => array('user_register'), 'access' => !$user->uid && variable_get('user_register', 1), 'type' => MENU_LOCAL_TASK);
727 $items[] = array('path' => 'user/password', 'title' => t('Request new password'),
728 'callback' => 'drupal_get_form', 'callback arguments' => array('user_pass'), 'access' => !$user->uid, 'type' => MENU_LOCAL_TASK);
729 $items[] = array('path' => 'user/reset', 'title' => t('Reset password'),
730 'callback' => 'drupal_get_form', 'callback arguments' => array('user_pass_reset'), 'access' => TRUE, 'type' => MENU_CALLBACK);
731 $items[] = array('path' => 'user/help', 'title' => t('Help'),
732 'callback' => 'user_help_page', 'type' => MENU_CALLBACK);
735 $items[] = array('path' => 'admin/user',
736 'title' => t('User management'),
737 'description' => t('Manage your site\'s users, groups and access to site features.'),
738 'position' => 'left',
739 'callback' => 'system_admin_menu_block_page',
740 'access' => user_access('administer site configuration'),
742 $items[] = array('path' => 'admin/user/user', 'title' => t('Users'),
743 'description' => t('List, add, and edit users.'),
744 'callback' => 'user_admin', 'callback arguments' => array('list'), 'access' => $admin_access);
745 $items[] = array('path' => 'admin/user/user/list', 'title' => t('List'),
746 'type' => MENU_DEFAULT_LOCAL_TASK, 'weight' => -10);
747 $items[] = array('path' => 'admin/user/user/create', 'title' => t('Add user'),
748 'callback' => 'user_admin', 'callback arguments' => array('create'), 'access' => $admin_access,
749 'type' => MENU_LOCAL_TASK);
750 $items[] = array('path' => 'admin/user/settings', 'title' => t('User settings'),
751 'description' => t('Configure default behavior of users, including registration requirements, e-mails, and user pictures.'),
752 'callback' => 'drupal_get_form', 'callback arguments' => array('user_admin_settings'));
754 // Admin access pages
755 $items[] = array('path' => 'admin/user/access', 'title' => t('Access control'),
756 'description' => t('Determine access to features by selecting permissions for roles.'),
757 'callback' => 'drupal_get_form', 'callback arguments' => array('user_admin_perm'), 'access' => $access_access);
758 $items[] = array('path' => 'admin/user/roles', 'title' => t('Roles'),
759 'description' => t('List, edit, or add user roles.'),
760 'callback' => 'drupal_get_form', 'callback arguments' => array('user_admin_new_role'), 'access' => $access_access,
761 'type' => MENU_NORMAL_ITEM);
762 $items[] = array('path' => 'admin/user/roles/edit', 'title' => t('Edit role'),
763 'callback' => 'drupal_get_form', 'callback arguments' => array('user_admin_role'), 'access' => $access_access,
764 'type' => MENU_CALLBACK);
765 $items[] = array('path' => 'admin/user/rules', 'title' => t('Access rules'),
766 'description' => t('List and create rules to disallow usernames, e-mail addresses, and IP addresses.'),
767 'callback' => 'user_admin_access', 'access' => $access_access);
768 $items[] = array('path' => 'admin/user/rules/list', 'title' => t('List'),
769 'access' => $access_access, 'type' => MENU_DEFAULT_LOCAL_TASK, 'weight' => -10);
770 $items[] = array('path' => 'admin/user/rules/add', 'title' => t('Add rule'),
771 'callback' => 'user_admin_access_add', 'access' => $access_access,
772 'type' => MENU_LOCAL_TASK);
773 $items[] = array('path' => 'admin/user/rules/check', 'title' => t('Check rules'),
774 'callback' => 'user_admin_access_check', 'access' => $access_access,
775 'type' => MENU_LOCAL_TASK);
776 $items[] = array('path' => 'admin/user/rules/edit', 'title' => t('Edit rule'),
777 'callback' => 'user_admin_access_edit', 'access' => $access_access,
778 'type' => MENU_CALLBACK);
779 $items[] = array('path' => 'admin/user/rules/delete', 'title' => t('Delete rule'),
780 'callback' => 'drupal_get_form', 'callback arguments' => array('user_admin_access_delete_confirm'),
781 'access' => $access_access, 'type' => MENU_CALLBACK);
783 if (module_exists('search')) {
784 $items[] = array('path' => 'admin/user/search', 'title' => t('Search users'),
785 'description' => t('Search users by name.'),
786 'callback' => 'user_admin', 'callback arguments' => array('search'), 'access' => $admin_access,
787 'type' => MENU_NORMAL_ITEM);
790 // Your personal page
792 $items[] = array('path' => 'user/'. $user->uid, 'title' => t('My account'),
793 'callback' => 'user_view', 'callback arguments' => array(arg(1)), 'access' => TRUE,
794 'type' => MENU_DYNAMIC_ITEM);
797 $items[] = array('path' => 'logout', 'title' => t('Log out'),
798 'access' => $user->uid,
799 'callback' => 'user_logout',
803 // Add the CSS for this module. We put this in !$may_cache so it is only
804 // added once per request.
805 drupal_add_css(drupal_get_path('module', 'user') .'/user.css', 'module');
806 if ($_GET['q'] == 'user' && $user->uid) {
807 // We want to make the current user's profile accessible without knowing
808 // their uid, so just linking to /user is enough.
809 drupal_goto('user/'. $user->uid);
812 if (arg(0) == 'user' && is_numeric(arg(1)) && arg(1) > 0) {
813 $account = user_load(array('uid' => arg(1)));
815 if ($user !== FALSE) {
816 // Always let a user view their own account
817 $view_access |= $user->uid == arg(1);
818 // Only admins can view blocked accounts
819 $view_access &= $account->status || $admin_access;
821 $items[] = array('path' => 'user/'. arg(1), 'title' => t('User'),
822 'type' => MENU_CALLBACK, 'callback' => 'user_view',
823 'callback arguments' => array(arg(1)), 'access' => $view_access);
825 $items[] = array('path' => 'user/'. arg(1) .'/view', 'title' => t('View'),
826 'access' => $view_access, 'type' => MENU_DEFAULT_LOCAL_TASK, 'weight' => -10);
828 $items[] = array('path' => 'user/'. arg(1) .'/edit', 'title' => t('Edit'),
829 'callback' => 'drupal_get_form', 'callback arguments' => array('user_edit'),
830 'access' => $admin_access || $user->uid == arg(1), 'type' => MENU_LOCAL_TASK);
831 $items[] = array('path' => 'user/'. arg(1) .'/delete', 'title' => t('Delete'),
832 'callback' => 'user_edit', 'access' => $admin_access,
833 'type' => MENU_CALLBACK);
835 if (arg(2) == 'edit') {
836 if (($categories = _user_categories($account)) && (count($categories) > 1)) {
837 foreach ($categories as $key => $category) {
839 'path' => 'user/'. arg(1) .'/edit/'. $category['name'],
840 'title' => $category['title'],
841 'type' => $category['name'] == 'account' ? MENU_DEFAULT_LOCAL_TASK : MENU_LOCAL_TASK,
842 'weight' => $category['weight'],
843 'access' => ($admin_access || $user->uid == arg(1)));
855 * Accepts an user object, $account, or a DA name and returns an associative
856 * array of modules and DA names. Called at external login.
858 function user_get_authmaps($authname = NULL) {
859 $result = db_query("SELECT authname, module FROM {authmap} WHERE authname = '%s'", $authname);
860 if (db_num_rows($result) > 0) {
861 while ($authmap = db_fetch_object($result)) {
862 $authmaps[$authmap->module] = $authmap->authname;
871 function user_set_authmaps($account, $authmaps) {
872 foreach ($authmaps as $key => $value) {
873 $module = explode('_', $key, 2);
875 db_query("UPDATE {authmap} SET authname = '%s' WHERE uid = %d AND module = '%s'", $value, $account->uid, $module[1]);
876 if (!db_affected_rows()) {
877 db_query("INSERT INTO {authmap} (authname, uid, module) VALUES ('%s', %d, '%s')", $value, $account->uid, $module[1]);
881 db_query("DELETE FROM {authmap} WHERE uid = %d AND module = '%s'", $account->uid, $module[1]);
886 function user_auth_help_links() {
888 foreach (module_list() as $module) {
889 if (module_hook($module, 'auth')) {
890 $links[] = l(module_invoke($module, 'info', 'name'), 'user/help', array(), NULL, $module);
896 /*** User features *********************************************************/
900 function user_login($msg = '') {
903 // If we are already logged on, go to the user page instead.
905 drupal_goto('user/'. $user->uid);
908 // Display login form:
910 $form['message'] = array('#value' => '<p>'. check_plain($msg) .'</p>');
912 $form['name'] = array('#type' => 'textfield',
913 '#title' => t('Username'),
915 '#maxlength' => USERNAME_MAX_LENGTH,
917 '#attributes' => array('tabindex' => '1'),
919 if (variable_get('drupal_authentication_service', FALSE) && count(user_auth_help_links()) > 0) {
920 $form['name']['#description'] = t('Enter your @s username, or an ID from one of our affiliates: !a.', array('@s' => variable_get('site_name', 'Drupal'), '!a' => implode(', ', user_auth_help_links())));
923 $form['name']['#description'] = t('Enter your @s username.', array('@s' => variable_get('site_name', 'Drupal')));
925 $form['pass'] = array('#type' => 'password',
926 '#title' => t('Password'),
927 '#description' => t('Enter the password that accompanies your username.'),
929 '#attributes' => array('tabindex' => '2'),
931 $form['submit'] = array('#type' => 'submit', '#value' => t('Log in'), '#weight' => 2, '#attributes' => array('tabindex' => '3'));
936 function user_login_validate($form_id, $form_values) {
937 if ($form_values['name']) {
938 if (user_is_blocked($form_values['name'])) {
939 // blocked in user administration
940 form_set_error('name', t('The username %name has not been activated or is blocked.', array('%name' => $form_values['name'])));
942 else if (drupal_is_denied('user', $form_values['name'])) {
943 // denied by access controls
944 form_set_error('name', t('The name %name is a reserved username.', array('%name' => $form_values['name'])));
946 else if ($form_values['pass']) {
947 $user = user_authenticate($form_values['name'], trim($form_values['pass']));
950 form_set_error('name', t('Sorry, unrecognized username or password. <a href="@password">Have you forgotten your password?</a>', array('@password' => url('user/password'))));
951 watchdog('user', t('Login attempt failed for %user.', array('%user' => $form_values['name'])));
957 function user_login_submit($form_id, $form_values) {
960 // To handle the edge case where this function is called during a
961 // bootstrap, check for the existence of t().
962 if (function_exists('t')) {
963 $message = t('Session opened for %name.', array('%name' => $user->name));
966 $message = "Session opened for ". check_plain($user->name);
968 watchdog('user', $message);
970 // Update the user table timestamp noting user has logged in.
971 db_query("UPDATE {users} SET login = %d WHERE uid = %d", time(), $user->uid);
973 user_module_invoke('login', $form_values, $user);
976 return 'user/'. $user->uid;
980 function user_authenticate($name, $pass) {
983 // Try to log in the user locally. Don't set $user unless successful.
984 if ($account = user_load(array('name' => $name, 'pass' => $pass, 'status' => 1))) {
989 // Strip name and server from ID:
990 if ($server = strrchr($name, '@')) {
991 $name = substr($name, 0, strlen($name) - strlen($server));
992 $server = substr($server, 1);
995 // When possible, determine corresponding external auth source. Invoke
996 // source, and log in user if successful:
997 if ($server && ($result = user_get_authmaps("$name@$server"))) {
998 if (module_invoke(key($result), 'auth', $name, $pass, $server)) {
999 $user = user_external_load("$name@$server");
1000 watchdog('user', t('External load by %user using module %module.', array('%user' => $name .'@'. $server, '%module' => key($result))));
1004 // Try each external authentication source in series. Register user if
1007 foreach (module_implements('auth') as $module) {
1008 if (module_invoke($module, 'auth', $name, $pass, $server)) {
1010 $name .= '@'. $server;
1012 $user = user_load(array('name' => $name));
1013 if (!$user->uid) { // Register this new user.
1014 $userinfo = array('name' => $name, 'pass' => user_password(), 'init' => $name, 'status' => 1);
1016 $userinfo["authname_$module"] = $name;
1018 $user = user_save('', $userinfo);
1019 watchdog('user', t('New external user: %user using module %module.', array('%user' => $name, '%module' => $module)), WATCHDOG_NOTICE, l(t('edit'), 'user/'. $user->uid .'/edit'));
1029 * Menu callback; logs the current user out, and redirects to the home page.
1031 function user_logout() {
1034 watchdog('user', t('Session closed for %name.', array('%name' => $user->name)));
1036 // Destroy the current session:
1038 module_invoke_all('user', 'logout', NULL, $user);
1040 // Load the anonymous user
1041 $user = drupal_anonymous_user();
1046 function user_pass() {
1049 $form['name'] = array('#type' => 'textfield',
1050 '#title' => t('Username or e-mail address'),
1052 '#maxlength' => max(USERNAME_MAX_LENGTH, EMAIL_MAX_LENGTH),
1053 '#required' => TRUE,
1055 $form['submit'] = array('#type' => 'submit',
1056 '#value' => t('E-mail new password'),
1062 function user_pass_validate($form_id, $form_values) {
1063 $name = $form_values['name'];
1064 $account = user_load(array('mail' => $name, 'status' => 1));
1066 $account = user_load(array('name' => $name, 'status' => 1));
1068 if ($account->uid) {
1069 form_set_value(array('#parents' => array('account')), $account);
1072 form_set_error('name', t('Sorry, %name is not recognized as a user name or an email address.', array('%name' => $name)));
1076 function user_pass_submit($form_id, $form_values) {
1079 $account = $form_values['account'];
1080 $from = variable_get('site_mail', ini_get('sendmail_from'));
1082 // Mail one time login URL and instructions.
1083 $variables = array('!username' => $account->name, '!site' => variable_get('site_name', 'Drupal'), '!login_url' => user_pass_reset_url($account), '!uri' => $base_url, '!uri_brief' => substr($base_url, strlen('http://')), '!mailto' => $account->mail, '!date' => format_date(time()), '!login_uri' => url('user', NULL, NULL, TRUE), '!edit_uri' => url('user/'. $account->uid .'/edit', NULL, NULL, TRUE));
1084 $subject = _user_mail_text('pass_subject', $variables);
1085 $body = _user_mail_text('pass_body', $variables);
1086 $mail_success = drupal_mail('user-pass', $account->mail, $subject, $body, $from);
1088 if ($mail_success) {
1089 watchdog('user', t('Password reset instructions mailed to %name at %email.', array('%name' => $account->name, '%email' => $account->mail)));
1090 drupal_set_message(t('Further instructions have been sent to your e-mail address.'));
1093 watchdog('user', t('Error mailing password reset instructions to %name at %email.', array('%name' => $account->name, '%email' => $account->mail)), WATCHDOG_ERROR);
1094 drupal_set_message(t('Unable to send mail. Please contact the site admin.'));
1100 * Menu callback; process one time login link and redirects to the user page on success.
1102 function user_pass_reset($uid, $timestamp, $hashed_pass, $action = NULL) {
1105 // Check if the user is already logged in. The back button is often the culprit here.
1107 drupal_set_message(t('You have already used this one-time login link. It is not necessary to use this link to login anymore. You are already logged in.'));
1111 // Time out, in seconds, until login URL expires. 24 hours = 86400 seconds.
1114 // Some redundant checks for extra security ?
1115 if ($timestamp < $current && $account = user_load(array('uid' => $uid, 'status' => 1)) ) {
1116 // No time out for first time login.
1117 if ($account->login && $current - $timestamp > $timeout) {
1118 drupal_set_message(t('You have tried to use a one-time login link that has expired. Please request a new one using the form below.'));
1119 drupal_goto('user/password');
1121 else if ($account->uid && $timestamp > $account->login && $timestamp < $current && $hashed_pass == user_pass_rehash($account->pass, $timestamp, $account->login)) {
1122 // First stage is a confirmation form, then login
1123 if ($action == 'login') {
1124 watchdog('user', t('User %name used one-time login link at time %timestamp.', array('%name' => $account->name, '%timestamp' => $timestamp)));
1125 // Update the user table noting user has logged in.
1126 // And this also makes this hashed password a one-time-only login.
1127 db_query("UPDATE {users} SET login = %d WHERE uid = %d", time(), $account->uid);
1128 // Now we can set the new user.
1130 // And proceed with normal login, going to user page.
1132 user_module_invoke('login', $edit, $user);
1133 drupal_set_message(t('You have just used your one-time login link. It is no longer necessary to use this link to login. Please change your password.'));
1134 drupal_goto('user/'. $user->uid .'/edit');
1137 $form['message'] = array('#value' => t('<p>This is a one-time login for %user_name and will expire on %expiration_date</p><p>Click on this button to login to the site and change your password.</p>', array('%user_name' => $account->name, '%expiration_date' => format_date($timestamp + $timeout))));
1138 $form['help'] = array('#value' => '<p>'. t('This login can be used only once.') .'</p>');
1139 $form['submit'] = array('#type' => 'submit', '#value' => t('Log in'));
1140 $form['#action'] = url("user/reset/$uid/$timestamp/$hashed_pass/login");
1145 drupal_set_message(t('You have tried to use a one-time login link which has either been used or is no longer valid. Please request a new one using the form below.'));
1146 drupal_goto('user/password');
1150 // Deny access, no more clues.
1151 // Everything will be in the watchdog's URL for the administrator to check.
1152 drupal_access_denied();
1157 function user_pass_reset_url($account) {
1158 $timestamp = time();
1159 return url("user/reset/$account->uid/$timestamp/".user_pass_rehash($account->pass, $timestamp, $account->login), NULL, NULL, TRUE);
1162 function user_pass_rehash($password, $timestamp, $login) {
1163 return md5($timestamp . $password . $login);
1166 function user_register() {
1169 $admin = user_access('administer users');
1171 // If we aren't admin but already logged on, go to the user page instead.
1172 if (!$admin && $user->uid) {
1173 drupal_goto('user/'. $user->uid);
1178 // Display the registration form.
1180 $form['user_registration_help'] = array('#value' => filter_xss_admin(variable_get('user_registration_help', '')));
1182 $affiliates = user_auth_help_links();
1183 if (!$admin && count($affiliates) > 0) {
1184 $affiliates = implode(', ', $affiliates);
1185 $form['affiliates'] = array('#value' => '<p>'. t('Note: if you have an account with one of our affiliates (!s), you may <a href="@login_uri">login now</a> instead of registering.', array('!s' => $affiliates, '@login_uri' => url('user'))) .'</p>');
1187 // Merge in the default user edit fields.
1188 $form = array_merge($form, user_edit_form(NULL, NULL, TRUE));
1190 $form['account']['notify'] = array(
1191 '#type' => 'checkbox',
1192 '#title' => t('Notify user of new account')
1194 // Redirect back to page which initiated the create request; usually admin/user/user/create
1195 $form['destination'] = array('#type' => 'hidden', '#value' => $_GET['q']);
1198 // Create a dummy variable for pass-by-reference parameters.
1200 $extra = _user_forms($null, NULL, NULL, 'register');
1202 // Remove form_group around default fields if there are no other groups.
1204 $form['name'] = $form['account']['name'];
1205 $form['mail'] = $form['account']['mail'];
1206 $form['pass'] = $form['account']['pass'];
1207 $form['status'] = $form['account']['status'];
1208 $form['roles'] = $form['account']['roles'];
1209 $form['notify'] = $form['account']['notify'];
1210 unset($form['account']);
1213 $form = array_merge($form, $extra);
1215 $form['submit'] = array('#type' => 'submit', '#value' => t('Create new account'), '#weight' => 30);
1220 function user_register_validate($form_id, $form_values) {
1221 user_module_invoke('validate', $form_values, $form_values, 'account');
1224 function user_register_submit($form_id, $form_values) {
1226 $admin = user_access('administer users');
1228 $mail = $form_values['mail'];
1229 $name = $form_values['name'];
1230 if (!variable_get('user_email_verification', TRUE) || $admin) {
1231 $pass = $form_values['pass'];
1234 $pass = user_password();
1236 $notify = $form_values['notify'];
1237 $from = variable_get('site_mail', ini_get('sendmail_from'));
1238 if (isset($form_values['roles'])) {
1239 $roles = array_filter($form_values['roles']); // Remove unset roles
1242 if (!$admin && array_intersect(array_keys($form_values), array('uid', 'roles', 'init', 'session', 'status'))) {
1243 watchdog('security', t('Detected malicious attempt to alter protected user fields.'), WATCHDOG_WARNING);
1244 return 'user/register';
1246 //the unset below is needed to prevent these form values from being saved as user data
1247 unset($form_values['form_token'], $form_values['submit'], $form_values['op'], $form_values['notify'], $form_values['form_id'], $form_values['affiliates'], $form_values['destination']);
1249 $merge_data = array('pass' => $pass, 'init' => $mail, 'roles' => $roles);
1251 // Set the user's status because it was not displayed in the form.
1252 $merge_data['status'] = variable_get('user_register', 1) == 1;
1254 $account = user_save('', array_merge($form_values, $merge_data));
1255 watchdog('user', t('New user: %name %email.', array('%name' => $name, '%email' => '<'. $mail .'>')), WATCHDOG_NOTICE, l(t('edit'), 'user/'. $account->uid .'/edit'));
1257 $variables = array('!username' => $name, '!site' => variable_get('site_name', 'Drupal'), '!password' => $pass, '!uri' => $base_url, '!uri_brief' => substr($base_url, strlen('http://')), '!mailto' => $mail, '!date' => format_date(time()), '!login_uri' => url('user', NULL, NULL, TRUE), '!edit_uri' => url('user/'. $account->uid .'/edit', NULL, NULL, TRUE), '!login_url' => user_pass_reset_url($account));
1259 // The first user may login immediately, and receives a customized welcome e-mail.
1260 if ($account->uid == 1) {
1261 drupal_mail('user-register-admin', $mail, t('Drupal user account details for !s', array('!s' => $name)), strtr(t("!username,\n\nYou may now login to !uri using the following username and password:\n\n username: !username\n password: !password\n\n!edit_uri\n\n--drupal"), $variables), $from);
1262 drupal_set_message(t('<p>Welcome to Drupal. You are user #1, which gives you full and immediate access. All future registrants will receive their passwords via e-mail, so please make sure your website e-mail address is set properly under the general settings on the <a href="@settings">site information settings page</a>.</p><p> Your password is <strong>%pass</strong>. You may change your password below.</p>', array('%pass' => $pass, '@settings' => url('admin/settings/site-information'))));
1263 user_authenticate($account->name, trim($pass));
1265 return 'user/1/edit';
1268 if ($admin && !$notify) {
1269 drupal_set_message(t('Created a new user account. No e-mail has been sent.'));
1271 else if (!variable_get('user_email_verification', TRUE) && $account->status && !$admin) {
1272 // No e-mail verification is required, create new user account, and login user immediately.
1273 $subject = _user_mail_text('welcome_subject', $variables);
1274 $body = _user_mail_text('welcome_body', $variables);
1275 drupal_mail('user-register-welcome', $mail, $subject, $body, $from);
1276 user_authenticate($account->name, trim($pass));
1278 user_module_invoke('login', $edit, $account);
1281 else if ($account->status || $notify) {
1282 // Create new user account, no administrator approval required.
1283 $subject = $notify ? _user_mail_text('admin_subject', $variables) : _user_mail_text('welcome_subject', $variables);
1284 $body = $notify ? _user_mail_text('admin_body', $variables) : _user_mail_text('welcome_body', $variables);
1286 drupal_mail(($notify ? 'user-register-notify' : 'user-register-welcome'), $mail, $subject, $body, $from);
1289 drupal_set_message(t('Password and further instructions have been e-mailed to the new user %user.', array('%user' => $name)));
1292 drupal_set_message(t('Your password and further instructions have been sent to your e-mail address.'));
1297 // Create new user account, administrator approval required.
1298 $subject = _user_mail_text('approval_subject', $variables);
1299 $body = _user_mail_text('approval_body', $variables);
1301 drupal_mail('user-register-approval-user', $mail, $subject, $body, $from);
1302 drupal_mail('user-register-approval-admin', $from, $subject, t("!username has applied for an account.\n\n!edit_uri", $variables), $from);
1303 drupal_set_message(t('Thank you for applying for an account. Your account is currently pending approval by the site administrator.<br />In the meantime, your password and further instructions have been sent to your e-mail address.'));
1309 function user_edit_form($uid, $edit, $register = FALSE) {
1310 $admin = user_access('administer users');
1312 // Account information:
1313 $form['account'] = array('#type' => 'fieldset',
1314 '#title' => t('Account information'),
1316 if (user_access('change own username') || $admin || $register) {
1317 $form['account']['name'] = array('#type' => 'textfield',
1318 '#title' => t('Username'),
1319 '#default_value' => $edit['name'],
1320 '#maxlength' => USERNAME_MAX_LENGTH,
1321 '#description' => t('Your preferred username; punctuation is not allowed except for periods, hyphens, and underscores.'),
1322 '#required' => TRUE,
1325 $form['account']['mail'] = array('#type' => 'textfield',
1326 '#title' => t('E-mail address'),
1327 '#default_value' => $edit['mail'],
1328 '#maxlength' => EMAIL_MAX_LENGTH,
1329 '#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.'),
1330 '#required' => TRUE,
1333 $form['account']['pass'] = array('#type' => 'password_confirm',
1334 '#description' => t('To change the current user password, enter the new password in both fields.'),
1338 elseif (!variable_get('user_email_verification', TRUE) || $admin) {
1339 $form['account']['pass'] = array(
1340 '#type' => 'password_confirm',
1341 '#description' => t('Provide a password for the new account in both fields.'),
1342 '#required' => TRUE,
1347 $form['account']['status'] = array('#type' => 'radios', '#title' => t('Status'), '#default_value' => isset($edit['status']) ? $edit['status'] : 1, '#options' => array(t('Blocked'), t('Active')));
1349 if (user_access('administer access control')) {
1350 $roles = user_roles(1);
1351 unset($roles[DRUPAL_AUTHENTICATED_RID]);
1353 $form['account']['roles'] = array('#type' => 'checkboxes', '#title' => t('Roles'), '#default_value' => array_keys((array)$edit['roles']), '#options' => $roles, '#description' => t('The user receives the combined permissions of the %au role, and all roles selected here.', array('%au' => t('authenticated user'))));
1358 if (variable_get('user_pictures', 0) && !$register) {
1359 $form['picture'] = array('#type' => 'fieldset', '#title' => t('Picture'), '#weight' => 1);
1360 $picture = theme('user_picture', (object)$edit);
1362 $form['picture']['current_picture'] = array('#value' => $picture);
1363 $form['picture']['picture_delete'] = array('#type' => 'checkbox', '#title' => t('Delete picture'), '#description' => t('Check this box to delete your current picture.'));
1366 $form['picture']['picture_delete'] = array('#type' => 'hidden');
1368 $form['picture']['picture_upload'] = array('#type' => 'file', '#title' => t('Upload picture'), '#size' => 48, '#description' => t('Your virtual face or picture. Maximum dimensions are %dimensions and the maximum size is %size kB.', array('%dimensions' => variable_get('user_picture_dimensions', '85x85'), '%size' => variable_get('user_picture_file_size', '30'))) .' '. variable_get('user_picture_guidelines', ''));
1374 function _user_edit_validate($uid, &$edit) {
1375 $user = user_load(array('uid' => $uid));
1376 // Validate the username:
1377 if (user_access('change own username') || user_access('administer users') || arg(1) == 'register') {
1378 if ($error = user_validate_name($edit['name'])) {
1379 form_set_error('name', $error);
1381 else if (db_num_rows(db_query("SELECT uid FROM {users} WHERE uid != %d AND LOWER(name) = LOWER('%s')", $uid, $edit['name'])) > 0) {
1382 form_set_error('name', t('The name %name is already taken.', array('%name' => $edit['name'])));
1384 else if (drupal_is_denied('user', $edit['name'])) {
1385 form_set_error('name', t('The name %name has been denied access.', array('%name' => $edit['name'])));
1389 // Validate the e-mail address:
1390 if ($error = user_validate_mail($edit['mail'])) {
1391 form_set_error('mail', $error);
1393 else if (db_num_rows(db_query("SELECT uid FROM {users} WHERE uid != %d AND LOWER(mail) = LOWER('%s')", $uid, $edit['mail'])) > 0) {
1394 form_set_error('mail', t('The e-mail address %email is already registered. <a href="@password">Have you forgotten your password?</a>', array('%email' => $edit['mail'], '@password' => url('user/password'))));
1396 else if (drupal_is_denied('mail', $edit['mail'])) {
1397 form_set_error('mail', t('The e-mail address %email has been denied access.', array('%email' => $edit['mail'])));
1400 // If required, validate the uploaded picture.
1401 if ($file = file_check_upload('picture_upload')) {
1402 user_validate_picture($file, $edit, $user);
1406 function _user_edit_submit($uid, &$edit) {
1407 $user = user_load(array('uid' => $uid));
1408 // Delete picture if requested, and if no replacement picture was given.
1409 if ($edit['picture_delete']) {
1410 if ($user->picture && file_exists($user->picture)) {
1411 file_delete($user->picture);
1413 $edit['picture'] = '';
1415 if (isset($edit['roles'])) {
1416 $edit['roles'] = array_filter($edit['roles']);
1420 function user_edit($category = 'account') {
1423 $account = user_load(array('uid' => arg(1)));
1424 if ($account === FALSE) {
1425 drupal_set_message(t('The account does not exist or has already been deleted.'));
1426 drupal_goto('admin/user/user');
1429 $edit = $_POST['op'] ? $_POST : (array)$account;
1431 if (arg(2) == 'delete') {
1432 return drupal_get_form('user_confirm_delete', $account->name, $account->uid);
1434 else if ($_POST['op'] == t('Delete')) {
1435 if ($_REQUEST['destination']) {
1436 $destination = drupal_get_destination();
1437 unset($_REQUEST['destination']);
1439 // Note: we redirect from user/uid/edit to user/uid/delete to make the tabs disappear.
1440 drupal_goto("user/$account->uid/delete", $destination);
1443 $form = _user_forms($edit, $account, $category);
1444 $form['_category'] = array('#type' => 'value', '#value' => $category);
1445 $form['_account'] = array('#type' => 'value', '#value' => $account);
1446 $form['submit'] = array('#type' => 'submit', '#value' => t('Submit'), '#weight' => 30);
1447 if (user_access('administer users')) {
1448 $form['delete'] = array('#type' => 'submit', '#value' => t('Delete'), '#weight' => 31);
1450 $form['#attributes']['enctype'] = 'multipart/form-data';
1452 drupal_set_title(check_plain($account->name));
1456 function user_confirm_delete($name, $uid) {
1457 $form['uid'] = array('#type' => 'value', '#value' => $uid);
1458 return confirm_form($form,
1459 t('Are you sure you want to delete the account %name?', array('%name' => $name)),
1461 t('All submissions made by this user will be attributed to the anonymous account. This action cannot be undone.'),
1462 t('Delete'), t('Cancel'));
1465 function user_confirm_delete_submit($form_id, $form_values) {
1466 $account = user_load(array('uid' => $form_values['uid']));
1467 user_delete((array) $account, $form_values['uid']);
1468 return 'admin/user/user';
1474 * @param $edit An array of submitted form values.
1475 * @param $uid The user ID of the user to delete.
1477 function user_delete($edit, $uid) {
1478 $account = user_load(array('uid' => $uid));
1479 sess_destroy_uid($uid);
1480 db_query('DELETE FROM {users} WHERE uid = %d', $uid);
1481 db_query('DELETE FROM {users_roles} WHERE uid = %d', $uid);
1482 db_query('DELETE FROM {authmap} WHERE uid = %d', $uid);
1483 $array = array('%name' => $account->name, '%email' => '<'. $account->mail .'>');
1484 watchdog('user', t('Deleted user: %name %email.', $array), WATCHDOG_NOTICE);
1485 drupal_set_message(t('%name has been deleted.', $array));
1486 module_invoke_all('user', 'delete', $edit, $account);
1489 function user_edit_validate($form_id, $form_values) {
1490 user_module_invoke('validate', $form_values, $form_values['_account'], $form_values['_category']);
1491 // Validate input to ensure that non-privileged users can't alter protected data.
1492 if ((!user_access('administer users') && array_intersect(array_keys($form_values), array('uid', 'init', 'session'))) || (!user_access('administer access control') && isset($form_values['roles']))) {
1493 $message = t('Detected malicious attempt to alter protected user fields.');
1494 watchdog('security', $message, WATCHDOG_WARNING);
1495 // set this to a value type field
1496 form_set_error('category', $message);
1500 function user_edit_submit($form_id, $form_values) {
1501 $account = $form_values['_account'];
1502 $category = $form_values['_category'];
1503 unset($form_values['_account'], $form_values['op'], $form_values['submit'], $form_values['delete'], $form_values['form_token'], $form_values['form_id'], $form_values['_category']);
1504 user_module_invoke('submit', $form_values, $account, $category);
1505 user_save($account, $form_values, $category);
1507 // Delete that user's menu cache:
1508 cache_clear_all($account->uid .':', 'cache_menu', TRUE);
1510 // Clear the page cache because pages can contain usernames and/or profile information:
1513 drupal_set_message(t('The changes have been saved.'));
1514 return 'user/'. $account->uid;
1517 function user_view($uid = 0) {
1520 $account = user_load(array('uid' => $uid));
1521 if ($account === FALSE || ($account->access == 0 && !user_access('administer users'))) {
1522 return drupal_not_found();
1524 // Retrieve and merge all profile fields:
1526 foreach (module_list() as $module) {
1527 if ($data = module_invoke($module, 'user', 'view', '', $account)) {
1528 foreach ($data as $category => $items) {
1529 foreach ($items as $key => $item) {
1530 $item['class'] = "$module-". $item['class'];
1531 $fields[$category][$key] = $item;
1537 // Let modules change the returned fields - useful for personal privacy
1538 // controls. Since modules communicate changes by reference, we cannot use
1539 // module_invoke_all().
1540 foreach (module_implements('profile_alter') as $module) {
1541 $function = $module .'_profile_alter';
1542 $function($account, $fields);
1545 drupal_set_title(check_plain($account->name));
1546 return theme('user_profile', $account, $fields);
1549 /*** Administrative features ***********************************************/
1551 function _user_mail_text($messageid, $variables = array()) {
1553 // Check if an admin setting overrides the default string.
1554 if ($admin_setting = variable_get('user_mail_'. $messageid, FALSE)) {
1555 return strtr($admin_setting, $variables);
1557 // No override, return with default strings.
1559 switch ($messageid) {
1560 case 'welcome_subject':
1561 return t('Account details for !username at !site', $variables);
1562 case 'welcome_body':
1563 return t("!username,\n\nThank you for registering at !site. You may now log in to !login_uri using the following username and password:\n\nusername: !username\npassword: !password\n\nYou may also log in by clicking on this link or copying and pasting it in your browser:\n\n!login_url\n\nThis is a one-time login, so it can be used only once.\n\nAfter logging in, you will be redirected to !edit_uri so you can change your password.\n\n\n-- !site team", $variables);
1564 case 'admin_subject':
1565 return t('An administrator created an account for you at !site', $variables);
1567 return t("!username,\n\nA site administrator at !site has created an account for you. You may now log in to !login_uri using the following username and password:\n\nusername: !username\npassword: !password\n\nYou may also log in by clicking on this link or copying and pasting it in your browser:\n\n!login_url\n\nThis is a one-time login, so it can be used only once.\n\nAfter logging in, you will be redirected to !edit_uri so you can change your password.\n\n\n-- !site team", $variables);
1568 case 'approval_subject':
1569 return t('Account details for !username at !site (pending admin approval)', $variables);
1570 case 'approval_body':
1571 return t("!username,\n\nThank you for registering at !site. Your application for an account is currently pending approval. Once it has been granted, you may log in to !login_uri using the following username and password:\n\nusername: !username\npassword: !password\n\nYou may also log in by clicking on this link or copying and pasting it in your browser:\n\n!login_url\n\nThis is a one-time login, so it can be used only once.\n\nAfter logging in, you may wish to change your password at !edit_uri\n\n\n-- !site team", $variables);
1572 case 'pass_subject':
1573 return t('Replacement login information for !username at !site', $variables);
1575 return t("!username,\n\nA request to reset the password for your account has been made at !site.\n\nYou may now log in to !uri_brief clicking on this link or copying and pasting it in your browser:\n\n!login_url\n\nThis is a one-time login, so it can be used only once. It expires after one day and nothing will happen if it's not used.\n\nAfter logging in, you will be redirected to !edit_uri so you can change your password.", $variables);
1580 function user_admin_check_user() {
1581 $form['user'] = array('#type' => 'fieldset', '#title' => t('Username'));
1582 $form['user']['test'] = array('#type' => 'textfield', '#title' => '', '#description' => t('Enter a username to check if it will be denied or allowed.'), '#size' => 30, '#maxlength' => USERNAME_MAX_LENGTH);
1583 $form['user']['type'] = array('#type' => 'hidden', '#value' => 'user');
1584 $form['user']['submit'] = array('#type' => 'submit', '#value' => t('Check username'));
1585 $form['#base'] = 'user_admin_access_check';
1589 function user_admin_check_mail() {
1590 $form['mail'] = array('#type' => 'fieldset', '#title' => t('E-mail'));
1591 $form['mail']['test'] = array('#type' => 'textfield', '#title' => '', '#description' => t('Enter an e-mail address to check if it will be denied or allowed.'), '#size' => 30, '#maxlength' => EMAIL_MAX_LENGTH);
1592 $form['mail']['type'] = array('#type' => 'hidden', '#value' => 'mail');
1593 $form['mail']['submit'] = array('#type' => 'submit', '#value' => t('Check e-mail'));
1594 $form['#base'] = 'user_admin_access_check';
1598 function user_admin_check_host() {
1599 $form['host'] = array('#type' => 'fieldset', '#title' => t('Hostname'));
1600 $form['host']['test'] = array('#type' => 'textfield', '#title' => '', '#description' => t('Enter a hostname or IP address to check if it will be denied or allowed.'), '#size' => 30, '#maxlength' => 64);
1601 $form['host']['type'] = array('#type' => 'hidden', '#value' => 'host');
1602 $form['host']['submit'] = array('#type' => 'submit', '#value' => t('Check hostname'));
1603 $form['#base'] = 'user_admin_access_check';
1608 * Menu callback: check an access rule
1610 function user_admin_access_check() {
1611 $output = drupal_get_form('user_admin_check_user');
1612 $output .= drupal_get_form('user_admin_check_mail');
1613 $output .= drupal_get_form('user_admin_check_host');
1617 function user_admin_access_check_validate($form_id, $form_values) {
1618 if (empty($form_values['test'])) {
1619 form_set_error($form_values['type'], t('No value entered. Please enter a test string and try again.'));
1623 function user_admin_access_check_submit($form_id, $form_values) {
1624 switch ($form_values['type']) {
1626 if (drupal_is_denied('user', $form_values['test'])) {
1627 drupal_set_message(t('The username %name is not allowed.', array('%name' => $form_values['test'])));
1630 drupal_set_message(t('The username %name is allowed.', array('%name' => $form_values['test'])));
1634 if (drupal_is_denied('mail', $form_values['test'])) {
1635 drupal_set_message(t('The e-mail address %mail is not allowed.', array('%mail' => $form_values['test'])));
1638 drupal_set_message(t('The e-mail address %mail is allowed.', array('%mail' => $form_values['test'])));
1642 if (drupal_is_denied('host', $form_values['test'])) {
1643 drupal_set_message(t('The hostname %host is not allowed.', array('%host' => $form_values['test'])));
1646 drupal_set_message(t('The hostname %host is allowed.', array('%host' => $form_values['test'])));
1655 * Menu callback: add an access rule
1657 function user_admin_access_add($mask = NULL, $type = NULL) {
1658 if ($edit = $_POST) {
1659 if (!$edit['mask']) {
1660 form_set_error('mask', t('You must enter a mask.'));
1663 $aid = db_next_id('{access}_aid');
1664 db_query("INSERT INTO {access} (aid, mask, type, status) VALUES ('%s', '%s', '%s', %d)", $aid, $edit['mask'], $edit['type'], $edit['status']);
1665 drupal_set_message(t('The access rule has been added.'));
1666 drupal_goto('admin/user/rules');
1670 $edit['mask'] = $mask;
1671 $edit['type'] = $type;
1673 return drupal_get_form('user_admin_access_add_form', $edit, t('Add rule'));
1677 * Menu callback: delete an access rule
1679 function user_admin_access_delete_confirm($aid = 0) {
1680 $access_types = array('user' => t('username'), 'mail' => t('e-mail'), 'host' => t('host'));
1681 $edit = db_fetch_object(db_query('SELECT aid, type, status, mask FROM {access} WHERE aid = %d', $aid));
1684 $form['aid'] = array('#type' => 'hidden', '#value' => $aid);
1685 $output = confirm_form($form,
1686 t('Are you sure you want to delete the @type rule for %rule?', array('@type' => $access_types[$edit->type], '%rule' => $edit->mask)),
1688 t('This action cannot be undone.'),
1694 function user_admin_access_delete_confirm_submit($form_id, $form_values) {
1695 db_query('DELETE FROM {access} WHERE aid = %d', $form_values['aid']);
1696 drupal_set_message(t('The access rule has been deleted.'));
1697 return 'admin/user/rules';
1701 * Menu callback: edit an access rule
1703 function user_admin_access_edit($aid = 0) {
1704 if ($edit = $_POST) {
1705 if (!$edit['mask']) {
1706 form_set_error('mask', t('You must enter a mask.'));
1709 db_query("UPDATE {access} SET mask = '%s', type = '%s', status = '%s' WHERE aid = %d", $edit['mask'], $edit['type'], $edit['status'], $aid);
1710 drupal_set_message(t('The access rule has been saved.'));
1711 drupal_goto('admin/user/rules');
1715 $edit = db_fetch_array(db_query('SELECT aid, type, status, mask FROM {access} WHERE aid = %d', $aid));
1717 return drupal_get_form('user_admin_access_edit_form', $edit, t('Save rule'));
1720 function user_admin_access_form($edit, $submit) {
1721 $form['status'] = array(
1722 '#type' => 'radios',
1723 '#title' => t('Access type'),
1724 '#default_value' => $edit['status'],
1725 '#options' => array('1' => t('Allow'), '0' => t('Deny')),
1727 $type_options = array('user' => t('Username'), 'mail' => t('E-mail'), 'host' => t('Host'));
1728 $form['type'] = array(
1729 '#type' => 'radios',
1730 '#title' => t('Rule type'),
1731 '#default_value' => (isset($type_options[$edit['type']]) ? $edit['type'] : 'user'),
1732 '#options' => $type_options,
1734 $form['mask'] = array(
1735 '#type' => 'textfield',
1736 '#title' => t('Mask'),
1739 '#default_value' => $edit['mask'],
1740 '#description' => '%: '. t('Matches any number of characters, even zero characters') .'.<br />_: '. t('Matches exactly one character.'),
1741 '#required' => TRUE,
1743 $form['submit'] = array('#type' => 'submit', '#value' => $submit);
1749 * Menu callback: list all access rules
1751 function user_admin_access() {
1752 $header = array(array('data' => t('Access type'), 'field' => 'status'), array('data' => t('Rule type'), 'field' => 'type'), array('data' => t('Mask'), 'field' => 'mask'), array('data' => t('Operations'), 'colspan' => 2));
1753 $result = db_query("SELECT aid, type, status, mask FROM {access}". tablesort_sql($header));
1754 $access_types = array('user' => t('username'), 'mail' => t('e-mail'), 'host' => t('host'));
1756 while ($rule = db_fetch_object($result)) {
1757 $rows[] = array($rule->status ? t('allow') : t('deny'), $access_types[$rule->type], $rule->mask, l(t('edit'), 'admin/user/rules/edit/'. $rule->aid), l(t('delete'), 'admin/user/rules/delete/'. $rule->aid));
1759 if (count($rows) == 0) {
1760 $rows[] = array(array('data' => '<em>'. t('There are currently no access rules.') .'</em>', 'colspan' => 5));
1762 $output .= theme('table', $header, $rows);
1768 * Retrieve an array of roles matching specified conditions.
1770 * @param $membersonly
1771 * Set this to TRUE to exclude the 'anonymous' role.
1772 * @param $permission
1773 * A string containing a permission. If set, only roles containing that permission are returned.
1776 * An associative array with the role id as the key and the role name as value.
1778 function user_roles($membersonly = 0, $permission = 0) {
1782 $result = db_query("SELECT r.* FROM {role} r INNER JOIN {permission} p ON r.rid = p.rid WHERE p.perm LIKE '%%%s%%' ORDER BY r.name", $permission);
1785 $result = db_query('SELECT * FROM {role} ORDER BY name');
1787 while ($role = db_fetch_object($result)) {
1788 if (!$membersonly || ($membersonly && $role->rid != DRUPAL_ANONYMOUS_RID)) {
1789 $roles[$role->rid] = $role->name;
1796 * Menu callback: administer permissions.
1798 function user_admin_perm($rid = NULL) {
1799 if (is_numeric($rid)) {
1800 $result = db_query('SELECT r.rid, p.perm FROM {role} r LEFT JOIN {permission} p ON r.rid = p.rid WHERE r.rid = %d', $rid);
1803 $result = db_query('SELECT r.rid, p.perm FROM {role} r LEFT JOIN {permission} p ON r.rid = p.rid ORDER BY name');
1806 // Compile role array:
1807 // Add a comma at the end so when searching for a permission, we can
1808 // always search for "$perm," to make sure we do not confuse
1809 // permissions that are substrings of each other.
1810 while ($role = db_fetch_object($result)) {
1811 $role_permissions[$role->rid] = $role->perm .',';
1814 if (is_numeric($rid)) {
1815 $result = db_query('SELECT rid, name FROM {role} r WHERE r.rid = %d ORDER BY name', $rid);
1818 $result = db_query('SELECT rid, name FROM {role} ORDER BY name');
1821 $role_names = array();
1822 while ($role = db_fetch_object($result)) {
1823 $role_names[$role->rid] = $role->name;
1826 // Render role/permission overview:
1828 foreach (module_list(FALSE, FALSE, TRUE) as $module) {
1829 if ($permissions = module_invoke($module, 'perm')) {
1830 $form['permission'][] = array(
1831 '#value' => $module,
1833 asort($permissions);
1834 foreach ($permissions as $perm) {
1835 $options[$perm] = '';
1836 $form['permission'][$perm] = array('#value' => t($perm));
1837 foreach ($role_names as $rid => $name) {
1838 // Builds arrays for checked boxes for each role
1839 if (strpos($role_permissions[$rid], $perm .',') !== FALSE) {
1840 $status[$rid][] = $perm;
1847 // Have to build checkboxes here after checkbox arrays are built
1848 foreach ($role_names as $rid => $name) {
1849 $form['checkboxes'][$rid] = array('#type' => 'checkboxes', '#options' => $options, '#default_value' => $status[$rid]);
1850 $form['role_names'][$rid] = array('#value' => $name, '#tree' => TRUE);
1852 $form['submit'] = array('#type' => 'submit', '#value' => t('Save permissions'));
1857 function theme_user_admin_perm($form) {
1858 foreach (element_children($form['permission']) as $key) {
1859 // Don't take form control structures
1860 if (is_array($form['permission'][$key])) {
1863 if (is_numeric($key)) {
1864 $row[] = array('data' => t('@module module', array('@module' => drupal_render($form['permission'][$key]))), 'class' => 'module', 'id' => 'module-'. $form['permission'][$key]['#value'], 'colspan' => count($form['role_names']) + 1);
1867 $row[] = array('data' => drupal_render($form['permission'][$key]), 'class' => 'permission');
1868 foreach (element_children($form['checkboxes']) as $rid) {
1869 if (is_array($form['checkboxes'][$rid])) {
1870 $row[] = array('data' => drupal_render($form['checkboxes'][$rid][$key]), 'align' => 'center', 'title' => t($key));
1877 $header[] = (t('Permission'));
1878 foreach (element_children($form['role_names']) as $rid) {
1879 if (is_array($form['role_names'][$rid])) {
1880 $header[] = drupal_render($form['role_names'][$rid]);
1883 $output = theme('table', $header, $rows, array('id' => 'permissions'));
1884 $output .= drupal_render($form);
1888 function user_admin_perm_submit($form_id, $form_values) {
1889 // Save permissions:
1890 $result = db_query('SELECT * FROM {role}');
1891 while ($role = db_fetch_object($result)) {
1892 if (isset($form_values[$role->rid])) {
1893 // Delete, so if we clear every checkbox we reset that role;
1894 // otherwise permissions are active and denied everywhere.
1895 db_query('DELETE FROM {permission} WHERE rid = %d', $role->rid);
1896 $form_values[$role->rid] = array_filter($form_values[$role->rid]);
1897 if (count($form_values[$role->rid])) {
1898 db_query("INSERT INTO {permission} (rid, perm) VALUES (%d, '%s')", $role->rid, implode(', ', array_keys($form_values[$role->rid])));
1903 drupal_set_message(t('The changes have been saved.'));
1905 // Clear the cached pages and menus:
1911 * Menu callback: administer roles.
1913 function user_admin_role() {
1916 if (DRUPAL_ANONYMOUS_RID == $id || DRUPAL_AUTHENTICATED_RID == $id) {
1917 drupal_goto('admin/user/roles');
1919 // Display the edit role form.
1920 $role = db_fetch_object(db_query('SELECT * FROM {role} WHERE rid = %d', $id));
1921 $form['name'] = array(
1922 '#type' => 'textfield',
1923 '#title' => t('Role name'),
1924 '#default_value' => $role->name,
1926 '#required' => TRUE,
1928 '#description' => t('The name for this role. Example: "moderator", "editorial board", "site architect".'),
1930 $form['rid'] = array(
1934 $form['submit'] = array(
1935 '#type' => 'submit',
1936 '#value' => t('Save role'),
1938 $form['delete'] = array(
1939 '#type' => 'submit',
1940 '#value' => t('Delete role'),
1944 $form['name'] = array(
1945 '#type' => 'textfield',
1949 $form['submit'] = array(
1950 '#type' => 'submit',
1951 '#value' => t('Add role'),
1953 $form['#base'] = 'user_admin_role';
1958 function user_admin_role_validate($form_id, $form_values) {
1959 if ($form_values['name']) {
1960 if ($form_values['op'] == t('Save role')) {
1961 if (db_result(db_query("SELECT COUNT(*) FROM {role} WHERE name = '%s' AND rid != %d", $form_values['name'], $form_values['rid']))) {
1962 form_set_error('name', t('The role name %name already exists. Please choose another role name.', array('%name' => $form_values['name'])));
1965 else if ($form_values['op'] == t('Add role')) {
1966 if (db_result(db_query("SELECT COUNT(*) FROM {role} WHERE name = '%s'", $form_values['name']))) {
1967 form_set_error('name', t('The role name %name already exists. Please choose another role name.', array('%name' => $form_values['name'])));
1972 form_set_error('name', t('You must specify a valid role name.'));
1976 function user_admin_role_submit($form_id, $form_values) {
1977 if ($form_values['op'] == t('Save role')) {
1978 db_query("UPDATE {role} SET name = '%s' WHERE rid = %d", $form_values['name'], $form_values['rid']);
1979 drupal_set_message(t('The role has been renamed.'));
1981 else if ($form_values['op'] == t('Delete role')) {
1982 db_query('DELETE FROM {role} WHERE rid = %d', $form_values['rid']);
1983 db_query('DELETE FROM {permission} WHERE rid = %d', $form_values['rid']);
1984 // Update the users who have this role set:
1985 db_query('DELETE FROM {users_roles} WHERE rid = %d', $form_values['rid']);
1987 drupal_set_message(t('The role has been deleted.'));
1989 else if ($form_values['op'] == t('Add role')) {
1990 db_query("INSERT INTO {role} (name) VALUES ('%s')", $form_values['name']);
1991 drupal_set_message(t('The role has been added.'));
1993 return 'admin/user/roles';
1996 function theme_user_admin_new_role($form) {
1997 $header = array(t('Name'), array('data' => t('Operations'), 'colspan' => 2));
1998 foreach (user_roles() as $rid => $name) {
1999 $edit_permissions = l(t('edit permissions'), 'admin/user/access/'. $rid);
2000 if (!in_array($rid, array(DRUPAL_ANONYMOUS_RID, DRUPAL_AUTHENTICATED_RID))) {
2001 $rows[] = array($name, l(t('edit role'), 'admin/user/roles/edit/'. $rid), $edit_permissions);
2004 $rows[] = array($name, t('locked'), $edit_permissions);
2007 $rows[] = array(drupal_render($form['name']), array('data' => drupal_render($form['submit']), colspan => 2));
2009 $output = drupal_render($form);
2010 $output .= theme('table', $header, $rows);
2015 function user_admin_account() {
2016 $filter = user_build_filter_query();
2020 array('data' => t('Username'), 'field' => 'u.name'),
2021 array('data' => t('Status'), 'field' => 'u.status'),
2023 array('data' => t('Member for'), 'field' => 'u.created', 'sort' => 'desc'),
2024 array('data' => t('Last access'), 'field' => 'u.access'),
2028 $sql = 'SELECT DISTINCT u.uid, u.name, u.status, u.created, u.access FROM {users} u LEFT JOIN {users_roles} ur ON u.uid = ur.uid '. $filter['join'] .' WHERE u.uid != 0 '. $filter['where'];
2029 $sql .= tablesort_sql($header);
2030 $query_count = 'SELECT COUNT(DISTINCT u.uid) FROM {users} u LEFT JOIN {users_roles} ur ON u.uid = ur.uid '. $filter['join'] .' WHERE u.uid != 0 '. $filter['where'];
2031 $result = pager_query($sql, 50, 0, $query_count, $filter['args']);
2033 $form['options'] = array(
2034 '#type' => 'fieldset',
2035 '#title' => t('Update options'),
2036 '#prefix' => '<div class="container-inline">',
2037 '#suffix' => '</div>',
2040 foreach (module_invoke_all('user_operations') as $operation => $array) {
2041 $options[$operation] = $array['label'];
2043 $form['options']['operation'] = array(
2044 '#type' => 'select',
2045 '#options' => $options,
2046 '#default_value' => 'unblock',
2048 $form['options']['submit'] = array(
2049 '#type' => 'submit',
2050 '#value' => t('Update'),
2053 $destination = drupal_get_destination();
2055 $status = array(t('blocked'), t('active'));
2056 $roles = user_roles(1);
2058 while ($account = db_fetch_object($result)) {
2059 $accounts[$account->uid] = '';
2060 $form['name'][$account->uid] = array('#value' => theme('username', $account));
2061 $form['status'][$account->uid] = array('#value' => $status[$account->status]);
2062 $users_roles = array();
2063 $roles_result = db_query('SELECT rid FROM {users_roles} WHERE uid = %d', $account->uid);
2064 while ($user_role = db_fetch_object($roles_result)) {
2065 $users_roles[] = $roles[$user_role->rid];
2067 asort($users_roles);
2068 $form['roles'][$account->uid][0] = array('#value' => theme('item_list', $users_roles));
2069 $form['member_for'][$account->uid] = array('#value' => format_interval(time() - $account->created));
2070 $form['last_access'][$account->uid] = array('#value' => $account->access ? t('@time ago', array('@time' => format_interval(time() - $account->access))) : t('never'));
2071 $form['operations'][$account->uid] = array('#value' => l(t('edit'), "user/$account->uid/edit", array(), $destination));
2073 $form['accounts'] = array(
2074 '#type' => 'checkboxes',
2075 '#options' => $accounts
2077 $form['pager'] = array('#value' => theme('pager', NULL, 50, 0));
2083 * Theme user administration overview.
2085 function theme_user_admin_account($form) {
2088 theme('table_select_header_cell'),
2089 array('data' => t('Username'), 'field' => 'u.name'),
2090 array('data' => t('Status'), 'field' => 'u.status'),
2092 array('data' => t('Member for'), 'field' => 'u.created', 'sort' => 'desc'),
2093 array('data' => t('Last access'), 'field' => 'u.access'),
2097 $output = drupal_render($form['options']);
2098 if (isset($form['name']) && is_array($form['name'])) {
2099 foreach (element_children($form['name']) as $key) {
2101 drupal_render($form['accounts'][$key]),
2102 drupal_render($form['name'][$key]),
2103 drupal_render($form['status'][$key]),
2104 drupal_render($form['roles'][$key]),
2105 drupal_render($form['member_for'][$key]),
2106 drupal_render($form['last_access'][$key]),
2107 drupal_render($form['operations'][$key]),
2112 $rows[] = array(array('data' => t('No users available.'), 'colspan' => '7'));
2115 $output .= theme('table', $header, $rows);
2116 if ($form['pager']['#value']) {
2117 $output .= drupal_render($form['pager']);
2120 $output .= drupal_render($form);
2126 * Submit the user administration update form.
2128 function user_admin_account_submit($form_id, $form_values) {
2129 $operations = module_invoke_all('user_operations');
2130 $operation = $operations[$form_values['operation']];
2131 // Filter out unchecked accounts.
2132 $accounts = array_filter($form_values['accounts']);
2133 if ($function = $operation['callback']) {
2134 // Add in callback arguments if present.
2135 if (isset($operation['callback arguments'])) {
2136 $args = array_merge(array($accounts), $operation['callback arguments']);
2139 $args = array($accounts);
2141 call_user_func_array($function, $args);
2143 cache_clear_all('*', 'cache_menu', TRUE);
2144 drupal_set_message(t('The update has been performed.'));
2148 function user_admin_account_validate($form_id, $form_values) {
2149 $form_values['accounts'] = array_filter($form_values['accounts']);
2150 if (count($form_values['accounts']) == 0) {
2151 form_set_error('', t('No users selected.'));
2156 * Implementation of hook_user_operations().
2158 function user_user_operations() {
2159 global $form_values;
2161 $operations = array(
2163 'label' => t('Unblock the selected users'),
2164 'callback' => 'user_user_operations_unblock',
2167 'label' => t('Block the selected users'),
2168 'callback' => 'user_user_operations_block',
2171 'label' => t('Delete the selected users'),
2175 if (user_access('administer access control')) {
2176 $roles = user_roles(1);
2177 unset($roles[DRUPAL_AUTHENTICATED_RID]); // Can't edit authenticated role.
2179 $add_roles = array();
2180 foreach ($roles as $key => $value) {
2181 $add_roles['add_role-'. $key] = $value;
2184 $remove_roles = array();
2185 foreach ($roles as $key => $value) {
2186 $remove_roles['remove_role-'. $key] = $value;
2189 if (count($roles)) {
2190 $role_operations = array(
2191 t('Add a role to the selected users') => array(
2192 'label' => $add_roles,
2194 t('Remove a role from the selected users') => array(
2195 'label' => $remove_roles,
2199 $operations += $role_operations;
2203 // If the form has been posted, we need to insert the proper data for role editing if necessary.
2205 $operation_rid = explode('-', $form_values['operation']);
2206 $operation = $operation_rid[0];
2207 $rid = $operation_rid[1];
2208 if ($operation == 'add_role' || $operation == 'remove_role') {
2209 if (user_access('administer access control')) {
2210 $operations[$form_values['operation']] = array(
2211 'callback' => 'user_multiple_role_edit',
2212 'callback arguments' => array($operation, $rid),
2216 watchdog('security', t('Detected malicious attempt to alter protected user fields.'), WATCHDOG_WARNING);
2226 * Callback function for admin mass unblocking users.
2228 function user_user_operations_unblock($accounts) {
2229 foreach ($accounts as $uid) {
2230 $account = user_load(array('uid' => (int)$uid));
2231 // Skip unblocking user if they are already unblocked.
2232 if ($account !== FALSE && $account->status == 0) {
2233 user_save($account, array('status' => 1));
2239 * Callback function for admin mass blocking users.
2241 function user_user_operations_block($accounts) {
2242 foreach ($accounts as $uid) {
2243 $account = user_load(array('uid' => (int)$uid));
2244 // Skip blocking user if they are already blocked.
2245 if ($account !== FALSE && $account->status == 1) {
2246 user_save($account, array('status' => 0));
2252 * Callback function for admin mass adding/deleting a user role.
2254 function user_multiple_role_edit($accounts, $operation, $rid) {
2255 // The role name is not necessary as user_save() will reload the user
2256 // object, but some modules' hook_user() may look at this first.
2257 $role_name = db_result(db_query('SELECT name FROM {role} WHERE rid = %d', $rid));
2259 switch ($operation) {
2261 foreach ($accounts as $uid) {
2262 $account = user_load(array('uid' => (int)$uid));
2263 // Skip adding the role to the user if they already have it.
2264 if ($account !== FALSE && !isset($account->roles[$rid])) {
2265 $roles = $account->roles + array($rid => $role_name);
2266 user_save($account, array('roles' => $roles));
2271 foreach ($accounts as $uid) {
2272 $account = user_load(array('uid' => (int)$uid));
2273 // Skip removing the role from the user if they already don't have it.
2274 if ($account !== FALSE && isset($account->roles[$rid])) {
2275 $roles = array_diff($account->roles, array($rid => $role_name));
2276 user_save($account, array('roles' => $roles));
2283 function user_multiple_delete_confirm() {
2286 $form['accounts'] = array('#prefix' => '<ul>', '#suffix' => '</ul>', '#tree' => TRUE);
2287 // array_filter returns only elements with TRUE values
2288 foreach (array_filter($edit['accounts']) as $uid => $value) {
2289 $user = db_result(db_query('SELECT name FROM {users} WHERE uid = %d', $uid));
2290 $form['accounts'][$uid] = array('#type' => 'hidden', '#value' => $uid, '#prefix' => '<li>', '#suffix' => check_plain($user) ."</li>\n");
2292 $form['operation'] = array('#type' => 'hidden', '#value' => 'delete');
2294 return confirm_form($form,
2295 t('Are you sure you want to delete these users?'),
2296 'admin/user/user', t('This action cannot be undone.'),
2297 t('Delete all'), t('Cancel'));
2300 function user_multiple_delete_confirm_submit($form_id, $form_values) {
2301 if ($form_values['confirm']) {
2302 foreach ($form_values['accounts'] as $uid => $value) {
2303 user_delete($form_values, $uid);
2305 drupal_set_message(t('The users have been deleted.'));
2307 return 'admin/user/user';
2310 function user_admin_settings() {
2311 // User registration settings.
2312 $form['registration'] = array('#type' => 'fieldset', '#title' => t('User registration settings'));
2313 $form['registration']['user_register'] = array('#type' => 'radios', '#title' => t('Public registrations'), '#default_value' => variable_get('user_register', 1), '#options' => array(t('Only site administrators can create new user accounts.'), t('Visitors can create accounts and no administrator approval is required.'), t('Visitors can create accounts but administrator approval is required.')));
2314 $form['registration']['user_email_verification'] = array('#type' => 'checkbox', '#title' => t('Require e-mail verification when a visitor creates an account'), '#default_value' => variable_get('user_email_verification', TRUE), '#description' => t('If this box is checked, new users will be required to validate their e-mail address prior to logging into to the site, and will be assigned a system-generated password. With it unchecked, users will be logged in immediately upon registering, and may select their own passwords during registration.'));
2315 $form['registration']['user_registration_help'] = array('#type' => 'textarea', '#title' => t('User registration guidelines'), '#default_value' => variable_get('user_registration_help', ''), '#description' => t("This text is displayed at the top of the user registration form. It's useful for helping or instructing your users."));
2317 // User e-mail settings.
2318 $form['email'] = array('#type' => 'fieldset', '#title' => t('User e-mail settings'));
2319 $form['email']['user_mail_welcome_subject'] = array('#type' => 'textfield', '#title' => t('Subject of welcome e-mail'), '#default_value' => _user_mail_text('welcome_subject'), '#maxlength' => 180, '#description' => t('Customize the subject of your welcome e-mail, which is sent to new members upon registering.') .' '. t('Available variables are:') .' !username, !site, !password, !uri, !uri_brief, !mailto, !date, !login_uri, !edit_uri, !login_url.');
2320 $form['email']['user_mail_welcome_body'] = array('#type' => 'textarea', '#title' => t('Body of welcome e-mail'), '#default_value' => _user_mail_text('welcome_body'), '#rows' => 15, '#description' => t('Customize the body of the welcome e-mail, which is sent to new members upon registering.') .' '. t('Available variables are:') .' !username, !site, !password, !uri, !uri_brief, !mailto, !login_uri, !edit_uri, !login_url.');
2321 $form['email']['user_mail_admin_subject'] = array('#type' => 'textfield', '#title' => t('Subject of welcome e-mail (user created by administrator)'), '#default_value' => _user_mail_text('admin_subject'), '#maxlength' => 180, '#description' => t('Customize the subject of your welcome e-mail, which is sent to new member accounts created by an administrator.') .' '. t('Available variables are:') .' !username, !site, !password, !uri, !uri_brief, !mailto, !date, !login_uri, !edit_uri, !login_url.');
2322 $form['email']['user_mail_admin_body'] = array('#type' => 'textarea', '#title' => t('Body of welcome e-mail (user created by administrator)'), '#default_value' => _user_mail_text('admin_body'), '#rows' => 15, '#description' => t('Customize the body of the welcome e-mail, which is sent to new member accounts created by an administrator.') .' '. t('Available variables are:') .' !username, !site, !password, !uri, !uri_brief, !mailto, !login_uri, !edit_uri, !login_url.');
2323 $form['email']['user_mail_approval_subject'] = array('#type' => 'textfield', '#title' => t('Subject of welcome e-mail (awaiting admin approval)'), '#default_value' => _user_mail_text('approval_subject'), '#maxlength' => 180, '#description' => t('Customize the subject of your awaiting approval welcome e-mail, which is sent to new members upon registering.') .' '. t('Available variables are:') .' !username, !site, !password, !uri, !uri_brief, !mailto, !date, !login_uri, !edit_uri, !login_url.');
2324 $form['email']['user_mail_approval_body'] = array('#type' => 'textarea', '#title' => t('Body of welcome e-mail (awaiting admin approval)'), '#default_value' => _user_mail_text('approval_body'), '#rows' => 15, '#description' => t('Customize the body of the awaiting approval welcome e-mail, which is sent to new members upon registering.') .' '. t('Available variables are:') .' !username, !site, !password, !uri, !uri_brief, !mailto, !login_uri, !edit_uri, !login_url.');
2325 $form['email']['user_mail_pass_subject'] = array('#type' => 'textfield', '#title' => t('Subject of password recovery e-mail'), '#default_value' => _user_mail_text('pass_subject'), '#maxlength' => 180, '#description' => t('Customize the subject of your forgotten password e-mail.') .' '. t('Available variables are:') .' !username, !site, !login_url, !uri, !uri_brief, !mailto, !date, !login_uri, !edit_uri.');
2326 $form['email']['user_mail_pass_body'] = array('#type' => 'textarea', '#title' => t('Body of password recovery e-mail'), '#default_value' => _user_mail_text('pass_body'), '#rows' => 15, '#description' => t('Customize the body of the forgotten password e-mail.') .' '. t('Available variables are:') .' !username, !site, !login_url, !uri, !uri_brief, !mailto, !login_uri, !edit_uri.');
2328 // If picture support is enabled, check whether the picture directory exists:
2329 if (variable_get('user_pictures', 0)) {
2330 $picture_path = file_create_path(variable_get('user_picture_path', 'pictures'));
2331 file_check_directory($picture_path, 1, 'user_picture_path');
2334 $form['pictures'] = array('#type' => 'fieldset', '#title' => t('Pictures'));
2335 $form['pictures']['user_pictures'] = array('#type' => 'radios', '#title' => t('Picture support'), '#default_value' => variable_get('user_pictures', 0), '#options' => array(t('Disabled'), t('Enabled')), '#description' => t('Enable picture support.'));
2336 $form['pictures']['user_picture_path'] = array('#type' => 'textfield', '#title' => t('Picture image path'), '#default_value' => variable_get('user_picture_path', 'pictures'), '#size' => 30, '#maxlength' => 255, '#description' => t('Subdirectory in the directory %dir where pictures will be stored.', array('%dir' => file_directory_path() .'/')));
2337 $form['pictures']['user_picture_default'] = array('#type' => 'textfield', '#title' => t('Default picture'), '#default_value' => variable_get('user_picture_default', ''), '#size' => 30, '#maxlength' => 255, '#description' => t('URL of picture to display for users with no custom picture selected. Leave blank for none.'));
2338 $form['pictures']['user_picture_dimensions'] = array('#type' => 'textfield', '#title' => t('Picture maximum dimensions'), '#default_value' => variable_get('user_picture_dimensions', '85x85'), '#size' => 15, '#maxlength' => 10, '#description' => t('Maximum dimensions for pictures, in pixels.'));
2339 $form['pictures']['user_picture_file_size'] = array('#type' => 'textfield', '#title' => t('Picture maximum file size'), '#default_value' => variable_get('user_picture_file_size', '30'), '#size' => 15, '#maxlength' => 10, '#description' => t('Maximum file size for pictures, in kB.'));
2340 $form['pictures']['user_picture_guidelines'] = array('#type' => 'textarea', '#title' => t('Picture guidelines'), '#default_value' => variable_get('user_picture_guidelines', ''), '#description' => t("This text is displayed at the picture upload form in addition to the default guidelines. It's useful for helping or instructing your users."));
2342 return system_settings_form($form);
2345 function user_admin($callback_arg = '') {
2346 $op = isset($_POST['op']) ? $_POST['op'] : $callback_arg;
2351 $output = drupal_get_form('search_form', url('admin/user/search'), $_POST['keys'], 'user') . search_data($_POST['keys'], 'user');
2353 case t('Create new account'):
2355 $output = drupal_get_form('user_register');
2358 if ($_POST['accounts'] && $_POST['operation'] == 'delete') {
2359 $output = drupal_get_form('user_multiple_delete_confirm');
2362 $output = drupal_get_form('user_filter_form');
2363 $output .= drupal_get_form('user_admin_account');
2370 * Implementation of hook_help().
2372 function user_help($section) {
2376 case 'admin/help#user':
2377 $output = '<p>'. t('The user module allows users to register, login, and log out. Users benefit from being able to sign on because it associates content they create with their account and allows various permissions to be set for their roles. The user module supports user roles which can setup fine grained permissions allowing each role to do only what the administrator wants them to. Each user is assigned to one or more roles. By default there are two roles <em>anonymous</em> - a user who has not logged in, and <em>authenticated</em> a user who has signed up and who has been authorized.') .'</p>';
2378 $output .= '<p>'. t('Users can use their own name or handle and can fine tune some personal configuration settings through their individual my account page. Registered users need to authenticate by supplying either a local username and password, or a remote username and password such as DelphiForums ID, or one from a Drupal powered website. A visitor accessing your website is assigned an unique ID, the so-called session ID, which is stored in a cookie. For security\'s sake, the cookie does not contain personal information but acts as a key to retrieve the information stored on your server.') .'</p>';
2379 $output .= '<p>'. t('For more information please read the configuration and customization handbook <a href="@user">User page</a>.', array('@user' => 'http://drupal.org/handbook/modules/user/')) .'</p>';
2381 case 'admin/user/user':
2382 return '<p>'. t('Drupal allows users to register, login, log out, maintain user profiles, etc. Users of the site may not use their own names to post content until they have signed up for a user account.') .'</p>';
2383 case 'admin/user/user/create':
2384 case 'admin/user/user/account/create':
2385 return '<p>'. t('This web page allows the administrators to register new users by hand. Note that you cannot have a user where either the e-mail address or the username match another user in the system.') .'</p>';
2386 case 'admin/user/rules':
2387 return '<p>'. t('Set up username and e-mail address access rules for new <em>and</em> existing accounts (currently logged in accounts will not be logged out). If a username or e-mail address for an account matches any deny rule, but not an allow rule, then the account will not be allowed to be created or to log in. A host rule is effective for every page view, not just registrations.') .'</p>';
2388 case 'admin/user/access':
2389 return '<p>'. t('Permissions let you control what users can do on your site. Each user role (defined on the <a href="@role">user roles page</a>) has its own set of permissions. For example, you could give users classified as "Administrators" permission to "administer nodes" but deny this power to ordinary, "authenticated" users. You can use permissions to reveal new features to privileged users (those with subscriptions, for example). Permissions also allow trusted users to share the administrative burden of running a busy site.', array('@role' => url('admin/user/roles'))) .'</p>';
2390 case 'admin/user/roles':
2391 return t('<p>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 in <a href="@permissions">user permissions</a>. Examples of roles include: anonymous user, authenticated user, moderator, administrator and so on. In this area you will define the <em>role names</em> of the various roles. To delete a role choose "edit".</p><p>By default, Drupal comes with two user roles:</p>
2393 <li>Anonymous user: this role is used for users that don\'t have a user account or that are not authenticated.</li>
2394 <li>Authenticated user: this role is automatically granted to all logged in users.</li>
2395 </ul>', array('@permissions' => url('admin/user/access')));
2396 case 'admin/user/search':
2397 return '<p>'. t('Enter a simple pattern ("*" may be used as a wildcard match) to search for a username. For example, one may search for "br" and Drupal might return "brian", "brad", and "brenda".') .'</p>';
2398 case 'user/help#user':
2399 $site = variable_get('site_name', 'Drupal');
2401 $affiliates = user_auth_help_links();
2402 if (count($affiliates)) {
2403 $affiliate_info = implode(', ', user_auth_help_links());
2406 $affiliate_info = t('one of our affiliates');
2410 <h3>Distributed authentication<a id="da"></a></h3>
2411 <p>One of the more tedious moments in visiting a new website is filling out the registration form. Here at @site, you do not have to fill out a registration form if you are already a member of !affiliate-info. This capability is called <em>distributed authentication</em>, and <a href="@drupal">Drupal</a>, the software which powers @site, fully supports it.</p>
2412 <p>Distributed authentication enables a new user to input a username and password into the login box, and immediately be recognized, even if that user never registered at @site. This works because Drupal knows how to communicate with external registration databases. For example, lets say that new user \'Joe\' is already a registered member of <a href="@delphi-forums">Delphi Forums</a>. Drupal informs Joe on registration and login screens that he may login with his Delphi ID instead of registering with @site. Joe likes that idea, and logs in with a username of joe@remote.delphiforums.com and his usual Delphi password. Drupal then contacts the <em>remote.delphiforums.com</em> server behind the scenes (usually using <a href="@xml">XML-RPC</a>, <a href="@http-post">HTTP POST</a>, or <a href="@soap">SOAP</a>) and asks: "Is the password for user Joe correct?". If Delphi replies yes, then we create a new @site account for Joe and log him into it. Joe may keep on logging into @site in the same manner, and he will always be logged into the same account.</p>', array('!affiliate-info' => $affiliate_info, '@site' => $site, '@drupal' => 'http://drupal.org', '@delphi-forums' => 'http://www.delphiforums.com', '@xml' => 'http://www.xmlrpc.com', '@http-post' => 'http://www.w3.org/Protocols/', '@soap' => 'http://www.soapware.org'));
2414 foreach (module_list() as $module) {
2415 if (module_hook($module, 'auth')) {
2416 $output .= "<h4><a id=\"$module\"></a>". module_invoke($module, 'info', 'name') .'</h4>';
2417 $output .= module_invoke($module, 'help', "user/help#$module");
2427 * Menu callback; Prints user-specific help information.
2429 function user_help_page() {
2430 return user_help('user/help#user');
2434 * Retrieve a list of all user setting/information categories and sort them by weight.
2436 function _user_categories($account) {
2437 $categories = array();
2439 foreach (module_list() as $module) {
2440 if ($data = module_invoke($module, 'user', 'categories', NULL, $account, '')) {
2441 $categories = array_merge($data, $categories);
2445 usort($categories, '_user_sort');
2450 function _user_sort($a, $b) {
2451 return $a['weight'] < $b['weight'] ? -1 : ($a['weight'] > $b['weight'] ? 1 : ($a['title'] < $b['title'] ? -1 : 1));
2455 * Retrieve a list of all form elements for the specified category.
2457 function _user_forms(&$edit, $account, $category, $hook = 'form') {
2459 foreach (module_list() as $module) {
2460 if ($data = module_invoke($module, 'user', $hook, $edit, $account, $category)) {
2461 $groups = array_merge_recursive($data, $groups);
2464 uasort($groups, '_user_sort');
2466 return empty($groups) ? FALSE : $groups;
2470 * Retrieve a pipe delimited string of autocomplete suggestions for existing users
2472 function user_autocomplete($string = '') {
2475 $result = db_query_range("SELECT name FROM {users} WHERE LOWER(name) LIKE LOWER('%s%%')", $string, 0, 10);
2476 while ($user = db_fetch_object($result)) {
2477 $matches[$user->name] = check_plain($user->name);
2480 print drupal_to_js($matches);
2485 * List user administration filters that can be applied.
2487 function user_filters() {
2490 $roles = user_roles(1);
2491 unset($roles[DRUPAL_AUTHENTICATED_RID]); // Don't list authorized role.
2492 if (count($roles)) {
2493 $filters['role'] = array('title' => t('role'),
2494 'where' => "ur.rid = %d",
2495 'options' => $roles,
2500 $t_module = t('module');
2501 foreach (module_list() as $module) {
2502 if ($permissions = module_invoke($module, 'perm')) {
2503 asort($permissions);
2504 foreach ($permissions as $permission) {
2505 $options["$module $t_module"][$permission] = t($permission);
2510 $filters['permission'] = array('title' => t('permission'),
2511 'join' => 'LEFT JOIN {permission} p ON ur.rid = p.rid',
2512 'where' => " ((p.perm IS NOT NULL AND p.perm LIKE '%%%s%%') OR u.uid = 1) ",
2513 'options' => $options,
2516 $filters['status'] = array('title' => t('status'),
2517 'where' => 'u.status = %d',
2518 'options' => array(1 => t('active'), 0 => t('blocked')),
2524 * Build query for user administration filters based on session.
2526 function user_build_filter_query() {
2527 $filters = user_filters();
2530 $where = $args = $join = array();
2531 foreach ($_SESSION['user_overview_filter'] as $filter) {
2532 list($key, $value) = $filter;
2533 // This checks to see if this permission filter is an enabled permission for the authenticated role.
2534 // If so, then all users would be listed, and we can skip adding it to the filter query.
2535 if ($key == 'permission') {
2536 $account = new stdClass();
2537 $account->uid = 'user_filter';
2538 $account->roles = array(DRUPAL_AUTHENTICATED_RID => 1);
2539 if (user_access($value, $account)) {
2543 $where[] = $filters[$key]['where'];
2545 $join[] = $filters[$key]['join'];
2547 $where = count($where) ? 'AND '. implode(' AND ', $where) : '';
2548 $join = count($join) ? ' '. implode(' ', array_unique($join)) : '';
2550 return array('where' => $where,
2557 * Return form for user administration filters.
2559 function user_filter_form() {
2560 $session = &$_SESSION['user_overview_filter'];
2561 $session = is_array($session) ? $session : array();
2562 $filters = user_filters();
2565 $form['filters'] = array('#type' => 'fieldset',
2566 '#title' => t('Show only users where'),
2567 '#theme' => 'user_filters',
2569 foreach ($session as $filter) {
2570 list($type, $value) = $filter;
2571 // Merge an array of arrays into one if necessary.
2572 $options = $type == 'permission' ? call_user_func_array('array_merge', $filters[$type]['options']) : $filters[$type]['options'];
2573 $params = array('%property' => $filters[$type]['title'] , '%value' => $options[$value]);
2575 $form['filters']['current'][] = array('#value' => t('<em>and</em> where <strong>%property</strong> is <strong>%value</strong>', $params));
2578 $form['filters']['current'][] = array('#value' => t('<strong>%property</strong> is <strong>%value</strong>', $params));
2582 foreach ($filters as $key => $filter) {
2583 $names[$key] = $filter['title'];
2584 $form['filters']['status'][$key] = array('#type' => 'select',
2585 '#options' => $filter['options'],
2589 $form['filters']['filter'] = array('#type' => 'radios',
2590 '#options' => $names,
2592 $form['filters']['buttons']['submit'] = array('#type' => 'submit',
2593 '#value' => (count($session) ? t('Refine') : t('Filter'))
2595 if (count($session)) {
2596 $form['filters']['buttons']['undo'] = array('#type' => 'submit',
2597 '#value' => t('Undo')
2599 $form['filters']['buttons']['reset'] = array('#type' => 'submit',
2600 '#value' => t('Reset')
2608 * Theme user administration filter form.
2610 function theme_user_filter_form($form) {
2611 $output = '<div id="user-admin-filter">';
2612 $output .= drupal_render($form['filters']);
2613 $output .= '</div>';
2614 $output .= drupal_render($form);
2619 * Theme user administration filter selector.
2621 function theme_user_filters($form) {
2622 $output = '<ul class="clear-block">';
2623 if (sizeof($form['current'])) {
2624 foreach (element_children($form['current']) as $key) {
2625 $output .= '<li>'. drupal_render($form['current'][$key]) .'</li>';
2629 $output .= '<li><dl class="multiselect">'. (sizeof($form['current']) ? '<dt><em>'. t('and') .'</em> '. t('where') .'</dt>' : '') .'<dd class="a">';
2630 foreach (element_children($form['filter']) as $key) {
2631 $output .= drupal_render($form['filter'][$key]);
2635 $output .= '<dt>'. t('is') .'</dt><dd class="b">';
2637 foreach (element_children($form['status']) as $key) {
2638 $output .= drupal_render($form['status'][$key]);
2643 $output .= '<div class="container-inline" id="user-admin-buttons">'. drupal_render($form['buttons']) .'</div>';
2644 $output .= '</li></ul>';
2650 * Process result from user administration filter form.
2652 function user_filter_form_submit($form_id, $form_values) {
2653 $op = $form_values['op'];
2654 $filters = user_filters();
2656 case t('Filter'): case t('Refine'):
2657 if (isset($form_values['filter'])) {
2658 $filter = $form_values['filter'];
2659 // Merge an array of arrays into one if necessary.
2660 $options = $filter == 'permission' ? call_user_func_array('array_merge', $filters[$filter]['options']) : $filters[$filter]['options'];
2661 if (isset($options[$form_values[$filter]])) {
2662 $_SESSION['user_overview_filter'][] = array($filter, $form_values[$filter]);
2667 array_pop($_SESSION['user_overview_filter']);
2670 $_SESSION['user_overview_filter'] = array();
2676 return 'admin/user/user';
2680 function user_forms() {
2681 $forms['user_admin_access_add_form']['callback'] = 'user_admin_access_form';
2682 $forms['user_admin_access_edit_form']['callback'] = 'user_admin_access_form';
2683 $forms['user_admin_new_role']['callback'] = 'user_admin_role';