2 // $Id: user.module,v 1.612.2.32 2007/09/13 20:42:42 killes Exp $
6 * Enables the user registration and login system.
10 * Invokes hook_user() in every module.
12 * We cannot use module_invoke() for this, because the arguments need to
13 * be passed by reference.
15 function user_module_invoke($type, &$array, &$user, $category = NULL) {
16 foreach (module_list() as $module) {
17 $function = $module .'_user';
18 if (function_exists($function)) {
19 $function($type, $array, $user, $category);
24 function user_external_load($authname) {
25 $result = db_query("SELECT uid FROM {authmap} WHERE authname = '%s'", $authname);
27 if ($user = db_fetch_object($result)) {
28 return user_load($user);
36 * Fetch a user object.
39 * An associative array of attributes to search for in selecting the
40 * user, such as user name or e-mail address.
43 * A fully-loaded $user object upon successful user load or FALSE if user cannot be loaded.
45 function user_load($array = array()) {
46 // Dynamically compose a SQL query:
50 foreach ($array as $key => $value) {
51 if ($key == 'uid' || $key == 'status') {
52 $query[] = "$key = %d";
55 else if ($key == 'pass') {
56 $query[] = "pass = '%s'";
57 $params[] = md5($value);
60 $query[]= "LOWER($key) = LOWER('%s')";
64 $result = db_query('SELECT * FROM {users} u WHERE ' . implode(' AND ', $query), $params);
66 if (db_num_rows($result)) {
67 $user = db_fetch_object($result);
68 $user = drupal_unpack($user);
70 $user->roles = array();
72 $user->roles[DRUPAL_AUTHENTICATED_RID] = 'authenticated user';
75 $user->roles[DRUPAL_ANONYMOUS_RID] = 'anonymous user';
77 $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);
78 while ($role = db_fetch_object($result)) {
79 $user->roles[$role->rid] = $role->name;
81 user_module_invoke('load', $array, $user);
91 * Save changes to a user account or add a new user.
94 * The $user object for the user to modify or add. If $user->uid is
95 * omitted, a new user will be added.
98 * An array of fields and values to save. For example array('name' => 'My name');
99 * Setting a field to null deletes it from the data column.
102 * (optional) The category for storing profile information in.
104 function user_save($account, $array = array(), $category = 'account') {
105 // Dynamically compose a SQL query:
106 $user_fields = user_fields();
108 user_module_invoke('update', $array, $account, $category);
110 $data = unserialize(db_result(db_query('SELECT data FROM {users} WHERE uid = %d', $account->uid)));
111 foreach ($array as $key => $value) {
112 if ($key == 'pass' && !empty($value)) {
113 $query .= "$key = '%s', ";
116 else if ((substr($key, 0, 4) !== 'auth') && ($key != 'pass')) {
117 if (in_array($key, $user_fields)) {
118 // Save standard fields
119 $query .= "$key = '%s', ";
122 else if ($key != 'roles') {
123 // Roles is a special case: it used below.
124 if ($value === null) {
128 $data[$key] = $value;
133 $query .= "data = '%s' ";
134 $v[] = serialize($data);
136 db_query("UPDATE {users} SET $query WHERE uid = %d", array_merge($v, array($account->uid)));
138 // Reload user roles if provided
139 if (is_array($array['roles'])) {
140 db_query('DELETE FROM {users_roles} WHERE uid = %d', $account->uid);
142 foreach (array_keys($array['roles']) as $rid) {
143 if (!in_array($rid, array(DRUPAL_ANONYMOUS_RID, DRUPAL_AUTHENTICATED_RID))) {
144 db_query('INSERT INTO {users_roles} (uid, rid) VALUES (%d, %d)', $account->uid, $rid);
149 // Delete a blocked user's sessions to kick them if they are online.
150 if (isset($array['status']) && $array['status'] == 0) {
151 db_query('DELETE FROM {sessions} WHERE uid = %d', $account->uid);
154 // Refresh user object
155 $user = user_load(array('uid' => $account->uid));
158 $array['created'] = time();
159 $array['uid'] = db_next_id('{users}_uid');
161 // Note, we wait with saving the data column to prevent module-handled
162 // fields from being saved there. We cannot invoke hook_user('insert') here
163 // because we don't have a fully initialized user object yet.
164 foreach ($array as $key => $value) {
168 $values[] = md5($value);
171 case 'uid': case 'mode': case 'sort':
172 case 'threshold': case 'created': case 'access':
173 case 'login': case 'status':
179 if (substr($key, 0, 4) !== 'auth' && in_array($key, $user_fields)) {
187 db_query('INSERT INTO {users} ('. implode(', ', $fields) .') VALUES ('. implode(', ', $s) .')', $values);
189 // Reload user roles (delete just to be safe).
190 db_query('DELETE FROM {users_roles} WHERE uid = %d', $array['uid']);
191 foreach ((array)$array['roles'] as $rid) {
192 if (!in_array($rid, array(DRUPAL_ANONYMOUS_RID, DRUPAL_AUTHENTICATED_RID))) {
193 db_query('INSERT INTO {users_roles} (uid, rid) VALUES (%d, %d)', $array['uid'], $rid);
197 // Build the initial user object.
198 $user = user_load(array('uid' => $array['uid']));
200 user_module_invoke('insert', $array, $user, $category);
202 // Build and save the serialized data field now
204 foreach ($array as $key => $value) {
205 if ((substr($key, 0, 4) !== 'auth') && ($key != 'roles') && (!in_array($key, $user_fields)) && ($value !== null)) {
206 $data[$key] = $value;
209 db_query("UPDATE {users} SET data = '%s' WHERE uid = %d", serialize($data), $user->uid);
211 // Build the finished user object.
212 $user = user_load(array('uid' => $array['uid']));
215 // Save distributed authentication mappings
217 foreach ($array as $key => $value) {
218 if (substr($key, 0, 4) == 'auth') {
219 $authmaps[$key] = $value;
222 if (sizeof($authmaps) > 0) {
223 user_set_authmaps($user, $authmaps);
230 * Verify the syntax of the given name.
232 function user_validate_name($name) {
233 if (!strlen($name)) return t('You must enter a username.');
234 if (substr($name, 0, 1) == ' ') return t('The username cannot begin with a space.');
235 if (substr($name, -1) == ' ') return t('The username cannot end with a space.');
236 if (ereg(' ', $name)) return t('The username cannot contain multiple spaces in a row.');
237 if (ereg("[^\x80-\xF7 [:alnum:]@_.-]", $name)) return t('The username contains an illegal character.');
238 if (preg_match('/[\x{80}-\x{A0}'. // Non-printable ISO-8859-1 + NBSP
239 '\x{AD}'. // Soft-hyphen
240 '\x{2000}-\x{200F}'. // Various space characters
241 '\x{2028}-\x{202F}'. // Bidirectional text overrides
242 '\x{205F}-\x{206F}'. // Various text hinting characters
243 '\x{FEFF}'. // Byte order mark
244 '\x{FF01}-\x{FF60}'. // Full-width latin
245 '\x{FFF9}-\x{FFFD}'. // Replacement characters
246 '\x{0}]/u', // NULL byte
248 return t('The username contains an illegal character.');
250 if (ereg('@', $name) && !eregi('@([0-9a-z](-?[0-9a-z])*.)+[a-z]{2}([zmuvtg]|fo|me)?$', $name)) return t('The username is not a valid authentication ID.');
251 if (strlen($name) > 56) return t('The username %name is too long: it must be less than 56 characters.', array('%name' => theme('placeholder', $name)));
254 function user_validate_mail($mail) {
255 if (!$mail) return t('You must enter an e-mail address.');
256 if (!valid_email_address($mail)) {
257 return t('The e-mail address %mail is not valid.', array('%mail' => theme('placeholder', $mail)));
261 function user_validate_picture($file, &$edit, $user) {
263 // Initialize the picture:
264 $form_values['picture'] = $user->picture;
266 // Check that uploaded file is an image, with a maximum file size
267 // and maximum height/width.
268 $info = image_get_info($file->filepath);
269 list($maxwidth, $maxheight) = explode('x', variable_get('user_picture_dimensions', '85x85'));
271 if (!$info || !$info['extension']) {
272 form_set_error('picture_upload', t('The uploaded file was not an image.'));
274 else if (image_get_toolkit()) {
275 image_scale($file->filepath, $file->filepath, $maxwidth, $maxheight);
277 else if (filesize($file->filepath) > (variable_get('user_picture_file_size', '30') * 1000)) {
278 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'))));
280 else if ($info['width'] > $maxwidth || $info['height'] > $maxheight) {
281 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'))));
284 if (!form_get_errors()) {
285 if ($file = file_save_upload('picture_upload', variable_get('user_picture_path', 'pictures') .'/picture-'. $user->uid . '.' . $info['extension'], 1)) {
286 $form_values['picture'] = $file->filepath;
289 form_set_error('picture_upload', t("Failed to upload the picture image; the %directory directory doesn't exist.", array('%directory' => '<em>'. variable_get('user_picture_path', 'pictures') .'</em>')));
295 * Generate a random alphanumeric password.
297 function user_password($length = 10) {
298 // This variable contains the list of allowable characters for the
299 // password. Note that the number 0 and the letter 'O' have been
300 // removed to avoid confusion between the two. The same is true
302 $allowable_characters = 'abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789';
304 // Zero-based count of characters in the allowable list:
305 $len = strlen($allowable_characters) - 1;
307 // Declare the password as a blank string.
310 // Loop the number of times specified by $length.
311 for ($i = 0; $i < $length; $i++) {
313 // Each iteration, pick a random character from the
314 // allowable string and append it to the password:
315 $pass .= $allowable_characters[mt_rand(0, $len)];
322 * Determine whether the user has a given privilege.
325 * The permission, such as "administer nodes", being checked for.
327 * (optional) The account to check, if not given use currently logged in user.
330 * boolean TRUE if the current user has the requested permission.
332 * All permission checks in Drupal should go through this function. This
333 * way, we guarantee consistent behavior, and ensure that the superuser
334 * can perform all actions.
336 function user_access($string, $account = NULL) {
338 static $perm = array();
340 if (is_null($account)) {
344 // User #1 has all privileges:
345 if ($account->uid == 1) {
349 // To reduce the number of SQL queries, we cache the user's permissions
350 // in a static variable.
351 if (!isset($perm[$account->uid])) {
352 $result = db_query("SELECT DISTINCT(p.perm) FROM {role} r INNER JOIN {permission} p ON p.rid = r.rid WHERE r.rid IN (%s)", implode(',', array_keys($account->roles)));
354 $perm[$account->uid] = '';
355 while ($row = db_fetch_object($result)) {
356 $perm[$account->uid] .= "$row->perm, ";
360 if (isset($perm[$account->uid])) {
361 return strpos($perm[$account->uid], "$string, ") !== FALSE;
368 * Checks for usernames blocked by user administration
370 * @return boolean true for blocked users, false for active
372 function user_is_blocked($name) {
373 $allow = db_fetch_object(db_query("SELECT * FROM {users} WHERE status = 1 AND name = LOWER('%s')", $name));
374 $deny = db_fetch_object(db_query("SELECT * FROM {users} WHERE status = 0 AND name = LOWER('%s')", $name));
376 return $deny && !$allow;
380 * Send an e-mail message, using Drupal variables and default settings.
381 * More information in the <a href="http://php.net/manual/en/function.mail.php">PHP function reference for mail()</a>
383 * The mail adres or addresses where the message will be send to. The
384 * formatting of this string must comply with RFC 2822. Some examples are:
386 * user@example.com, anotheruser@example.com
387 * User <user@example.com>
388 * User <user@example.com>, Another User <anotheruser@example.com>
390 * Subject of the email to be sent. This must not contain any newline characters, or the mail may not be sent properly.
392 * Message to be sent. Drupal will format the correct line endings for you.
394 * String to be inserted at the end of the email header. This is typically
395 * used to add extra headers (From, Cc, and Bcc). Multiple extra headers
396 * should be separated with a CRLF (\r\n).
397 * <em>When sending mail, the mail must contain a From header.</em>
398 * @return Returns TRUE if the mail was successfully accepted for delivery, FALSE otherwise.
400 function user_mail($mail, $subject, $message, $header) {
401 if (variable_get('smtp_library', '') && file_exists(variable_get('smtp_library', ''))) {
402 include_once './' . variable_get('smtp_library', '');
403 return user_mail_wrapper($mail, $subject, $message, $header);
407 ** Note: if you are having problems with sending mail, or mails look wrong
408 ** when they are received you may have to modify the str_replace to suit
410 ** - \r\n will work under dos and windows.
411 ** - \n will work for linux, unix and BSDs.
412 ** - \r will work for macs.
414 ** According to RFC 2646, it's quite rude to not wrap your e-mails:
416 ** "The Text/Plain media type is the lowest common denominator of
417 ** Internet e-mail, with lines of no more than 997 characters (by
418 ** convention usually no more than 80), and where the CRLF sequence
419 ** represents a line break [MIME-IMT]."
423 ** http://www.rfc-editor.org/rfc/rfc2646.txt
428 mime_header_encode($subject),
429 str_replace("\r", '', $message),
430 "MIME-Version: 1.0\nContent-Type: text/plain; charset=UTF-8; format=flowed\nContent-transfer-encoding: 8Bit\n" . $header
435 function user_fields() {
439 $result = db_query('SELECT * FROM {users} WHERE uid = 1');
440 if (db_num_rows($result)) {
441 $fields = array_keys(db_fetch_array($result));
444 // Make sure we return the default fields at least
445 $fields = array('uid', 'name', 'pass', 'mail', 'picture', 'mode', 'sort', 'threshold', 'theme', 'signature', 'created', 'access', 'login', 'status', 'timezone', 'language', 'init', 'data');
453 * Implementation of hook_perm().
455 function user_perm() {
456 return array('administer access control', 'administer users', 'access user profiles', 'change own username');
460 * Implementation of hook_file_download().
462 * Ensure that user pictures (avatars) are always downloadable.
464 function user_file_download($file) {
465 if (strpos($file, variable_get('user_picture_path', 'pictures') .'/picture-') === 0) {
466 $info = image_get_info(file_create_path($file));
467 return array('Content-type: '. $info['mime_type']);
472 * Implementation of hook_search().
474 function user_search($op = 'search', $keys = null) {
477 if (user_access('access user profiles')) {
481 if (user_access('access user profiles')) {
483 // Replace wildcards with MySQL/PostgreSQL wildcards.
484 $keys = preg_replace('!\*+!', '%', $keys);
485 $result = pager_query("SELECT * FROM {users} WHERE LOWER(name) LIKE LOWER('%%%s%%')", 15, 0, NULL, $keys);
486 while ($account = db_fetch_object($result)) {
487 $find[] = array('title' => $account->name, 'link' => url('user/'. $account->uid));
495 * Implementation of hook_user().
497 function user_user($type, &$edit, &$user, $category = NULL) {
498 if ($type == 'view') {
499 $items[] = array('title' => t('Member for'),
500 'value' => format_interval(time() - $user->created),
504 return array(t('History') => $items);
506 if ($type == 'form' && $category == 'account') {
507 return user_edit_form(arg(1), $edit);
510 if ($type == 'validate' && $category == 'account') {
511 return _user_edit_validate(arg(1), $edit);
514 if ($type == 'submit' && $category == 'account') {
515 return _user_edit_submit(arg(1), $edit);
518 if ($type == 'categories') {
519 return array(array('name' => 'account', 'title' => t('account settings'), 'weight' => 1));
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 == 3) {
538 $period = drupal_map_assoc(array(30, 60, 120, 180, 300, 600, 900, 1800, 2700, 3600, 5400, 7200, 10800, 21600, 43200, 86400), 'format_interval');
539 $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.'));
540 $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.'));
544 else if ($op == 'save' && $delta == 3) {
545 variable_set('user_block_seconds_online', $edit['user_block_seconds_online']);
546 variable_set('user_block_max_list_count', $edit['user_block_max_list_count']);
548 else if ($op == 'view') {
553 // For usability's sake, avoid showing two login forms on one page.
554 if (!$user->uid && !(arg(0) == 'user' && !is_numeric(arg(1)))) {
555 $form['#action'] = url($_GET['q'], drupal_get_destination());
556 $form['#id'] = 'user-login-form';
557 $form['name'] = array('#type' => 'textfield',
558 '#title' => t('Username'),
563 $form['pass'] = array('#type' => 'password',
564 '#title' => t('Password'),
569 $form['submit'] = array('#type' => 'submit',
570 '#value' => t('Log in'),
573 if (variable_get('user_register', 1)) {
574 $items[] = l(t('Create new account'), 'user/register', array('title' => t('Create a new user account.')));
576 $items[] = l(t('Request new password'), 'user/password', array('title' => t('Request new password via e-mail.')));
577 $form['links'] = array('#value' => theme('item_list', $items));
579 $block['subject'] = t('User login');
580 $block['content'] = drupal_get_form('user_login_block', $form, 'user_login');
585 if ($menu = theme('menu_tree')) {
586 $block['subject'] = $user->uid ? check_plain($user->name) : t('Navigation');
587 $block['content'] = $menu;
592 if (user_access('access content')) {
593 // Retrieve a list of new users who have subsequently accessed the site successfully.
594 $result = db_query_range('SELECT uid, name FROM {users} WHERE status != 0 AND access != 0 ORDER BY created DESC', 0, 5);
595 while ($account = db_fetch_object($result)) {
598 $output = theme('user_list', $items);
600 $block['subject'] = t('Who\'s new');
601 $block['content'] = $output;
606 if (user_access('access content')) {
607 // Count users with activity in the past defined period.
608 $time_period = variable_get('user_block_seconds_online', 900);
610 // Perform database queries to gather online user lists.
611 $guests = db_fetch_object(db_query('SELECT COUNT(sid) AS count FROM {sessions} WHERE timestamp >= %d AND uid = 0', time() - $time_period));
612 $users = db_query('SELECT uid, name, access FROM {users} WHERE access >= %d AND uid != 0 ORDER BY access DESC', time() - $time_period);
613 $total_users = db_num_rows($users);
615 // Format the output with proper grammar.
616 if ($total_users == 1 && $guests->count == 1) {
617 $output = t('There is currently %members and %visitors online.', array('%members' => format_plural($total_users, '1 user', '%count users'), '%visitors' => format_plural($guests->count, '1 guest', '%count guests')));
620 $output = t('There are currently %members and %visitors online.', array('%members' => format_plural($total_users, '1 user', '%count users'), '%visitors' => format_plural($guests->count, '1 guest', '%count guests')));
623 // Display a list of currently online users.
624 $max_users = variable_get('user_block_max_list_count', 10);
625 if ($total_users && $max_users) {
628 while ($max_users-- && $account = db_fetch_object($users)) {
632 $output .= theme('user_list', $items, t('Online users'));
635 $block['subject'] = t('Who\'s online');
636 $block['content'] = $output;
643 function theme_user_picture($account) {
644 if (variable_get('user_pictures', 0)) {
645 if ($account->picture && file_exists($account->picture)) {
646 $picture = file_create_url($account->picture);
648 else if (variable_get('user_picture_default', '')) {
649 $picture = variable_get('user_picture_default', '');
652 if (isset($picture)) {
653 $alt = t('%user\'s picture', array('%user' => $account->name ? $account->name : variable_get('anonymous', 'Anonymous')));
654 $picture = theme('image', $picture, $alt, $alt, '', false);
655 if (!empty($account->uid) && user_access('access user profiles')) {
656 $picture = l($picture, "user/$account->uid", array('title' => t('View user profile.')), NULL, NULL, FALSE, TRUE);
659 return "<div class=\"picture\">$picture</div>";
666 * @param $account the user object
667 * @param $fields a multidimensional array for the fields, in the form of array (
668 * 'category1' => array(item_array1, item_array2), 'category2' => array(item_array3,
669 * .. etc.). Item arrays are formatted as array(array('title' => 'item title',
670 * 'value' => 'item value', 'class' => 'class-name'), ... etc.). Module names are incorporated
671 * into the CSS class.
675 function theme_user_profile($account, $fields) {
676 $output = '<div class="profile">';
677 $output .= theme('user_picture', $account);
678 foreach ($fields as $category => $items) {
679 if (strlen($category) > 0) {
680 $output .= '<h2 class="title">'. check_plain($category) .'</h2>';
683 foreach ($items as $item) {
684 if (isset($item['title'])) {
685 $output .= '<dt class="'. $item['class'] .'">'. $item['title'] .'</dt>';
687 $output .= '<dd class="'. $item['class'] .'">'. $item['value'] .'</dd>';
697 * Make a list of users.
698 * @param $items an array with user objects. Should contain at least the name and uid
702 function theme_user_list($users, $title = NULL) {
703 if (!empty($users)) {
704 foreach ($users as $user) {
705 $items[] = theme('username', $user);
708 return theme('item_list', $items, $title);
712 * Implementation of hook_menu().
714 function user_menu($may_cache) {
719 $admin_access = user_access('administer users');
720 $access_access = user_access('administer access control');
721 $view_access = user_access('access user profiles');
724 $items[] = array('path' => 'user', 'title' => t('user account'),
725 'callback' => 'user_login', 'access' => TRUE, 'type' => MENU_CALLBACK);
727 $items[] = array('path' => 'user/autocomplete', 'title' => t('user autocomplete'),
728 'callback' => 'user_autocomplete', 'access' => $view_access, 'type' => MENU_CALLBACK);
730 // Registration and login pages.
731 $items[] = array('path' => 'user/login', 'title' => t('log in'),
732 'callback' => 'user_login', 'type' => MENU_DEFAULT_LOCAL_TASK);
733 $items[] = array('path' => 'user/register', 'title' => t('register'),
734 'callback' => 'user_register', 'access' => $user->uid == 0 && variable_get('user_register', 1), 'type' => MENU_LOCAL_TASK);
735 $items[] = array('path' => 'user/password', 'title' => t('request new password'),
736 'callback' => 'user_pass', 'access' => $user->uid == 0, 'type' => MENU_LOCAL_TASK);
737 $items[] = array('path' => 'user/reset', 'title' => t('reset password'),
738 'callback' => 'user_pass_reset', 'access' => TRUE, 'type' => MENU_CALLBACK);
739 $items[] = array('path' => 'user/help', 'title' => t('help'),
740 'callback' => 'user_help_page', 'type' => MENU_CALLBACK);
743 $items[] = array('path' => 'admin/user', 'title' => t('users'),
744 'callback' => 'user_admin', 'access' => $admin_access);
745 $items[] = array('path' => 'admin/user/list', 'title' => t('list'),
746 'type' => MENU_DEFAULT_LOCAL_TASK, 'weight' => -10);
747 $items[] = array('path' => 'admin/user/create', 'title' => t('add user'),
748 'callback' => 'user_admin', 'access' => $admin_access,
749 'type' => MENU_LOCAL_TASK);
750 $items[] = array('path' => 'admin/settings/user', 'title' => t('users'),
751 'callback' => 'user_configure');
753 // Admin access pages
754 $items[] = array('path' => 'admin/access', 'title' => t('access control'),
755 'callback' => 'user_admin_perm', 'access' => $access_access);
756 $items[] = array('path' => 'admin/access/permissions', 'title' => t('permissions'),
757 'callback' => 'user_admin_perm', 'access' => $access_access,
758 'type' => MENU_DEFAULT_LOCAL_TASK, 'weight' => -10);
759 $items[] = array('path' => 'admin/access/roles', 'title' => t('roles'),
760 'callback' => 'user_admin_role', 'access' => $access_access,
761 'type' => MENU_LOCAL_TASK);
762 $items[] = array('path' => 'admin/access/roles/edit', 'title' => t('edit role'),
763 'callback' => 'user_admin_role', 'access' => $access_access,
764 'type' => MENU_CALLBACK);
765 $items[] = array('path' => 'admin/access/rules', 'title' => t('access rules'),
766 'callback' => 'user_admin_access', 'access' => $access_access,
767 'type' => MENU_LOCAL_TASK, 'weight' => 10);
768 $items[] = array('path' => 'admin/access/rules/list', 'title' => t('list'),
769 'access' => $access_access, 'type' => MENU_DEFAULT_LOCAL_TASK, 'weight' => -10);
770 $items[] = array('path' => 'admin/access/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/access/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/access/rules/edit', 'title' => t('edit rule'),
777 'callback' => 'user_admin_access_edit', 'access' => $access_access,
778 'type' => MENU_CALLBACK);
779 $items[] = array('path' => 'admin/access/rules/delete', 'title' => t('delete rule'),
780 'callback' => 'user_admin_access_delete', 'access' => $access_access,
781 'type' => MENU_CALLBACK);
783 if (module_exist('search')) {
784 $items[] = array('path' => 'admin/user/search', 'title' => t('search'),
785 'callback' => 'user_admin', 'access' => $admin_access,
786 'type' => MENU_LOCAL_TASK);
789 // Your personal page
791 $items[] = array('path' => 'user/'. $user->uid, 'title' => t('my account'),
792 'callback' => 'user_view', 'callback arguments' => array(arg(1)), 'access' => TRUE,
793 'type' => MENU_DYNAMIC_ITEM);
796 $items[] = array('path' => 'logout', 'title' => t('log out'),
797 'access' => $user->uid != 0,
798 'callback' => 'user_logout',
802 if (arg(0) == 'user' && is_numeric(arg(1)) && arg(1) > 0) {
803 $account = user_load(array('uid' => arg(1)));
805 if ($user !== FALSE) {
806 // Always let a user view their own account
807 $view_access |= $user->uid == arg(1);
808 // Only admins can view blocked accounts
809 $view_access &= $account->status || $admin_access;
811 $items[] = array('path' => 'user/'. arg(1), 'title' => t('user'),
812 'type' => MENU_CALLBACK, 'callback' => 'user_view',
813 'callback arguments' => array(arg(1)), 'access' => $view_access);
815 $items[] = array('path' => 'user/'. arg(1) .'/view', 'title' => t('view'),
816 'access' => $view_access, 'type' => MENU_DEFAULT_LOCAL_TASK, 'weight' => -10);
818 $items[] = array('path' => 'user/'. arg(1) .'/edit', 'title' => t('edit'),
819 'callback' => 'user_edit', 'access' => $admin_access || $user->uid == arg(1),
820 'type' => MENU_LOCAL_TASK);
821 $items[] = array('path' => 'user/'. arg(1) .'/delete', 'title' => t('delete'),
822 'callback' => 'user_edit', 'access' => $admin_access,
823 'type' => MENU_CALLBACK);
825 if (arg(2) == 'edit') {
826 if (($categories = _user_categories($account)) && (count($categories) > 1)) {
827 foreach ($categories as $key => $category) {
829 'path' => 'user/'. arg(1) .'/edit/'. $category['name'],
830 'title' => $category['title'],
831 'type' => $category['name'] == 'account' ? MENU_DEFAULT_LOCAL_TASK : MENU_LOCAL_TASK,
832 'weight' => $category['weight'],
833 'access' => ($admin_access || $user->uid == arg(1)));
845 * Accepts an user object, $account, or a DA name and returns an associative
846 * array of modules and DA names. Called at external login.
848 function user_get_authmaps($authname = NULL) {
849 $result = db_query("SELECT authname, module FROM {authmap} WHERE authname = '%s'", $authname);
850 if (db_num_rows($result) > 0) {
851 while ($authmap = db_fetch_object($result)) {
852 $authmaps[$authmap->module] = $authmap->authname;
861 function user_set_authmaps($account, $authmaps) {
862 foreach ($authmaps as $key => $value) {
863 $module = explode('_', $key, 2);
865 db_query("UPDATE {authmap} SET authname = '%s' WHERE uid = %d AND module = '%s'", $value, $account->uid, $module['1']);
866 if (!db_affected_rows()) {
867 db_query("INSERT INTO {authmap} (authname, uid, module) VALUES ('%s', %d, '%s')", $value, $account->uid, $module[1]);
871 db_query("DELETE FROM {authmap} WHERE uid = %d AND module = '%s'", $account->uid, $module['1']);
876 function user_auth_help_links() {
878 foreach (module_list() as $module) {
879 if (module_hook($module, 'auth')) {
880 $links[] = l(module_invoke($module, 'info', 'name'), "user/help#$module");
886 /*** User features *********************************************************/
888 // disabling user management
889 function user_functions_disabled_message () {
890 return "Drupal native user management functions are disabled";
893 function user_login($msg = '') {
895 return user_functions_disabled_message();
897 global $user, $base_url;
899 // If we are already logged on, go to the user page instead
901 drupal_goto('user/'. $user->uid);
904 // Display login form:
906 $form['message'] = array('#value' => '<p>'. check_plain($msg) .'</p>');
908 unset($_GET['time']);
909 $form['#action'] = url($_GET['q'], drupal_get_destination());
910 $form['name'] = array('#type' => 'textfield',
911 '#title' => t('Username'),
915 '#attributes' => array('tabindex' => '1'),
917 if (variable_get('drupal_authentication_service', FALSE) && count(user_auth_help_links()) > 0) {
918 $form['name']['#description'] = t('Enter your %s username, or an ID from one of our affiliates: %a.', array('%s' => variable_get('site_name', 'local'), '%a' => implode(', ', user_auth_help_links())));
921 $form['name']['#description'] = t('Enter your %s username.', array('%s' => variable_get('site_name', 'local')));
923 $form['pass'] = array('#type' => 'password',
924 '#title' => t('Password'),
925 '#description' => t('Enter the password that accompanies your username.'),
927 '#attributes' => array('tabindex' => '2'),
929 $form['submit'] = array('#type' => 'submit', '#value' => t('Log in'), '#weight' => 2, '#attributes' => array('tabindex' => '3'));
930 return drupal_get_form('user_login', $form);
933 function user_login_validate($form_id, $form_values) {
934 if ($form_values['name']) {
935 if (user_is_blocked($form_values['name'])) {
936 // blocked in user administration
937 form_set_error('name', t('The username %name has not been activated or is blocked.', array('%name' => theme('placeholder', $form_values['name']))));
939 else if (drupal_is_denied('user', $form_values['name'])) {
940 // denied by access controls
941 form_set_error('name', t('The name %name is a reserved username.', array('%name' => theme('placeholder', $form_values['name']))));
943 else if ($form_values['pass']) {
944 $user = user_authenticate($form_values['name'], trim($form_values['pass']));
947 form_set_error('name', t('Sorry. Unrecognized username or password.') .' '. l(t('Have you forgotten your password?'), 'user/password'));
948 watchdog('user', t('Login attempt failed for %user.', array('%user' => theme('placeholder', $form_values['name']))));
954 function user_login_submit($form_id, $form_values) {
957 // To handle the edge case where this function is called during a
958 // bootstrap, check for the existence of t().
959 if (function_exists('t')) {
960 $message = t('Session opened for %name.', array('%name' => theme('placeholder', $user->name)));
963 $message = "Session opened for ". check_plain($user->name);
965 watchdog('user', $message);
967 // Update the user table timestamp noting user has logged in.
968 db_query("UPDATE {users} SET login = %d WHERE uid = %d", time(), $user->uid);
970 user_module_invoke('login', $form_values, $user);
973 return 'user/'. $user->uid;
977 function user_authenticate($name, $pass) {
980 // Try to log in the user locally. Don't set $user unless successful.
981 if ($account = user_load(array('name' => $name, 'pass' => $pass, 'status' => 1))) {
985 // Strip name and server from ID:
986 if ($server = strrchr($name, '@')) {
987 $name = substr($name, 0, strlen($name) - strlen($server));
988 $server = substr($server, 1);
991 // When possible, determine corresponding external auth source. Invoke
992 // source, and log in user if successful:
993 if (!$user->uid && $server && $result = user_get_authmaps("$name@$server")) {
994 if (module_invoke(key($result), 'auth', $name, $pass, $server)) {
995 $user = user_external_load("$name@$server");
996 watchdog('user', t('External load by %user using module %module.', array('%user' => theme('placeholder', $name .'@'. $server), '%module' => theme('placeholder', key($result)))));
999 $error = t('Invalid password for %s.', array('%s' => theme('placeholder', $name .'@'. $server)));
1003 // Try each external authentication source in series. Register user if
1005 else if (!$user->uid && $server) {
1006 foreach (module_list() as $module) {
1007 if (module_hook($module, 'auth')) {
1008 if (module_invoke($module, 'auth', $name, $pass, $server)) {
1009 if (variable_get('user_register', 1) == 1) {
1010 $account = user_load(array('name' => "$name@$server"));
1011 if (!$account->uid) { // Register this new user.
1012 $user = user_save('', array('name' => "$name@$server", 'pass' => user_password(), 'init' => "$name@$server", 'status' => 1, "authname_$module" => "$name@$server"));
1013 watchdog('user', t('New external user: %user using module %module.', array('%user' => theme('placeholder', $name .'@'. $server), '%module' => theme('placeholder', $module))), WATCHDOG_NOTICE, l(t('edit'), 'user/'. $user->uid .'/edit'));
1025 * Menu callback; logs the current user out, and redirects to the home page.
1027 function user_logout() {
1030 watchdog('user', t('Session closed for %name.', array('%name' => theme('placeholder', $user->name))));
1032 // Destroy the current session:
1034 module_invoke_all('user', 'logout', NULL, $user);
1036 // We have to use $GLOBALS to unset a global variable:
1037 $user = user_load(array('uid' => 0));
1042 function user_pass() {
1044 return user_functions_disabled_message();
1047 $form['name'] = array('#type' => 'textfield',
1048 '#title' => t('Username'),
1052 $form['mail'] = array('#type' => 'textfield',
1053 '#title' => t('E-mail address'),
1057 $form['submit'] = array('#type' => 'submit',
1058 '#value' => t('E-mail new password'),
1061 return drupal_get_form('user_pass', $form);
1064 function user_pass_validate() {
1065 global $form_values;
1067 $name = $form_values['name'];
1068 $mail = $form_values['mail'];
1069 if ($name && !($form_values['account'] = user_load(array('name' => $name, 'status' => 1)))) {
1070 form_set_error('name', t('Sorry. The username %name is not recognized.', array('%name' => theme('placeholder', $name))));
1072 else if ($mail && !($form_values['account'] = user_load(array('mail' => $mail, 'status' => 1)))) {
1073 form_set_error('mail', t('Sorry. The e-mail address %email is not recognized.', array('%email' => theme('placeholder', $mail))));
1075 else if (!$mail && !$name) {
1076 form_set_error('password', t('You must provide either a username or e-mail address.'));
1080 function user_pass_submit($form_id, $form_values) {
1083 $account = $form_values['account'];
1084 $from = variable_get('site_mail', ini_get('sendmail_from'));
1086 // Mail one time login URL and instructions.
1087 $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));
1088 $subject = _user_mail_text('pass_subject', $variables);
1089 $body = _user_mail_text('pass_body', $variables);
1090 $headers = "From: $from\nReply-to: $from\nX-Mailer: Drupal\nReturn-path: $from\nErrors-to: $from";
1091 $mail_success = user_mail($account->mail, $subject, $body, $headers);
1093 if ($mail_success) {
1094 watchdog('user', t('Password reset instructions mailed to %name at %email.', array('%name' => theme('placeholder', $account->name), '%email' => theme('placeholder', $account->mail))));
1095 drupal_set_message(t('Further instructions have been sent to your e-mail address.'));
1098 watchdog('user', t('Error mailing password reset instructions to %name at %email.', array('%name' => theme('placeholder', $account->name), '%email' => theme('placeholder', $account->mail))), WATCHDOG_ERROR);
1099 drupal_set_message(t('Unable to send mail. Please contact the site admin.'));
1104 function theme_user_pass($form) {
1105 $output = '<p>'. t('Enter your username <strong><em>or</em></strong> your e-mail address.') .'</p>';
1106 $output .= form_render($form);
1111 * Menu callback; process one time login link and redirects to the user page on success.
1113 function user_pass_reset($uid, $timestamp, $hashed_pass, $action = NULL) {
1116 // Check if the user is already logged in. The back button is often the culprit here.
1118 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.'));
1122 // Time out, in seconds, until login URL expires. 24 hours = 86400 seconds.
1125 // Some redundant checks for extra security ?
1126 if ($timestamp < $current && $account = user_load(array('uid' => $uid, 'status' => 1)) ) {
1127 // No time out for first time login.
1128 if ($account->login && $current - $timestamp > $timeout) {
1129 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.'));
1130 drupal_goto('user/password');
1132 else if ($account->uid && $timestamp > $account->login && $timestamp < $current && $hashed_pass == user_pass_rehash($account->pass, $timestamp, $account->login)) {
1133 // First stage is a confirmation form, then login
1134 if ($action == 'login') {
1135 watchdog('user', t('User %name used one-time login link at time %timestamp.', array('%name' => theme('placeholder', $account->name), '%timestamp' => theme('placeholder', $timestamp))));
1136 // Update the user table noting user has logged in.
1137 // And this also makes this hashed password a one-time-only login.
1138 db_query("UPDATE {users} SET login = %d WHERE uid = %d", time(), $account->uid);
1139 // Now we can set the new user.
1141 // And proceed with normal login, going to user page.
1142 user_module_invoke('login', $edit, $user);
1143 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.'));
1144 drupal_goto('user/'. $user->uid .'/edit');
1147 $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' => theme('placeholder',$account->name), '%expiration_date' => format_date($timestamp + $timeout))));
1148 $form['help'] = array('#value' => t('<p>This login can be used only once.</p>'));
1149 $form['submit'] = array('#type' => 'submit', '#value' => t('Log in'));
1150 $form['#action'] = url("user/reset/$uid/$timestamp/$hashed_pass/login");
1151 return drupal_get_form('user_pass_reset', $form);
1155 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.'));
1156 drupal_goto('user/password');
1160 // Deny access, no more clues.
1161 // Everything will be in the watchdog's URL for the administrator to check.
1162 drupal_access_denied();
1167 function user_pass_reset_url($account) {
1168 $timestamp = time();
1169 return url("user/reset/$account->uid/$timestamp/".user_pass_rehash($account->pass, $timestamp, $account->login), NULL, NULL, TRUE);
1172 function user_pass_rehash($password, $timestamp, $login) {
1173 return md5($timestamp . $password . $login);
1176 function user_register() {
1178 return user_functions_disabled_message();
1182 $admin = user_access('administer users');
1184 // If we aren't admin but already logged on, go to the user page instead.
1185 if (!$admin && $user->uid) {
1186 drupal_goto('user/'. $user->uid);
1189 // Display the registration form.
1191 $form['user_registration_help'] = array('#type' => 'markup', '#value' => filter_xss_admin(variable_get('user_registration_help', '')));
1193 $affiliates = user_auth_help_links();
1194 if (!$admin && count($affiliates) > 0) {
1195 $affiliates = implode(', ', $affiliates);
1196 $form['affiliates'] = array('#type' => 'markup', '#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>');
1198 $form['name'] = array('#type' => 'textfield',
1199 '#title' => t('Username'),
1202 '#description' => t('Your full name or your preferred username; only letters, numbers and spaces are allowed.'),
1203 '#required' => TRUE);
1204 $form['mail'] = array('#type' => 'textfield',
1205 '#title' => t('E-mail address'),
1208 '#description' => t('A password and instructions will be sent to this e-mail address, so make sure it is accurate.'),
1209 '#required' => TRUE,
1212 $form['pass'] = array('#type' => 'password',
1213 '#title' => t('Password'),
1215 '#description' => t('Provide a password for the new account.'),
1216 '#required' => TRUE,
1218 $form['notify'] = array(
1219 '#type' => 'checkbox',
1220 '#title' => t('Notify user of new account')
1223 $extra = _user_forms($null, $null, $null, 'register');
1225 // Only display form_group around default fields if there are other groups.
1227 $form['account'] = array('#type' => 'fieldset', '#title' => t('Account information'));
1228 $form['account']['name'] = $form['name'];
1229 $form['account']['mail'] = $form['mail'];
1230 $form['account']['pass'] = $form['pass'];
1231 $form['account']['notify'] = $form['notify'];
1232 unset($form['name'], $form['mail'], $form['pass'], $form['notify']);
1233 $form = array_merge($form, $extra);
1235 $form['submit'] = array('#type' => 'submit', '#value' => t('Create new account'), '#weight' => 30);
1237 return drupal_get_form('user_register', $form);
1240 function user_register_validate($form_id, $form_values) {
1241 user_module_invoke('validate', $form_values, $form_values, 'account');
1244 function user_register_submit($form_id, $form_values) {
1247 $admin = user_access('administer users');
1249 $mail = $form_values['mail'];
1250 $name = $form_values['name'];
1251 $pass = $admin ? $form_values['pass'] : user_password();
1252 $notify = $form_values['notify'];
1253 $from = variable_get('site_mail', ini_get('sendmail_from'));
1255 if (!$admin && array_intersect(array_keys($form_values), array('uid', 'roles', 'init', 'session', 'status'))) {
1256 watchdog('security', t('Detected malicious attempt to alter protected user fields.'), WATCHDOG_WARNING);
1257 return 'user/register';
1259 //the unset below is needed to prevent these form values from being saved as user data
1260 unset($form_values['form_token'], $form_values['submit'], $form_values['op'], $form_values['notify'], $form_values['form_id'], $form_values['affiliates'], $form_values['destination']);
1262 $account = user_save('', array_merge($form_values, array('pass' => $pass, 'init' => $mail, 'status' => ($admin || variable_get('user_register', 1) == 1))));
1263 watchdog('user', t('New user: %name %email.', array('%name' => theme('placeholder', $name), '%email' => theme('placeholder', '<'. $mail .'>'))), WATCHDOG_NOTICE, l(t('edit'), 'user/'. $account->uid .'/edit'));
1265 $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));
1267 // The first user may login immediately, and receives a customized welcome e-mail.
1268 if ($account->uid == 1) {
1269 user_mail($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: $from\nReply-to: $from\nX-Mailer: Drupal\nReturn-path: $from\nErrors-to: $from");
1270 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">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'))));
1271 user_authenticate($account->name, trim($pass));
1273 // Set the installed schema version of the system module to the most recent version.
1274 include_once './includes/install.inc';
1275 drupal_set_installed_schema_version('system', max(drupal_get_schema_versions('system')));
1277 return 'user/1/edit';
1280 if ($admin && !$notify) {
1281 drupal_set_message(t('Created a new user account. No e-mail has been sent.'));
1283 return 'admin/user';
1285 else if ($account->status || $notify) {
1286 // Create new user account, no administrator approval required.
1287 $subject = $notify ? _user_mail_text('admin_subject', $variables) : _user_mail_text('welcome_subject', $variables);
1288 $body = $notify ? _user_mail_text('admin_body', $variables) : _user_mail_text('welcome_body', $variables);
1290 user_mail($mail, $subject, $body, "From: $from\nReply-to: $from\nX-Mailer: Drupal\nReturn-path: $from\nErrors-to: $from");
1293 drupal_set_message(t('Password and further instructions have been e-mailed to the new user %user.', array('%user' => theme('placeholder', $name))));
1294 return 'admin/user';
1297 drupal_set_message(t('Your password and further instructions have been sent to your e-mail address.'));
1302 // Create new user account, administrator approval required.
1303 $subject = _user_mail_text('approval_subject', $variables);
1304 $body = _user_mail_text('approval_body', $variables);
1306 user_mail($mail, $subject, $body, "From: $from\nReply-to: $from\nX-Mailer: Drupal\nReturn-path: $from\nErrors-to: $from");
1307 user_mail(variable_get('site_mail', ini_get('sendmail_from')), $subject, t("%u has applied for an account.\n\n%uri", array('%u' => $account->name, '%uri' => url("user/$account->uid/edit", NULL, NULL, TRUE))), "From: $from\nReply-to: $from\nX-Mailer: Drupal\nReturn-path: $from\nErrors-to: $from");
1308 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.'));
1314 function user_edit_form($uid, $edit) {
1316 return user_functions_disabled_message();
1318 // Account information:
1319 $form['account'] = array('#type' => 'fieldset',
1320 '#title' => t('Account information'),
1322 if (user_access('change own username') || user_access('administer users')) {
1323 $form['account']['name'] = array('#type' => 'textfield',
1324 '#title' => t('Username'),
1325 '#default_value' => $edit['name'],
1327 '#description' => t('Your full name or your preferred username: only letters, numbers and spaces are allowed.'),
1328 '#required' => TRUE,
1331 $form['account']['mail'] = array('#type' => 'textfield',
1332 '#title' => t('E-mail address'),
1333 '#default_value' => $edit['mail'],
1335 '#description' => t('Insert 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.'),
1336 '#required' => TRUE,
1338 $form['account']['pass'] = array('#type' => 'password_confirm',
1339 '#title' => t('Password'),
1340 '#description' => t('To change the current user password, enter the new password in both fields.'),
1342 if (user_access('administer users')) {
1343 $form['account']['status'] = array('#type' => 'radios', '#title' => t('Status'), '#default_value' => $edit['status'], '#options' => array(t('Blocked'), t('Active')));
1345 if (user_access('administer access control')) {
1346 $roles = user_roles(1);
1347 unset($roles[DRUPAL_AUTHENTICATED_RID]);
1349 $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' => theme('placeholder', t('authenticated user')))));
1354 if (variable_get('user_pictures', 0)) {
1355 $form['picture'] = array('#type' => 'fieldset', '#title' => t('Picture'), '#weight' => 1);
1356 $picture = theme('user_picture', (object)$edit);
1358 $form['picture']['current_picture'] = array('#type' => 'markup', '#value' => $picture);
1359 $form['picture']['picture_delete'] = array('#type' => 'checkbox', '#title' => t('Delete picture'), '#description' => t('Check this box to delete your current picture.'));
1361 $form['picture']['picture_delete'] = array('#type' => 'hidden');
1363 $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', ''));
1369 function _user_edit_validate($uid, &$edit) {
1370 $user = user_load(array('uid' => $uid));
1371 // Validate the username:
1372 if (user_access('change own username') || user_access('administer users') || arg(1) == 'register') {
1373 if ($error = user_validate_name($edit['name'])) {
1374 form_set_error('name', $error);
1376 else if (db_num_rows(db_query("SELECT uid FROM {users} WHERE uid != %d AND LOWER(name) = LOWER('%s')", $uid, $edit['name'])) > 0) {
1377 form_set_error('name', t('The name %name is already taken.', array('%name' => theme('placeholder', $edit['name']))));
1379 else if (drupal_is_denied('user', $edit['name'])) {
1380 form_set_error('name', t('The name %name has been denied access.', array('%name' => theme('placeholder', $edit['name']))));
1384 // Validate the e-mail address:
1385 if ($error = user_validate_mail($edit['mail'])) {
1386 form_set_error('mail', $error);
1388 else if (db_num_rows(db_query("SELECT uid FROM {users} WHERE uid != %d AND LOWER(mail) = LOWER('%s')", $uid, $edit['mail'])) > 0) {
1389 form_set_error('mail', t('The e-mail address %email is already taken.', array('%email' => theme('placeholder', $edit['mail']))));
1391 else if (drupal_is_denied('mail', $edit['mail'])) {
1392 form_set_error('mail', t('The e-mail address %email has been denied access.', array('%email' => theme('placeholder', $edit['mail']))));
1395 // If required, validate the uploaded picture.
1396 if ($file = file_check_upload('picture_upload')) {
1397 user_validate_picture($file, $edit, $user);
1401 function _user_edit_submit($uid, &$edit) {
1402 $user = user_load(array('uid' => $uid));
1403 // Delete picture if requested, and if no replacement picture was given.
1404 if ($edit['picture_delete']) {
1405 if ($user->picture && file_exists($user->picture)) {
1406 file_delete($user->picture);
1408 $edit['picture'] = '';
1410 if (isset($edit['roles'])) {
1411 $edit['roles'] = array_filter($edit['roles']);
1415 function user_edit($category = 'account') {
1418 $account = user_load(array('uid' => arg(1)));
1419 if ($account === FALSE) {
1420 drupal_set_message(t('The account does not exist or has already been deleted.'));
1421 drupal_goto('admin/user');
1423 $edit = $_POST['op'] ? $_POST['edit'] : (array)$account;
1425 if (arg(2) == 'delete') {
1427 $form['account'] = array('#type' => 'value', '#value' => $account);
1428 return confirm_form('user_confirm_delete', $form, t('Are you sure you want to delete the account %name?', array('%name' => theme('placeholder', $account->name))), 'user/'. $account->uid, t('All submissions made by this user will be attributed to the anonymous account. This action cannot be undone.'), t('Delete'), t('Cancel'));
1430 else if ($_POST['op'] == t('Delete')) {
1431 if ($_REQUEST['destination']) {
1432 $destination = drupal_get_destination();
1433 unset($_REQUEST['destination']);
1435 // Note: we redirect from user/uid/edit to user/uid/delete to make the tabs disappear.
1436 drupal_goto("user/$account->uid/delete", $destination);
1439 $form = _user_forms($edit, $account, $category);
1440 $form['_category'] = array('#type' => 'value', '#value' => $category);
1441 $form['_account'] = array('#type' => 'value', '#value' => $account);
1442 $form['submit'] = array('#type' => 'submit', '#value' => t('Submit'), '#weight' => 30);
1443 if (user_access('administer users')) {
1444 $form['delete'] = array('#type' => 'submit', '#value' => t('Delete'), '#weight' => 31);
1446 $form['#attributes']['enctype'] = 'multipart/form-data';
1448 drupal_set_title(check_plain($account->name));
1449 return drupal_get_form('user_edit', $form);
1452 function user_edit_validate($form_id, $form_values) {
1453 user_module_invoke('validate', $form_values, $form_values['_account'], $form_values['_category']);
1454 // Validate input to ensure that non-privileged users can't alter protected data.
1455 if ((!user_access('administer users') && array_intersect(array_keys($form_values), array('uid', 'init', 'session'))) || (!user_access('administer access control') && isset($form_values['roles']))) {
1456 $message = t('Detected malicious attempt to alter protected user fields.');
1457 watchdog('security', $message, WATCHDOG_WARNING);
1458 // set this to a value type field
1459 form_set_error('category', $message);
1463 function user_edit_submit($form_id, $form_values) {
1464 $account = $form_values['_account'];
1465 $category = $form_values['_category'];
1466 unset($form_values['_account'], $form_values['op'], $form_values['submit'], $form_values['delete'], $form_values['form_token'], $form_values['form_id'], $form_values['_category']);
1467 user_module_invoke('submit', $form_values, $account, $category);
1468 user_save($account, $form_values, $category);
1469 // Delete that user's menu cache.
1470 cache_clear_all('menu:'. $account->uid, TRUE);
1471 drupal_set_message(t('The changes have been saved.'));
1472 return 'user/'. $account->uid;
1475 function user_confirm_delete_submit($form_id, $form_values) {
1476 $account = $form_values['account'];
1477 db_query('DELETE FROM {users} WHERE uid = %d', $account->uid);
1478 db_query('DELETE FROM {sessions} WHERE uid = %d', $account->uid);
1479 db_query('DELETE FROM {users_roles} WHERE uid = %d', $account->uid);
1480 db_query('DELETE FROM {authmap} WHERE uid = %d', $account->uid);
1481 watchdog('user', t('Deleted user: %name %email.', array('%name' => theme('placeholder', $account->name), '%email' => theme('placeholder', '<'. $account->mail .'>'))), WATCHDOG_NOTICE);
1482 drupal_set_message(t('The account has been deleted.'));
1483 module_invoke_all('user', 'delete', $form_values, $account);
1484 return 'admin/user';
1487 function user_view($uid = 0) {
1490 $account = user_load(array('uid' => $uid));
1491 if ($account === FALSE || ($account->access == 0 && !user_access('administer users'))) {
1492 return drupal_not_found();
1494 // Retrieve and merge all profile fields:
1496 foreach (module_list() as $module) {
1497 if ($data = module_invoke($module, 'user', 'view', '', $account)) {
1498 foreach ($data as $category => $items) {
1499 foreach ($items as $item) {
1500 $item['class'] = "$module-". $item['class'];
1501 $fields[$category][] = $item;
1506 drupal_set_title(check_plain($account->name));
1507 return theme('user_profile', $account, $fields);
1510 /*** Administrative features ***********************************************/
1512 function _user_mail_text($messageid, $variables = array()) {
1514 // Check if an admin setting overrides the default string.
1515 if ($admin_setting = variable_get('user_mail_' . $messageid, FALSE)) {
1516 return strtr($admin_setting, $variables);
1518 // No override, return with default strings.
1520 switch ($messageid) {
1521 case 'welcome_subject':
1522 return t('Account details for %username at %site', $variables);
1523 case 'welcome_body':
1524 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\nYour new %site membership also enables to you to login to other Drupal powered websites (e.g. http://drupal.org/) without registering. Just use the following Drupal ID and password:\n\nDrupal ID: %username@%uri_brief\npassword: %password\n\n\n-- %site team", $variables);
1525 case 'admin_subject':
1526 return t('An administrator created an account for you at %site', $variables);
1528 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\nYour new %site membership also enables to you to login to other Drupal powered websites (e.g. http://www.drupal.org/) without registering. Just use the following Drupal ID and password:\n\nDrupal ID: %username@%uri_brief\npassword: %password\n\n\n-- %site team", $variables);
1529 case 'approval_subject':
1530 return t('Account details for %username at %site (pending admin approval)', $variables);
1531 case 'approval_body':
1532 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\nYour new %site membership also enables to you to login to other Drupal powered websites (e.g. http://www.drop.org/) without registering. Just use the following Drupal ID and password:\n\nDrupal ID: %username@%uri_brief\npassword: %password\n\n\n-- %site team", $variables);
1533 case 'pass_subject':
1534 return t('Replacement login information for %username at %site', $variables);
1536 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);
1541 function user_configure_settings() {
1545 * Menu callback: check an access rule
1547 function user_admin_access_check() {
1548 $form['user'] = array('#type' => 'fieldset', '#title' => t('Username'));
1549 $form['user']['test'] = array('#type' => 'textfield', '#title' => '', '#description' => t('Enter a username to check if it will be denied or allowed.'), '#size' => 30, '#maxlength' => 64);
1550 $form['user']['type'] = array('#type' => 'hidden', '#value' => 'user');
1551 $form['user']['submit'] = array('#type' => 'submit', '#value' => t('Check username'));
1552 $output .= drupal_get_form('check_user', $form, 'user_admin_access_check');
1553 unset($form); // prevent endless loop?
1555 $form['mail'] = array('#type' => 'fieldset', '#title' => t('E-mail'));
1556 $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' => 64);
1557 $form['mail']['type'] = array('#type' => 'hidden', '#value' => 'mail');
1558 $form['mail']['submit'] = array('#type' => 'submit', '#value' => t('Check e-mail'));
1559 $output .= drupal_get_form('check_mail', $form, 'user_admin_access_check');
1560 unset($form); // prevent endless loop?
1562 $form['host'] = array('#type' => 'fieldset', '#title' => t('Hostname'));
1563 $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);
1564 $form['host']['type'] = array('#type' => 'hidden', '#value' => 'host');
1565 $form['host']['submit'] = array('#type' => 'submit', '#value' => t('Check hostname'));
1566 $output .= drupal_get_form('check_host', $form, 'user_admin_access_check');
1567 unset($form); // prevent endless loop?
1572 function user_admin_access_check_validate($form_id, $edit) {
1573 if (empty($edit['test'])) {
1574 form_set_error($edit['type'], t('No value entered. Please enter a test string and try again.'));
1578 function user_admin_access_check_submit($form_id, $edit) {
1579 switch ($edit['type']) {
1581 if (drupal_is_denied('user', $edit['test'])) {
1582 drupal_set_message(t('The username %name is not allowed.', array('%name' => theme('placeholder', $edit['test']))));
1585 drupal_set_message(t('The username %name is allowed.', array('%name' => theme('placeholder', $edit['test']))));
1589 if (drupal_is_denied('mail', $edit['test'])) {
1590 drupal_set_message(t('The e-mail address %mail is not allowed.', array('%mail' => theme('placeholder', $edit['test']))));
1593 drupal_set_message(t('The e-mail address %mail is allowed.', array('%mail' => theme('placeholder', $edit['test']))));
1597 if (drupal_is_denied('host', $edit['test'])) {
1598 drupal_set_message(t('The hostname %host is not allowed.', array('%host' => theme('placeholder', $edit['test']))));
1601 drupal_set_message(t('The hostname %host is allowed.', array('%host' => theme('placeholder', $edit['test']))));
1610 * Menu callback: add an access rule
1612 function user_admin_access_add($mask = NULL, $type = NULL) {
1613 if ($edit = $_POST['edit']) {
1614 if (!$edit['mask']) {
1615 form_set_error('mask', t('You must enter a mask.'));
1617 else if (drupal_valid_token($_POST['edit']['form_token'], 'access_rule', TRUE)) {
1618 $aid = db_next_id('{access}_aid');
1619 db_query("INSERT INTO {access} (aid, mask, type, status) VALUES ('%s', '%s', '%s', %d)", $aid, $edit['mask'], $edit['type'], $edit['status']);
1620 drupal_set_message(t('The access rule has been added.'));
1621 drupal_goto('admin/access/rules');
1624 form_set_error('form_token', t('Validation error, please try again. If this error persists, please contact the site administrator.'));
1628 $edit['mask'] = $mask;
1629 $edit['type'] = $type;
1632 $form = _user_admin_access_form($edit);
1633 $form['submit'] = array('#type' => 'submit', '#value' => t('Add rule'));
1635 return drupal_get_form('access_rule', $form);
1639 * Menu callback: delete an access rule
1641 function user_admin_access_delete($aid = 0) {
1642 $access_types = array('user' => t('username'), 'mail' => t('e-mail'));
1643 $edit = db_fetch_object(db_query('SELECT aid, type, status, mask FROM {access} WHERE aid = %d', $aid));
1646 $form['aid'] = array('#type' => 'hidden', '#value' => $aid);
1647 $output = confirm_form('user_admin_access_delete_confirm', $form,
1648 t('Are you sure you want to delete the %type rule for %rule?', array('%type' => $access_types[$edit->type], '%rule' => theme('placeholder', $edit->mask))),
1649 'admin/access/rules',
1650 t('This action cannot be undone.'),
1656 function user_admin_access_delete_confirm_submit($form_id, $edit) {
1657 db_query('DELETE FROM {access} WHERE aid = %d', $edit['aid']);
1658 drupal_set_message(t('The access rule has been deleted.'));
1659 return 'admin/access/rules';
1663 * Menu callback: edit an access rule
1665 function user_admin_access_edit($aid = 0) {
1666 if ($edit = $_POST['edit']) {
1667 if (!$edit['mask']) {
1668 form_set_error('mask', t('You must enter a mask.'));
1670 else if (drupal_valid_token($_POST['edit']['form_token'], 'access_rule', TRUE)) {
1671 db_query("UPDATE {access} SET mask = '%s', type = '%s', status = '%s' WHERE aid = %d", $edit['mask'], $edit['type'], $edit['status'], $aid);
1672 drupal_set_message(t('The access rule has been saved.'));
1673 drupal_goto('admin/access/rules');
1676 form_set_error('form_token', t('Validation error, please try again. If this error persists, please contact the site administrator.'));
1680 $edit = db_fetch_array(db_query('SELECT aid, type, status, mask FROM {access} WHERE aid = %d', $aid));
1682 $form = _user_admin_access_form($edit);
1683 $form['submit'] = array('#type' => 'submit', '#value' => t('Save rule'));
1685 return drupal_get_form('access_rule', $form);
1688 function _user_admin_access_form($edit) {
1689 $form['status'] = array(
1690 '#type' => 'radios',
1691 '#title' => t('Access type'),
1692 '#default_value' => $edit['status'],
1693 '#options' => array('1' => t('Allow'), '0' => t('Deny')),
1695 $type_options = array('user' => t('Username'), 'mail' => t('E-mail'), 'host' => t('Host'));
1696 $form['type'] = array(
1697 '#type' => 'radios',
1698 '#title' => t('Rule type'),
1699 '#default_value' => (isset($type_options[$edit['type']]) ? $edit['type'] : 'user'),
1700 '#options' => $type_options,
1702 $form['mask'] = array(
1703 '#type' => 'textfield',
1704 '#title' => t('Mask'),
1707 '#default_value' => $edit['mask'],
1708 '#description' => '%: '. t('Matches any number of characters, even zero characters') .'.<br />_: '. t('Matches exactly one character.'),
1709 '#required' => TRUE,
1715 * Menu callback: list all access rules
1717 function user_admin_access() {
1718 $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));
1719 $result = db_query("SELECT aid, type, status, mask FROM {access}". tablesort_sql($header));
1720 $access_types = array('user' => t('username'), 'mail' => t('e-mail'), 'host' => t('host'));
1722 while ($rule = db_fetch_object($result)) {
1723 $rows[] = array($rule->status ? t('allow') : t('deny'), $access_types[$rule->type], $rule->mask, l(t('edit'), 'admin/access/rules/edit/'. $rule->aid), l(t('delete'), 'admin/access/rules/delete/'. $rule->aid));
1725 if (count($rows) == 0) {
1726 $rows[] = array(array('data' => '<em>'. t('There are currently no access rules.') .'</em>', 'colspan' => 5));
1728 $output .= theme('table', $header, $rows);
1734 * Retrieve an array of roles matching specified conditions.
1736 * @param $membersonly
1737 * Set this to TRUE to exclude the 'anonymous' role.
1738 * @param $permission
1739 * A string containing a permission. If set, only roles containing that permission are returned.
1742 * An associative array with the role id as the key and the role name as value.
1744 function user_roles($membersonly = 0, $permission = 0) {
1748 $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);
1751 $result = db_query('SELECT * FROM {role} ORDER BY name');
1753 while ($role = db_fetch_object($result)) {
1754 if (!$membersonly || ($membersonly && $role->rid != DRUPAL_ANONYMOUS_RID)) {
1755 $roles[$role->rid] = $role->name;
1762 * Menu callback: administer permissions.
1764 function user_admin_perm($str_rids = NULL) {
1765 if (preg_match('/^([0-9]+[+ ])*[0-9]+$/', $str_rids)) {
1766 // The '+' character in a query string may be parsed as ' '.
1767 $rids = preg_split('/[+ ]/', $str_rids);
1771 $breadcrumbs = drupal_get_breadcrumb();
1772 $breadcrumbs[] = l(t('all roles'), 'admin/access');
1773 drupal_set_breadcrumb($breadcrumbs);
1774 $result = db_query('SELECT r.rid, p.perm FROM {role} r LEFT JOIN {permission} p ON r.rid = p.rid WHERE r.rid IN (%s) ORDER BY name', implode(', ', $rids));
1777 $result = db_query('SELECT r.rid, p.perm FROM {role} r LEFT JOIN {permission} p ON r.rid = p.rid ORDER BY name');
1780 // Compile role array:
1781 // Add a comma at the end so when searching for a permission, we can
1782 // always search for "$perm," to make sure we do not confuse
1783 // permissions that are substrings of each other.
1784 while ($role = db_fetch_object($result)) {
1785 $role_permissions[$role->rid] = $role->perm .',';
1789 $result = db_query('SELECT rid, name FROM {role} r WHERE r.rid IN (%s) ORDER BY name', implode(', ', $rids));
1792 $result = db_query('SELECT rid, name FROM {role} ORDER BY name');
1794 $role_names = array();
1795 while ($role = db_fetch_object($result)) {
1796 $role_names[$role->rid] = $role->name;
1799 // Render role/permission overview:
1801 foreach (module_list(FALSE, FALSE, TRUE) as $module) {
1802 if ($permissions = module_invoke($module, 'perm')) {
1803 $form['permission'][] = array('#type' => 'markup', '#value' => t('%module module', array('%module' => $module)));
1804 asort($permissions);
1805 foreach ($permissions as $perm) {
1806 $options[$perm] = '';
1807 $form['permission'][$perm] = array('#type' => 'markup', '#value' => t($perm));
1808 foreach ($role_names as $rid => $name) {
1809 // Builds arrays for checked boxes for each role
1810 if (strpos($role_permissions[$rid], $perm .',') !== FALSE) {
1811 $status[$rid][] = $perm;
1817 // Have to build checkboxes here after checkbox arrays are built
1818 foreach ($role_names as $rid => $name) {
1819 $form['checkboxes'][$rid] = array('#type' => 'checkboxes', '#options' => $options, '#default_value' => $status[$rid]);
1820 $form['role_names'][$rid] = array('#type' => 'markup', '#value' => l($name, 'admin/access/'. $rid), '#tree' => TRUE);
1822 $form['submit'] = array('#type' => 'submit', '#value' => t('Save permissions'));
1824 return drupal_get_form('user_admin_perm', $form);
1827 function theme_user_admin_perm($form) {
1828 foreach (element_children($form['permission']) as $key) {
1829 // Don't take form control structures
1830 if (is_array($form['permission'][$key])) {
1833 if (is_numeric($key)) {
1834 $row[] = array('data' => form_render($form['permission'][$key]), 'class' => 'module', 'colspan' => count($form['role_names']) + 1);
1838 $row[] = array('data' => form_render($form['permission'][$key]), 'class' => 'permission');
1839 foreach (element_children($form['checkboxes']) as $rid) {
1840 if (is_array($form['checkboxes'][$rid])) {
1841 $row[] = array('data' => form_render($form['checkboxes'][$rid][$key]), 'align' => 'center', 'title' => t($key));
1848 $header[] = (t('Permission'));
1849 foreach (element_children($form['role_names']) as $rid) {
1850 if (is_array($form['role_names'][$rid])) {
1851 $header[] = form_render($form['role_names'][$rid]);
1854 $output = theme('table', $header, $rows, array('id' => 'permissions'));
1855 $output .= form_render($form);
1859 function user_admin_perm_submit($form_id, $edit) {
1860 // Save permissions:
1861 $result = db_query('SELECT * FROM {role}');
1862 while ($role = db_fetch_object($result)) {
1863 if(isset($edit[$role->rid])) {
1864 // Delete, so if we clear every checkbox we reset that role;
1865 // otherwise permissions are active and denied everywhere.
1866 db_query('DELETE FROM {permission} WHERE rid = %d', $role->rid);
1867 foreach ($edit[$role->rid] as $key => $value) {
1869 unset($edit[$role->rid][$key]);
1872 if (count($edit[$role->rid])) {
1873 db_query("INSERT INTO {permission} (rid, perm) VALUES (%d, '%s')", $role->rid, implode(', ', array_keys($edit[$role->rid])));
1878 drupal_set_message(t('The changes have been saved.'));
1880 // Clear the cached pages and menus:
1886 * Menu callback: administer roles.
1888 function user_admin_role() {
1891 // Display role edit form.
1892 $role = db_fetch_object(db_query('SELECT * FROM {role} WHERE rid = %d', $id));
1893 $form['name'] = array('#type' => 'textfield', '#title' => t('Role name'), '#default_value' => $role->name, '#size' => 30, '#required' => TRUE, '#maxlength' => 64, '#description' => t('The name for this role. Example: "moderator", "editorial board", "site architect".'));
1894 $form['rid'] = array('#type' => 'value', '#value' => $id);
1895 $form['submit'] = array('#type' => 'submit', '#value' => t('Save role'));
1896 $form['delete'] = array('#type' => 'submit', '#value' => t('Delete role'));
1897 return drupal_get_form('user_admin_edit_role', $form);
1900 $form['name'] = array('#type' => 'textfield', '#size' => 32, '#maxlength' => 64);
1901 $form['submit'] = array('#type' => 'submit', '#value' => t('Add role'));
1902 return drupal_get_form('user_admin_new_role', $form);
1907 function user_admin_edit_role_validate($form_id, $form_values) {
1908 if (drupal_valid_token($form_values['form_token'], 'user_admin_edit_role', TRUE)) {
1909 if (db_result(db_query("SELECT COUNT(*) FROM {role} WHERE name = '%s' AND rid != %d", $form_values['name'], $form_values['rid']))) {
1910 form_set_error('name', t('The role name %name already exists. Please choose another role name.', array('%name' => $form_values['name'])));
1914 form_set_error('form_token', t('Validation error, please try again. If this error persists, please contact the site administrator.'));
1918 function user_admin_edit_role_submit($form_id, $form_values) {
1919 $op = isset($_POST['op']) ? $_POST['op'] : '';
1921 if ($op == t('Save role')) {
1922 db_query("UPDATE {role} SET name = '%s' WHERE rid = %d", $form_values['name'], $form_values['rid']);
1923 drupal_set_message(t('The role has been renamed.'));
1925 else if ($op == t('Delete role')) {
1926 db_query('DELETE FROM {role} WHERE rid = %d', $form_values['rid']);
1927 db_query('DELETE FROM {permission} WHERE rid = %d', $form_values['rid']);
1928 // Update the users who have this role set:
1929 db_query('DELETE FROM {users_roles} WHERE rid = %d', $form_values['rid']);
1930 drupal_set_message(t('The role has been deleted.'));
1932 return 'admin/access/roles';
1935 function user_admin_new_role_validate($form_id, $form_values) {
1936 if ($form_values['name']) {
1937 if (drupal_valid_token($form_values['form_token'], 'user_admin_new_role', TRUE)) {
1938 if (db_result(db_query("SELECT COUNT(*) FROM {role} WHERE name = '%s'", $form_values['name']))) {
1939 form_set_error('name', t('The role name %name already exists. Please choose another role name.', array('%name' => $form_values['name'])));
1943 form_set_error('form_token', t('Validation error, please try again. If this error persists, please contact the site administrator.'));
1947 form_set_error('name', t('You must specify a valid role name.'));
1951 function user_admin_new_role_submit($form_id, $form_values) {
1952 db_query("INSERT INTO {role} (name) VALUES ('%s')", $form_values['name']);
1953 drupal_set_message(t('The role has been added.'));
1954 return 'admin/access/roles';
1957 function theme_user_admin_new_role($form) {
1958 $header = array(t('Name'), t('Operations'));
1959 foreach (user_roles() as $rid => $name) {
1960 if (!in_array($rid, array(DRUPAL_ANONYMOUS_RID, DRUPAL_AUTHENTICATED_RID))) {
1961 $rows[] = array($name, l(t('edit'), 'admin/access/roles/edit/'. $rid));
1964 $rows[] = array($name, '<span class="disabled">'. t('locked') .'</span>');
1967 $rows[] = array(form_render($form['name']), form_render($form['submit']));
1969 $output = theme('table', $header, $rows);
1970 $output .= form_render($form);
1975 function user_admin_account() {
1977 array('data' => t('Username'), 'field' => 'u.name'),
1978 array('data' => t('Status'), 'field' => 'u.status'),
1979 array('data' => t('Member for'), 'field' => 'u.created', 'sort' => 'desc'),
1980 array('data' => t('Last access'), 'field' => 'u.access'),
1983 $sql = 'SELECT u.uid, u.name, u.status, u.created, u.access FROM {users} u WHERE uid != 0';
1984 $sql .= tablesort_sql($header);
1985 $result = pager_query($sql, 50);
1987 $status = array(t('blocked'), t('active'));
1988 while ($account = db_fetch_object($result)) {
1989 $rows[] = array(theme('username', $account),
1990 $status[$account->status],
1991 format_interval(time() - $account->created),
1992 $account->access ? t('%time ago', array('%time' => format_interval(time() - $account->access))) : t('never'),
1993 l(t('edit'), "user/$account->uid/edit", array()));
1996 $output = theme('table', $header, $rows);
1997 $output .= theme('pager', NULL, 50, 0);
2001 function user_configure() {
2002 // User registration settings.
2003 $form['registration'] = array('#type' => 'fieldset', '#title' => t('User registration settings'));
2004 $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.')));
2005 $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.'));
2007 // User e-mail settings.
2008 $form['email'] = array('#type' => 'fieldset', '#title' => t('User e-mail settings'));
2009 $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.');
2010 $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.');
2011 $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.');
2012 $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.');
2013 $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.');
2014 $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.');
2015 $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.');
2016 $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.');
2018 // If picture support is enabled, check whether the picture directory exists:
2019 if (variable_get('user_pictures', 0)) {
2020 $picture_path = file_create_path(variable_get('user_picture_path', 'pictures'));
2021 file_check_directory($picture_path, 1, 'user_picture_path');
2024 $form['pictures'] = array('#type' => 'fieldset', '#title' => t('Pictures'));
2025 $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.'));
2026 $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() .'/')));
2027 $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.'));
2028 $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.'));
2029 $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.'));
2030 $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.'));
2032 return system_settings_form('user_configure_settings', $form);
2035 function user_admin() {
2036 $edit = isset($_POST['edit']) ? $_POST['edit'] : '';
2037 $op = isset($_POST['op']) ? $_POST['op'] : '';
2046 $output = search_form(url('admin/user/search'), $_POST['edit']['keys'], 'user') . search_data($_POST['edit']['keys'], 'user');
2048 case t('Create new account'):
2050 $output = user_register();
2053 $output = user_admin_account();
2059 * Implementation of hook_help().
2061 function user_help($section) {
2065 case 'admin/help#user':
2066 $output = '<p>'. t('The user module allows users to register, login, and logout. 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>';
2067 $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>';
2068 $output .= t('<p>You can</p>
2070 <li>view your <a href="%user">user page</a>.</li>
2071 <li>administer users at <a href="%admin-user">administer >> user</a>.</li>
2072 <li>allow users who have the "select different theme" permission to select themes from their user account by enabling themes in <a href="%admin-themes">administer >> themes</a>.</li>
2073 <li>read user profile help at <a href="%admin-help-profile">administer >> help >> profile</a>.</li>
2074 <li>read about distributed authentication in the system module help at <a href="%admin-help-system">administer >> help >> system</a>.</li>
2076 ', array('%user' => url('user'), '%admin-user' => url('admin/user'), '%admin-themes' => url('admin/themes'), '%admin-help-profile' => url('admin/help/profile'), '%admin-help-system' => url('admin/help/system')));
2077 $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>';
2079 case 'admin/modules#description':
2080 return t('Manages the user registration and login system.');
2082 return t('<p>Drupal allows users to register, login, logout, maintain user profiles, etc. No participant can use his own name to post content until he signs up for a user account.</p>');
2083 case 'admin/user/create':
2084 case 'admin/user/account/create':
2085 return t('<p>This web page allows the administrators to register a 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>');
2086 case strstr($section, 'admin/access/rules'):
2087 return t('<p>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>');
2088 case 'admin/access':
2089 return t('<p>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.</p>', array('%role' => url('admin/access/roles')));
2090 case 'admin/access/roles':
2091 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>
2093 <li>Anonymous user: this role is used for users that don\'t have a user account or that are not authenticated.</li>
2094 <li>Authenticated user: this role is automatically granted to all logged in users.</li>
2095 </ul>', array('%permissions' => url('admin/access/permissions')));
2096 case 'admin/user/search':
2097 return t('<p>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>');
2098 case 'admin/user/configure':
2099 case 'admin/user/configure/settings':
2100 return t('<p>In order to use the full power of Drupal a visitor must sign up for an account. This page lets you setup how a user signs up, logs out, the guidelines from the system about user subscriptions, and the e-mails the system will send to the user.</p>');
2101 case 'user/help#user':
2102 $site = variable_get('site_name', 'this website');
2105 <h3>Distributed authentication<a id=\"da\"></a></h3>
2106 <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 %help-links. This capability is called <em>distributed authentication</em>, and is unique to <a href=\"%drupal\">Drupal</a>, the software which powers %site.</p>
2107 <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('%help-links' => (implode(', ', user_auth_help_links())), '%site' => "<em>$site</em>", '%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'));
2109 foreach (module_list() as $module) {
2110 if (module_hook($module, 'auth')) {
2111 $output .= "<h4><a id=\"$module\"></a>". module_invoke($module, 'info', 'name') .'</h4>';
2112 $output .= module_invoke($module, 'help', "user/help#$module");
2122 * Menu callback; Prints user-specific help information.
2124 function user_help_page() {
2125 return user_help('user/help#user');
2129 * Retrieve a list of all user setting/information categories and sort them by weight.
2131 function _user_categories($account) {
2132 $categories = array();
2134 foreach (module_list() as $module) {
2135 if ($data = module_invoke($module, 'user', 'categories', NULL, $account, '')) {
2136 $categories = array_merge($data, $categories);
2140 usort($categories, '_user_sort');
2145 function _user_sort($a, $b) {
2146 return $a['weight'] < $b['weight'] ? -1 : ($a['weight'] > $b['weight'] ? 1 : ($a['title'] < $b['title'] ? -1 : 1));
2150 * Retrieve a list of all form elements for the specified category.
2152 function _user_forms(&$edit, $account, $category, $hook = 'form') {
2154 foreach (module_list() as $module) {
2155 if ($data = module_invoke($module, 'user', $hook, $edit, $account, $category)) {
2156 $groups = array_merge_recursive($data, $groups);
2159 uasort($groups, '_user_sort');
2161 return empty($groups) ? FALSE : $groups;
2165 * Retrieve a pipe delimited string of autocomplete suggestions for existing users
2167 function user_autocomplete($string) {
2170 $result = db_query_range("SELECT name FROM {users} WHERE LOWER(name) LIKE LOWER('%s%%')", $string, 0, 10);
2171 while ($user = db_fetch_object($result)) {
2172 $matches[$user->name] = check_plain($user->name);
2175 print drupal_to_js($matches);