| [ Index ] |
PHP Cross Reference of Drupal 6 (yi-drupal) |
[Summary view] [Print] [Text view]
1 <?php 2 3 /** 4 * @file 5 * Enables the user registration and login system. 6 */ 7 8 define('USERNAME_MAX_LENGTH', 60); 9 define('EMAIL_MAX_LENGTH', 64); 10 11 /** 12 * Invokes hook_user() in every module. 13 * 14 * We cannot use module_invoke() for this, because the arguments need to 15 * be passed by reference. 16 * 17 * @param $op 18 * The operation to be passed as the first parameter of the hook function. 19 * @param $edit 20 * An associative array variable containing form values to be passed 21 * as the second parameter of the hook function. 22 * @param $account 23 * The user account object to be passed as the third parameter of the hook 24 * function. 25 * @param $category 26 * The category of user information being acted upon. 27 */ 28 function user_module_invoke($op, &$edit, &$account, $category = NULL) { 29 foreach (module_list() as $module) { 30 $function = $module .'_user'; 31 if (function_exists($function)) { 32 $function($op, $edit, $account, $category); 33 } 34 } 35 } 36 37 /** 38 * Implementation of hook_theme(). 39 */ 40 function user_theme() { 41 return array( 42 'user_picture' => array( 43 'arguments' => array('account' => NULL), 44 'template' => 'user-picture', 45 ), 46 'user_profile' => array( 47 'arguments' => array('account' => NULL), 48 'template' => 'user-profile', 49 'file' => 'user.pages.inc', 50 ), 51 'user_profile_category' => array( 52 'arguments' => array('element' => NULL), 53 'template' => 'user-profile-category', 54 'file' => 'user.pages.inc', 55 ), 56 'user_profile_item' => array( 57 'arguments' => array('element' => NULL), 58 'template' => 'user-profile-item', 59 'file' => 'user.pages.inc', 60 ), 61 'user_list' => array( 62 'arguments' => array('users' => NULL, 'title' => NULL), 63 ), 64 'user_admin_perm' => array( 65 'arguments' => array('form' => NULL), 66 'file' => 'user.admin.inc', 67 ), 68 'user_admin_new_role' => array( 69 'arguments' => array('form' => NULL), 70 'file' => 'user.admin.inc', 71 ), 72 'user_admin_account' => array( 73 'arguments' => array('form' => NULL), 74 'file' => 'user.admin.inc', 75 ), 76 'user_filter_form' => array( 77 'arguments' => array('form' => NULL), 78 'file' => 'user.admin.inc', 79 ), 80 'user_filters' => array( 81 'arguments' => array('form' => NULL), 82 'file' => 'user.admin.inc', 83 ), 84 'user_signature' => array( 85 'arguments' => array('signature' => NULL), 86 ), 87 ); 88 } 89 90 function user_external_load($authname) { 91 $result = db_query("SELECT uid FROM {authmap} WHERE authname = '%s'", $authname); 92 93 if ($user = db_fetch_array($result)) { 94 return user_load($user); 95 } 96 else { 97 return 0; 98 } 99 } 100 101 /** 102 * Perform standard Drupal login operations for a user object. 103 * 104 * The user object must already be authenticated. This function verifies 105 * that the user account is not blocked/denied and then performs the login, 106 * updates the login timestamp in the database, invokes hook_user('login'), 107 * and regenerates the session. 108 * 109 * @param $account 110 * An authenticated user object to be set as the currently logged 111 * in user. 112 * @param $edit 113 * The array of form values submitted by the user, if any. 114 * This array is passed to hook_user op login. 115 * @return boolean 116 * TRUE if the login succeeds, FALSE otherwise. 117 */ 118 function user_external_login($account, $edit = array()) { 119 $form = drupal_get_form('user_login'); 120 121 $state['values'] = $edit; 122 if (empty($state['values']['name'])) { 123 $state['values']['name'] = $account->name; 124 } 125 126 // Check if user is blocked or denied by access rules. 127 user_login_name_validate($form, $state, (array)$account); 128 if (form_get_errors()) { 129 // Invalid login. 130 return FALSE; 131 } 132 133 // Valid login. 134 global $user; 135 $user = $account; 136 user_authenticate_finalize($state['values']); 137 return TRUE; 138 } 139 140 /** 141 * Fetch a user object. 142 * 143 * @param $user_info 144 * Information about the user to load, consisting of one of the following: 145 * - An associative array whose keys are fields in the {users} table (such as 146 * uid, name, pass, mail, status) and whose values are the field's value. 147 * - A numeric user ID. 148 * 149 * @return 150 * A fully-loaded $user object upon successful user load or FALSE if user 151 * cannot be loaded. 152 */ 153 function user_load($user_info = array()) { 154 // Dynamically compose a SQL query: 155 $query = array(); 156 $params = array(); 157 158 if (is_numeric($user_info)) { 159 $user_info = array('uid' => $user_info); 160 } 161 elseif (!is_array($user_info)) { 162 return FALSE; 163 } 164 165 foreach ($user_info as $key => $value) { 166 if ($key == 'uid' || $key == 'status') { 167 $query[] = "$key = %d"; 168 $params[] = $value; 169 } 170 else if ($key == 'pass') { 171 $query[] = "pass = '%s'"; 172 $params[] = md5($value); 173 } 174 else { 175 $query[]= "LOWER($key) = LOWER('%s')"; 176 $params[] = $value; 177 } 178 } 179 $result = db_query('SELECT * FROM {users} u WHERE '. implode(' AND ', $query), $params); 180 181 if ($user = db_fetch_object($result)) { 182 $user = drupal_unpack($user); 183 184 $user->roles = array(); 185 if ($user->uid) { 186 $user->roles[DRUPAL_AUTHENTICATED_RID] = 'authenticated user'; 187 } 188 else { 189 $user->roles[DRUPAL_ANONYMOUS_RID] = 'anonymous user'; 190 } 191 $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); 192 while ($role = db_fetch_object($result)) { 193 $user->roles[$role->rid] = $role->name; 194 } 195 user_module_invoke('load', $user_info, $user); 196 } 197 else { 198 $user = FALSE; 199 } 200 201 return $user; 202 } 203 204 /** 205 * Save changes to a user account or add a new user. 206 * 207 * @param $account 208 * The user object for to modify or add. If you want to modify an existing 209 * user account, you will need to ensure that (a) $account is an object, and 210 * (b) you have set $account->uid to the numeric user ID of the user account 211 * you wish to modify. Pass in NULL or any non-object to add a new user. 212 * @param $array 213 * (optional) An array of fields and values to save. For example, 214 * array('name' => 'My name'); Keys that do not belong to columns 215 * in the user-related tables are added to the a serialized array 216 * in the 'data' column and will be loaded in the $user->data array by 217 * user_load(). Setting a field to NULL deletes it from the data column, 218 * if you are modifying an existing user account. 219 * @param $category 220 * (optional) The category for storing profile information in. 221 * 222 * @return 223 * A fully-loaded $user object upon successful save or FALSE if the save failed. 224 */ 225 function user_save($account, $array = array(), $category = 'account') { 226 // Dynamically compose a SQL query: 227 $user_fields = user_fields(); 228 if (is_object($account) && $account->uid) { 229 user_module_invoke('update', $array, $account, $category); 230 $query = ''; 231 $data = unserialize(db_result(db_query('SELECT data FROM {users} WHERE uid = %d', $account->uid))); 232 // Consider users edited by an administrator as logged in, if they haven't 233 // already, so anonymous users can view the profile (if allowed). 234 if (empty($array['access']) && empty($account->access) && user_access('administer users')) { 235 $array['access'] = time(); 236 } 237 foreach ($array as $key => $value) { 238 if ($key == 'pass' && !empty($value)) { 239 $query .= "$key = '%s', "; 240 $v[] = md5($value); 241 } 242 else if ((substr($key, 0, 4) !== 'auth') && ($key != 'pass')) { 243 if (in_array($key, $user_fields)) { 244 // Save standard fields. 245 $query .= "$key = '%s', "; 246 $v[] = $value; 247 } 248 else if ($key != 'roles') { 249 // Roles is a special case: it used below. 250 if ($value === NULL) { 251 unset($data[$key]); 252 } 253 elseif (!empty($key)) { 254 $data[$key] = $value; 255 } 256 } 257 } 258 } 259 $query .= "data = '%s' "; 260 $v[] = serialize($data); 261 262 $success = db_query("UPDATE {users} SET $query WHERE uid = %d", array_merge($v, array($account->uid))); 263 if (!$success) { 264 // The query failed - better to abort the save than risk further data loss. 265 return FALSE; 266 } 267 268 // Reload user roles if provided. 269 if (isset($array['roles']) && is_array($array['roles'])) { 270 db_query('DELETE FROM {users_roles} WHERE uid = %d', $account->uid); 271 272 foreach (array_keys($array['roles']) as $rid) { 273 if (!in_array($rid, array(DRUPAL_ANONYMOUS_RID, DRUPAL_AUTHENTICATED_RID))) { 274 db_query('INSERT INTO {users_roles} (uid, rid) VALUES (%d, %d)', $account->uid, $rid); 275 } 276 } 277 } 278 279 // Delete a blocked user's sessions to kick them if they are online. 280 if (isset($array['status']) && $array['status'] == 0) { 281 sess_destroy_uid($account->uid); 282 } 283 284 // If the password changed, delete all open sessions and recreate 285 // the current one. 286 if (!empty($array['pass'])) { 287 sess_destroy_uid($account->uid); 288 if ($account->uid == $GLOBALS['user']->uid) { 289 sess_regenerate(); 290 } 291 } 292 293 // Refresh user object. 294 $user = user_load(array('uid' => $account->uid)); 295 296 // Send emails after we have the new user object. 297 if (isset($array['status']) && $array['status'] != $account->status) { 298 // The user's status is changing; conditionally send notification email. 299 $op = $array['status'] == 1 ? 'status_activated' : 'status_blocked'; 300 _user_mail_notify($op, $user); 301 } 302 303 user_module_invoke('after_update', $array, $user, $category); 304 } 305 else { 306 // Allow 'created' to be set by the caller. 307 if (!isset($array['created'])) { 308 $array['created'] = time(); 309 } 310 // Consider users created by an administrator as already logged in, so 311 // anonymous users can view the profile (if allowed). 312 if (empty($array['access']) && user_access('administer users')) { 313 $array['access'] = time(); 314 } 315 316 // Note: we wait to save the data column to prevent module-handled 317 // fields from being saved there. We cannot invoke hook_user('insert') here 318 // because we don't have a fully initialized user object yet. 319 foreach ($array as $key => $value) { 320 switch ($key) { 321 case 'pass': 322 $fields[] = $key; 323 $values[] = md5($value); 324 $s[] = "'%s'"; 325 break; 326 case 'mode': case 'sort': case 'timezone': 327 case 'threshold': case 'created': case 'access': 328 case 'login': case 'status': 329 $fields[] = $key; 330 $values[] = $value; 331 $s[] = "%d"; 332 break; 333 default: 334 if (substr($key, 0, 4) !== 'auth' && in_array($key, $user_fields)) { 335 $fields[] = $key; 336 $values[] = $value; 337 $s[] = "'%s'"; 338 } 339 break; 340 } 341 } 342 $success = db_query('INSERT INTO {users} ('. implode(', ', $fields) .') VALUES ('. implode(', ', $s) .')', $values); 343 if (!$success) { 344 // On a failed INSERT some other existing user's uid may be returned. 345 // We must abort to avoid overwriting their account. 346 return FALSE; 347 } 348 349 // Build the initial user object. 350 $array['uid'] = db_last_insert_id('users', 'uid'); 351 $user = user_load(array('uid' => $array['uid'])); 352 353 user_module_invoke('insert', $array, $user, $category); 354 355 // Build and save the serialized data field now. 356 $data = array(); 357 foreach ($array as $key => $value) { 358 if ((substr($key, 0, 4) !== 'auth') && ($key != 'roles') && (!in_array($key, $user_fields)) && ($value !== NULL)) { 359 $data[$key] = $value; 360 } 361 } 362 db_query("UPDATE {users} SET data = '%s' WHERE uid = %d", serialize($data), $user->uid); 363 364 // Save user roles (delete just to be safe). 365 if (isset($array['roles']) && is_array($array['roles'])) { 366 db_query('DELETE FROM {users_roles} WHERE uid = %d', $array['uid']); 367 foreach (array_keys($array['roles']) as $rid) { 368 if (!in_array($rid, array(DRUPAL_ANONYMOUS_RID, DRUPAL_AUTHENTICATED_RID))) { 369 db_query('INSERT INTO {users_roles} (uid, rid) VALUES (%d, %d)', $array['uid'], $rid); 370 } 371 } 372 } 373 374 // Build the finished user object. 375 $user = user_load(array('uid' => $array['uid'])); 376 } 377 378 // Save distributed authentication mappings. 379 $authmaps = array(); 380 foreach ($array as $key => $value) { 381 if (substr($key, 0, 4) == 'auth') { 382 $authmaps[$key] = $value; 383 } 384 } 385 if (sizeof($authmaps) > 0) { 386 user_set_authmaps($user, $authmaps); 387 } 388 389 return $user; 390 } 391 392 /** 393 * Verify the syntax of the given name. 394 */ 395 function user_validate_name($name) { 396 if (!strlen($name)) { 397 return t('You must enter a username.'); 398 } 399 if (substr($name, 0, 1) == ' ') { 400 return t('The username cannot begin with a space.'); 401 } 402 if (substr($name, -1) == ' ') { 403 return t('The username cannot end with a space.'); 404 } 405 if (strpos($name, ' ') !== FALSE) { 406 return t('The username cannot contain multiple spaces in a row.'); 407 } 408 if (preg_match('/[^\x{80}-\x{F7} a-z0-9@_.\'-]/i', $name)) { 409 return t('The username contains an illegal character.'); 410 } 411 if (preg_match('/[\x{80}-\x{A0}'. // Non-printable ISO-8859-1 + NBSP 412 '\x{AD}'. // Soft-hyphen 413 '\x{2000}-\x{200F}'. // Various space characters 414 '\x{2028}-\x{202F}'. // Bidirectional text overrides 415 '\x{205F}-\x{206F}'. // Various text hinting characters 416 '\x{FEFF}'. // Byte order mark 417 '\x{FF01}-\x{FF60}'. // Full-width latin 418 '\x{FFF9}-\x{FFFD}'. // Replacement characters 419 '\x{0}-\x{1F}]/u', // NULL byte and control characters 420 $name)) { 421 return t('The username contains an illegal character.'); 422 } 423 if (drupal_strlen($name) > USERNAME_MAX_LENGTH) { 424 return t('The username %name is too long: it must be %max characters or less.', array('%name' => $name, '%max' => USERNAME_MAX_LENGTH)); 425 } 426 } 427 428 function user_validate_mail($mail) { 429 if (!$mail) return t('You must enter an e-mail address.'); 430 if (!valid_email_address($mail)) { 431 return t('The e-mail address %mail is not valid.', array('%mail' => $mail)); 432 } 433 } 434 435 function user_validate_picture(&$form, &$form_state) { 436 // If required, validate the uploaded picture. 437 $validators = array( 438 'file_validate_is_image' => array(), 439 'file_validate_image_resolution' => array(variable_get('user_picture_dimensions', '85x85')), 440 'file_validate_size' => array(variable_get('user_picture_file_size', '30') * 1024), 441 ); 442 if ($file = file_save_upload('picture_upload', $validators)) { 443 // Remove the old picture. 444 if (isset($form_state['values']['_account']->picture) && file_exists($form_state['values']['_account']->picture)) { 445 file_delete($form_state['values']['_account']->picture); 446 } 447 448 // The image was saved using file_save_upload() and was added to the 449 // files table as a temporary file. We'll make a copy and let the garbage 450 // collector delete the original upload. 451 $info = image_get_info($file->filepath); 452 $destination = variable_get('user_picture_path', 'pictures') .'/picture-'. $form['#uid'] .'.'. $info['extension']; 453 if (file_copy($file, $destination, FILE_EXISTS_REPLACE)) { 454 $form_state['values']['picture'] = $file->filepath; 455 } 456 else { 457 form_set_error('picture_upload', t("Failed to upload the picture image; the %directory directory doesn't exist or is not writable.", array('%directory' => variable_get('user_picture_path', 'pictures')))); 458 } 459 } 460 } 461 462 /** 463 * Generate a random alphanumeric password. 464 */ 465 function user_password($length = 10) { 466 // This variable contains the list of allowable characters for the 467 // password. Note that the number 0 and the letter 'O' have been 468 // removed to avoid confusion between the two. The same is true 469 // of 'I', 1, and 'l'. 470 $allowable_characters = 'abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789'; 471 472 // Zero-based count of characters in the allowable list: 473 $len = strlen($allowable_characters) - 1; 474 475 // Declare the password as a blank string. 476 $pass = ''; 477 478 // Loop the number of times specified by $length. 479 for ($i = 0; $i < $length; $i++) { 480 481 // Each iteration, pick a random character from the 482 // allowable string and append it to the password: 483 $pass .= $allowable_characters[mt_rand(0, $len)]; 484 } 485 486 return $pass; 487 } 488 489 /** 490 * Determine whether the user has a given privilege. 491 * 492 * @param $string 493 * The permission, such as "administer nodes", being checked for. 494 * @param $account 495 * (optional) The account to check, if not given use currently logged in user. 496 * @param $reset 497 * (optional) Resets the user's permissions cache, which will result in a 498 * recalculation of the user's permissions. This is necessary to support 499 * dynamically added user roles. 500 * 501 * @return 502 * Boolean TRUE if the current user has the requested permission. 503 * 504 * All permission checks in Drupal should go through this function. This 505 * way, we guarantee consistent behavior, and ensure that the superuser 506 * can perform all actions. 507 */ 508 function user_access($string, $account = NULL, $reset = FALSE) { 509 global $user; 510 static $perm = array(); 511 512 if ($reset) { 513 $perm = array(); 514 } 515 516 if (!isset($account)) { 517 $account = $user; 518 } 519 520 // User #1 has all privileges: 521 if ($account->uid == 1) { 522 return TRUE; 523 } 524 525 // To reduce the number of SQL queries, we cache the user's permissions 526 // in a static variable. 527 if (!isset($perm[$account->uid])) { 528 $result = db_query("SELECT p.perm FROM {role} r INNER JOIN {permission} p ON p.rid = r.rid WHERE r.rid IN (". db_placeholders($account->roles) .")", array_keys($account->roles)); 529 530 $perms = array(); 531 while ($row = db_fetch_object($result)) { 532 $perms += array_flip(explode(', ', $row->perm)); 533 } 534 $perm[$account->uid] = $perms; 535 } 536 537 return isset($perm[$account->uid][$string]); 538 } 539 540 /** 541 * Checks for usernames blocked by user administration. 542 * 543 * @return boolean TRUE for blocked users, FALSE for active. 544 */ 545 function user_is_blocked($name) { 546 $deny = db_fetch_object(db_query("SELECT name FROM {users} WHERE status = 0 AND name = LOWER('%s')", $name)); 547 548 return $deny; 549 } 550 551 function user_fields() { 552 static $fields; 553 554 if (!$fields) { 555 $result = db_query('SELECT * FROM {users} WHERE uid = 1'); 556 if ($field = db_fetch_array($result)) { 557 $fields = array_keys($field); 558 } 559 else { 560 // Make sure we return the default fields at least. 561 $fields = array('uid', 'name', 'pass', 'mail', 'picture', 'mode', 'sort', 'threshold', 'theme', 'signature', 'signature_format', 'created', 'access', 'login', 'status', 'timezone', 'language', 'init', 'data'); 562 } 563 } 564 565 return $fields; 566 } 567 568 /** 569 * Implementation of hook_perm(). 570 */ 571 function user_perm() { 572 return array('administer permissions', 'administer users', 'access user profiles', 'change own username'); 573 } 574 575 /** 576 * Implementation of hook_file_download(). 577 * 578 * Ensure that user pictures (avatars) are always downloadable. 579 */ 580 function user_file_download($file) { 581 if (strpos($file, variable_get('user_picture_path', 'pictures') .'/picture-') === 0) { 582 $info = image_get_info(file_create_path($file)); 583 return array('Content-type: '. $info['mime_type']); 584 } 585 } 586 587 /** 588 * Implementation of hook_search(). 589 */ 590 function user_search($op = 'search', $keys = NULL, $skip_access_check = FALSE) { 591 switch ($op) { 592 case 'name': 593 if ($skip_access_check || user_access('access user profiles')) { 594 return t('Users'); 595 } 596 case 'search': 597 if (user_access('access user profiles')) { 598 $find = array(); 599 // Replace wildcards with MySQL/PostgreSQL wildcards. 600 $keys = preg_replace('!\*+!', '%', $keys); 601 if (user_access('administer users')) { 602 // Administrators can also search in the otherwise private email field. 603 $result = pager_query("SELECT name, uid, mail FROM {users} WHERE LOWER(name) LIKE LOWER('%%%s%%') OR LOWER(mail) LIKE LOWER('%%%s%%')", 15, 0, NULL, $keys, $keys); 604 while ($account = db_fetch_object($result)) { 605 $find[] = array('title' => $account->name .' ('. $account->mail .')', 'link' => url('user/'. $account->uid, array('absolute' => TRUE))); 606 } 607 } 608 else { 609 $result = pager_query("SELECT name, uid FROM {users} WHERE LOWER(name) LIKE LOWER('%%%s%%')", 15, 0, NULL, $keys); 610 while ($account = db_fetch_object($result)) { 611 $find[] = array('title' => $account->name, 'link' => url('user/'. $account->uid, array('absolute' => TRUE))); 612 } 613 } 614 return $find; 615 } 616 } 617 } 618 619 /** 620 * Implementation of hook_elements(). 621 */ 622 function user_elements() { 623 return array( 624 'user_profile_category' => array(), 625 'user_profile_item' => array(), 626 ); 627 } 628 629 /** 630 * Implementation of hook_user(). 631 */ 632 function user_user($type, &$edit, &$account, $category = NULL) { 633 if ($type == 'view') { 634 $account->content['user_picture'] = array( 635 '#value' => theme('user_picture', $account), 636 '#weight' => -10, 637 ); 638 if (!isset($account->content['summary'])) { 639 $account->content['summary'] = array(); 640 } 641 $account->content['summary'] += array( 642 '#type' => 'user_profile_category', 643 '#attributes' => array('class' => 'user-member'), 644 '#weight' => 5, 645 '#title' => t('History'), 646 ); 647 $account->content['summary']['member_for'] = array( 648 '#type' => 'user_profile_item', 649 '#title' => t('Member for'), 650 '#value' => format_interval(time() - $account->created), 651 ); 652 } 653 if ($type == 'form' && $category == 'account') { 654 $form_state = array(); 655 return user_edit_form($form_state, (isset($account->uid) ? $account->uid : FALSE), $edit); 656 } 657 658 if ($type == 'validate' && $category == 'account') { 659 return _user_edit_validate((isset($account->uid) ? $account->uid : FALSE), $edit); 660 } 661 662 if ($type == 'submit' && $category == 'account') { 663 return _user_edit_submit((isset($account->uid) ? $account->uid : FALSE), $edit); 664 } 665 666 if ($type == 'categories') { 667 return array(array('name' => 'account', 'title' => t('Account settings'), 'weight' => 1)); 668 } 669 } 670 671 function user_login_block() { 672 $form = array( 673 '#action' => url($_GET['q'], array('query' => drupal_get_destination())), 674 '#id' => 'user-login-form', 675 '#validate' => user_login_default_validators(), 676 '#submit' => array('user_login_submit'), 677 ); 678 $form['name'] = array('#type' => 'textfield', 679 '#title' => t('Username'), 680 '#maxlength' => USERNAME_MAX_LENGTH, 681 '#size' => 15, 682 '#required' => TRUE, 683 ); 684 $form['pass'] = array('#type' => 'password', 685 '#title' => t('Password'), 686 '#maxlength' => 60, 687 '#size' => 15, 688 '#required' => TRUE, 689 ); 690 $form['submit'] = array('#type' => 'submit', 691 '#value' => t('Log in'), 692 ); 693 $items = array(); 694 if (variable_get('user_register', 1)) { 695 $items[] = l(t('Create new account'), 'user/register', array('attributes' => array('title' => t('Create a new user account.')))); 696 } 697 $items[] = l(t('Request new password'), 'user/password', array('attributes' => array('title' => t('Request new password via e-mail.')))); 698 $form['links'] = array('#value' => theme('item_list', $items)); 699 return $form; 700 } 701 702 /** 703 * Implementation of hook_block(). 704 */ 705 function user_block($op = 'list', $delta = 0, $edit = array()) { 706 global $user; 707 708 if ($op == 'list') { 709 $blocks[0]['info'] = t('User login'); 710 // Not worth caching. 711 $blocks[0]['cache'] = BLOCK_NO_CACHE; 712 713 $blocks[1]['info'] = t('Navigation'); 714 // Menu blocks can't be cached because each menu item can have 715 // a custom access callback. menu.inc manages its own caching. 716 $blocks[1]['cache'] = BLOCK_NO_CACHE; 717 718 $blocks[2]['info'] = t('Who\'s new'); 719 720 // Too dynamic to cache. 721 $blocks[3]['info'] = t('Who\'s online'); 722 $blocks[3]['cache'] = BLOCK_NO_CACHE; 723 return $blocks; 724 } 725 else if ($op == 'configure' && $delta == 2) { 726 $form['user_block_whois_new_count'] = array( 727 '#type' => 'select', 728 '#title' => t('Number of users to display'), 729 '#default_value' => variable_get('user_block_whois_new_count', 5), 730 '#options' => drupal_map_assoc(array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)), 731 ); 732 return $form; 733 } 734 else if ($op == 'configure' && $delta == 3) { 735 $period = drupal_map_assoc(array(30, 60, 120, 180, 300, 600, 900, 1800, 2700, 3600, 5400, 7200, 10800, 21600, 43200, 86400), 'format_interval'); 736 $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.')); 737 $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.')); 738 739 return $form; 740 } 741 else if ($op == 'save' && $delta == 2) { 742 variable_set('user_block_whois_new_count', $edit['user_block_whois_new_count']); 743 } 744 else if ($op == 'save' && $delta == 3) { 745 variable_set('user_block_seconds_online', $edit['user_block_seconds_online']); 746 variable_set('user_block_max_list_count', $edit['user_block_max_list_count']); 747 } 748 else if ($op == 'view') { 749 $block = array(); 750 751 switch ($delta) { 752 case 0: 753 // For usability's sake, avoid showing two login forms on one page. 754 if (!$user->uid && !(arg(0) == 'user' && !is_numeric(arg(1)))) { 755 756 $block['subject'] = t('User login'); 757 $block['content'] = drupal_get_form('user_login_block'); 758 } 759 return $block; 760 761 case 1: 762 if ($menu = menu_tree()) { 763 $block['subject'] = $user->uid ? check_plain($user->name) : t('Navigation'); 764 $block['content'] = $menu; 765 } 766 return $block; 767 768 case 2: 769 if (user_access('access content')) { 770 // Retrieve a list of new users who have subsequently accessed the site successfully. 771 $result = db_query_range('SELECT uid, name FROM {users} WHERE status != 0 AND access != 0 ORDER BY created DESC', 0, variable_get('user_block_whois_new_count', 5)); 772 while ($account = db_fetch_object($result)) { 773 $items[] = $account; 774 } 775 $output = theme('user_list', $items); 776 777 $block['subject'] = t('Who\'s new'); 778 $block['content'] = $output; 779 } 780 return $block; 781 782 case 3: 783 if (user_access('access content')) { 784 // Count users active within the defined period. 785 $interval = time() - variable_get('user_block_seconds_online', 900); 786 787 // Perform database queries to gather online user lists. We use s.timestamp 788 // rather than u.access because it is much faster. 789 $anonymous_count = sess_count($interval); 790 $authenticated_count = db_result(db_query('SELECT COUNT(DISTINCT s.uid) FROM {sessions} s WHERE s.timestamp >= %d AND s.uid > 0', $interval)); 791 792 // Format the output with proper grammar. 793 if ($anonymous_count == 1 && $authenticated_count == 1) { 794 $output = t('There is currently %members and %visitors online.', array('%members' => format_plural($authenticated_count, '1 user', '@count users'), '%visitors' => format_plural($anonymous_count, '1 guest', '@count guests'))); 795 } 796 else { 797 $output = t('There are currently %members and %visitors online.', array('%members' => format_plural($authenticated_count, '1 user', '@count users'), '%visitors' => format_plural($anonymous_count, '1 guest', '@count guests'))); 798 } 799 800 // Display a list of currently online users. 801 $max_users = variable_get('user_block_max_list_count', 10); 802 if ($authenticated_count && $max_users) { 803 $authenticated_users = db_query_range('SELECT u.uid, u.name, MAX(s.timestamp) AS timestamp FROM {users} u INNER JOIN {sessions} s ON u.uid = s.uid WHERE s.timestamp >= %d AND s.uid > 0 GROUP BY u.uid, u.name ORDER BY s.timestamp DESC', $interval, 0, $max_users); 804 while ($account = db_fetch_object($authenticated_users)) { 805 $items[] = $account; 806 } 807 $output .= theme('user_list', $items, t('Online users')); 808 } 809 810 $block['subject'] = t('Who\'s online'); 811 $block['content'] = $output; 812 } 813 return $block; 814 } 815 } 816 } 817 818 /** 819 * Process variables for user-picture.tpl.php. 820 * 821 * The $variables array contains the following arguments: 822 * - $account 823 * 824 * @see user-picture.tpl.php 825 */ 826 function template_preprocess_user_picture(&$variables) { 827 $variables['picture'] = ''; 828 if (variable_get('user_pictures', 0)) { 829 $account = $variables['account']; 830 if (!empty($account->picture) && file_exists($account->picture)) { 831 $picture = file_create_url($account->picture); 832 } 833 else if (variable_get('user_picture_default', '')) { 834 $picture = variable_get('user_picture_default', ''); 835 } 836 837 if (isset($picture)) { 838 $alt = t("@user's picture", array('@user' => $account->name ? $account->name : variable_get('anonymous', t('Anonymous')))); 839 $variables['picture'] = theme('image', $picture, $alt, $alt, '', FALSE); 840 if (!empty($account->uid) && user_access('access user profiles')) { 841 $attributes = array('attributes' => array('title' => t('View user profile.')), 'html' => TRUE); 842 $variables['picture'] = l($variables['picture'], "user/$account->uid", $attributes); 843 } 844 } 845 } 846 } 847 848 /** 849 * Make a list of users. 850 * 851 * @param $users 852 * An array with user objects. Should contain at least the name and uid. 853 * @param $title 854 * (optional) Title to pass on to theme_item_list(). 855 * 856 * @ingroup themeable 857 */ 858 function theme_user_list($users, $title = NULL) { 859 if (!empty($users)) { 860 foreach ($users as $user) { 861 $items[] = theme('username', $user); 862 } 863 } 864 return theme('item_list', $items, $title); 865 } 866 867 function user_is_anonymous() { 868 // Menu administrators can see items for anonymous when administering. 869 return !$GLOBALS['user']->uid || !empty($GLOBALS['menu_admin']); 870 } 871 872 function user_is_logged_in() { 873 return (bool)$GLOBALS['user']->uid; 874 } 875 876 function user_register_access() { 877 return user_is_anonymous() && variable_get('user_register', 1); 878 } 879 880 function user_view_access($account) { 881 return $account && $account->uid && 882 ( 883 // Always let users view their own profile. 884 ($GLOBALS['user']->uid == $account->uid) || 885 // Administrators can view all accounts. 886 user_access('administer users') || 887 // The user is not blocked and logged in at least once. 888 ($account->access && $account->status && user_access('access user profiles')) 889 ); 890 } 891 892 /** 893 * Access callback for user account editing. 894 */ 895 function user_edit_access($account) { 896 return (($GLOBALS['user']->uid == $account->uid) || user_access('administer users')) && $account->uid > 0; 897 } 898 899 function user_load_self($arg) { 900 $arg[1] = user_load($GLOBALS['user']->uid); 901 return $arg; 902 } 903 904 /** 905 * Implementation of hook_menu(). 906 */ 907 function user_menu() { 908 $items['user/autocomplete'] = array( 909 'title' => 'User autocomplete', 910 'page callback' => 'user_autocomplete', 911 'access callback' => 'user_access', 912 'access arguments' => array('access user profiles'), 913 'type' => MENU_CALLBACK, 914 'file' => 'user.pages.inc', 915 ); 916 917 // Registration and login pages. 918 $items['user'] = array( 919 'title' => 'User account', 920 'page callback' => 'user_page', 921 'access callback' => TRUE, 922 'type' => MENU_CALLBACK, 923 'file' => 'user.pages.inc', 924 ); 925 926 $items['user/login'] = array( 927 'title' => 'Log in', 928 'access callback' => 'user_is_anonymous', 929 'type' => MENU_DEFAULT_LOCAL_TASK, 930 ); 931 932 $items['user/register'] = array( 933 'title' => 'Create new account', 934 'page callback' => 'drupal_get_form', 935 'page arguments' => array('user_register'), 936 'access callback' => 'user_register_access', 937 'type' => MENU_LOCAL_TASK, 938 'file' => 'user.pages.inc', 939 ); 940 941 $items['user/password'] = array( 942 'title' => 'Request new password', 943 'page callback' => 'drupal_get_form', 944 'page arguments' => array('user_pass'), 945 'access callback' => 'user_is_anonymous', 946 'type' => MENU_LOCAL_TASK, 947 'file' => 'user.pages.inc', 948 ); 949 $items['user/reset/%/%/%'] = array( 950 'title' => 'Reset password', 951 'page callback' => 'drupal_get_form', 952 'page arguments' => array('user_pass_reset', 2, 3, 4), 953 'access callback' => TRUE, 954 'type' => MENU_CALLBACK, 955 'file' => 'user.pages.inc', 956 ); 957 958 // Admin user pages. 959 $items['admin/user'] = array( 960 'title' => 'User management', 961 'description' => "Manage your site's users, groups and access to site features.", 962 'position' => 'left', 963 'page callback' => 'system_admin_menu_block_page', 964 'access arguments' => array('access administration pages'), 965 'file' => 'system.admin.inc', 966 'file path' => drupal_get_path('module', 'system'), 967 ); 968 $items['admin/user/user'] = array( 969 'title' => 'Users', 970 'description' => 'List, add, and edit users.', 971 'page callback' => 'user_admin', 972 'page arguments' => array('list'), 973 'access arguments' => array('administer users'), 974 'file' => 'user.admin.inc', 975 ); 976 $items['admin/user/user/list'] = array( 977 'title' => 'List', 978 'type' => MENU_DEFAULT_LOCAL_TASK, 979 'weight' => -10, 980 ); 981 $items['admin/user/user/create'] = array( 982 'title' => 'Add user', 983 'page arguments' => array('create'), 984 'access arguments' => array('administer users'), 985 'type' => MENU_LOCAL_TASK, 986 'file' => 'user.admin.inc', 987 ); 988 $items['admin/user/settings'] = array( 989 'title' => 'User settings', 990 'description' => 'Configure default behavior of users, including registration requirements, e-mails, and user pictures.', 991 'page callback' => 'drupal_get_form', 992 'page arguments' => array('user_admin_settings'), 993 'access arguments' => array('administer users'), 994 'file' => 'user.admin.inc', 995 ); 996 997 // Admin access pages. 998 $items['admin/user/permissions'] = array( 999 'title' => 'Permissions', 1000 'description' => 'Determine access to features by selecting permissions for roles.', 1001 'page callback' => 'drupal_get_form', 1002 'page arguments' => array('user_admin_perm'), 1003 'access arguments' => array('administer permissions'), 1004 'file' => 'user.admin.inc', 1005 ); 1006 $items['admin/user/roles'] = array( 1007 'title' => 'Roles', 1008 'description' => 'List, edit, or add user roles.', 1009 'page callback' => 'drupal_get_form', 1010 'page arguments' => array('user_admin_new_role'), 1011 'access arguments' => array('administer permissions'), 1012 'file' => 'user.admin.inc', 1013 ); 1014 $items['admin/user/roles/edit'] = array( 1015 'title' => 'Edit role', 1016 'page arguments' => array('user_admin_role'), 1017 'access arguments' => array('administer permissions'), 1018 'type' => MENU_CALLBACK, 1019 'file' => 'user.admin.inc', 1020 ); 1021 $items['admin/user/rules'] = array( 1022 'title' => 'Access rules', 1023 'description' => 'List and create rules to disallow usernames, e-mail addresses, and IP addresses.', 1024 'page callback' => 'user_admin_access', 1025 'access arguments' => array('administer permissions'), 1026 'file' => 'user.admin.inc', 1027 ); 1028 $items['admin/user/rules/list'] = array( 1029 'title' => 'List', 1030 'type' => MENU_DEFAULT_LOCAL_TASK, 1031 'weight' => -10, 1032 ); 1033 $items['admin/user/rules/add'] = array( 1034 'title' => 'Add rule', 1035 'page callback' => 'user_admin_access_add', 1036 'access arguments' => array('administer permissions'), 1037 'type' => MENU_LOCAL_TASK, 1038 'file' => 'user.admin.inc', 1039 ); 1040 $items['admin/user/rules/check'] = array( 1041 'title' => 'Check rules', 1042 'page callback' => 'user_admin_access_check', 1043 'access arguments' => array('administer permissions'), 1044 'type' => MENU_LOCAL_TASK, 1045 'file' => 'user.admin.inc', 1046 ); 1047 $items['admin/user/rules/edit'] = array( 1048 'title' => 'Edit rule', 1049 'page callback' => 'user_admin_access_edit', 1050 'access arguments' => array('administer permissions'), 1051 'type' => MENU_CALLBACK, 1052 'file' => 'user.admin.inc', 1053 ); 1054 $items['admin/user/rules/delete'] = array( 1055 'title' => 'Delete rule', 1056 'page callback' => 'drupal_get_form', 1057 'page arguments' => array('user_admin_access_delete_confirm'), 1058 'access arguments' => array('administer permissions'), 1059 'type' => MENU_CALLBACK, 1060 'file' => 'user.admin.inc', 1061 ); 1062 1063 $items['logout'] = array( 1064 'title' => 'Log out', 1065 'access callback' => 'user_is_logged_in', 1066 'page callback' => 'user_logout', 1067 'weight' => 10, 1068 'file' => 'user.pages.inc', 1069 ); 1070 1071 $items['user/%user_uid_optional'] = array( 1072 'title' => 'My account', 1073 'title callback' => 'user_page_title', 1074 'title arguments' => array(1), 1075 'page callback' => 'user_view', 1076 'page arguments' => array(1), 1077 'access callback' => 'user_view_access', 1078 'access arguments' => array(1), 1079 'parent' => '', 1080 'file' => 'user.pages.inc', 1081 ); 1082 1083 $items['user/%user/view'] = array( 1084 'title' => 'View', 1085 'type' => MENU_DEFAULT_LOCAL_TASK, 1086 'weight' => -10, 1087 ); 1088 1089 $items['user/%user/delete'] = array( 1090 'title' => 'Delete', 1091 'page callback' => 'drupal_get_form', 1092 'page arguments' => array('user_confirm_delete', 1), 1093 'access callback' => 'user_delete_access', 1094 'access arguments' => array(1), 1095 'type' => MENU_CALLBACK, 1096 'file' => 'user.pages.inc', 1097 ); 1098 1099 $items['user/%user_category/edit'] = array( 1100 'title' => 'Edit', 1101 'page callback' => 'user_edit', 1102 'page arguments' => array(1), 1103 'access callback' => 'user_edit_access', 1104 'access arguments' => array(1), 1105 'type' => MENU_LOCAL_TASK, 1106 'load arguments' => array('%map', '%index'), 1107 'file' => 'user.pages.inc', 1108 ); 1109 1110 $items['user/%user_category/edit/account'] = array( 1111 'title' => 'Account', 1112 'type' => MENU_DEFAULT_LOCAL_TASK, 1113 'load arguments' => array('%map', '%index'), 1114 ); 1115 1116 $empty_account = new stdClass(); 1117 if (($categories = _user_categories($empty_account)) && (count($categories) > 1)) { 1118 foreach ($categories as $key => $category) { 1119 // 'account' is already handled by the MENU_DEFAULT_LOCAL_TASK. 1120 if ($category['name'] != 'account') { 1121 $items['user/%user_category/edit/'. $category['name']] = array( 1122 'title callback' => 'check_plain', 1123 'title arguments' => array($category['title']), 1124 'page callback' => 'user_edit', 1125 'page arguments' => array(1, 3), 1126 'access callback' => isset($category['access callback']) ? $category['access callback'] : 'user_edit_access', 1127 'access arguments' => isset($category['access arguments']) ? $category['access arguments'] : array(1), 1128 'type' => MENU_LOCAL_TASK, 1129 'weight' => $category['weight'], 1130 'load arguments' => array('%map', '%index'), 1131 'tab_parent' => 'user/%/edit', 1132 'file' => 'user.pages.inc', 1133 ); 1134 } 1135 } 1136 } 1137 return $items; 1138 } 1139 1140 /** 1141 * Implementation of hook_init(). 1142 */ 1143 function user_init() { 1144 drupal_add_css(drupal_get_path('module', 'user') .'/user.css', 'module'); 1145 } 1146 1147 /** 1148 * Load either a specified or the current user account. 1149 * 1150 * @param $uid 1151 * An optional user ID of the user to load. If not provided, the current 1152 * user's ID will be used. 1153 * @return 1154 * A fully-loaded $user object upon successful user load, FALSE if user 1155 * cannot be loaded. 1156 * 1157 * @see user_load() 1158 */ 1159 function user_uid_optional_load($uid = NULL) { 1160 if (!isset($uid)) { 1161 $uid = $GLOBALS['user']->uid; 1162 } 1163 return user_load($uid); 1164 } 1165 1166 /** 1167 * Return a user object after checking if any profile category in the path exists. 1168 */ 1169 function user_category_load($uid, &$map, $index) { 1170 static $user_categories, $accounts; 1171 1172 // Cache $account - this load function will get called for each profile tab. 1173 if (!isset($accounts[$uid])) { 1174 $accounts[$uid] = user_load($uid); 1175 } 1176 $valid = TRUE; 1177 if (($account = $accounts[$uid]) && isset($map[$index + 1]) && $map[$index + 1] == 'edit') { 1178 // Since the path is like user/%/edit/category_name, the category name will 1179 // be at a position 2 beyond the index corresponding to the % wildcard. 1180 $category_index = $index + 2; 1181 // Valid categories may contain slashes, and hence need to be imploded. 1182 $category_path = implode('/', array_slice($map, $category_index)); 1183 if ($category_path) { 1184 // Check that the requested category exists. 1185 $valid = FALSE; 1186 if (!isset($user_categories)) { 1187 $empty_account = new stdClass(); 1188 $user_categories = _user_categories($empty_account); 1189 } 1190 foreach ($user_categories as $category) { 1191 if ($category['name'] == $category_path) { 1192 $valid = TRUE; 1193 // Truncate the map array in case the category name had slashes. 1194 $map = array_slice($map, 0, $category_index); 1195 // Assign the imploded category name to the last map element. 1196 $map[$category_index] = $category_path; 1197 break; 1198 } 1199 } 1200 } 1201 } 1202 return $valid ? $account : FALSE; 1203 } 1204 1205 /** 1206 * Returns the user id of the currently logged in user. 1207 */ 1208 function user_uid_optional_to_arg($arg) { 1209 // Give back the current user uid when called from eg. tracker, aka. 1210 // with an empty arg. Also use the current user uid when called from 1211 // the menu with a % for the current account link. 1212 return empty($arg) || $arg == '%' ? $GLOBALS['user']->uid : $arg; 1213 } 1214 1215 /** 1216 * Menu item title callback - use the user name if it's not the current user. 1217 */ 1218 function user_page_title($account) { 1219 if ($account->uid == $GLOBALS['user']->uid) { 1220 return t('My account'); 1221 } 1222 return $account->name; 1223 } 1224 1225 /** 1226 * Discover which external authentication module(s) authenticated a username. 1227 * 1228 * @param $authname 1229 * A username used by an external authentication module. 1230 * @return 1231 * An associative array with module as key and username as value. 1232 */ 1233 function user_get_authmaps($authname = NULL) { 1234 $result = db_query("SELECT authname, module FROM {authmap} WHERE authname = '%s'", $authname); 1235 $authmaps = array(); 1236 $has_rows = FALSE; 1237 while ($authmap = db_fetch_object($result)) { 1238 $authmaps[$authmap->module] = $authmap->authname; 1239 $has_rows = TRUE; 1240 } 1241 return $has_rows ? $authmaps : 0; 1242 } 1243 1244 /** 1245 * Save mappings of which external authentication module(s) authenticated 1246 * a user. Maps external usernames to user ids in the users table. 1247 * 1248 * @param $account 1249 * A user object. 1250 * @param $authmaps 1251 * An associative array with a compound key and the username as the value. 1252 * The key is made up of 'authname_' plus the name of the external authentication 1253 * module. 1254 * @see user_external_login_register() 1255 */ 1256 function user_set_authmaps($account, $authmaps) { 1257 foreach ($authmaps as $key => $value) { 1258 $module = explode('_', $key, 2); 1259 if ($value) { 1260 db_query("UPDATE {authmap} SET authname = '%s' WHERE uid = %d AND module = '%s'", $value, $account->uid, $module[1]); 1261 if (!db_affected_rows()) { 1262 @db_query("INSERT INTO {authmap} (authname, uid, module) VALUES ('%s', %d, '%s')", $value, $account->uid, $module[1]); 1263 } 1264 } 1265 else { 1266 db_query("DELETE FROM {authmap} WHERE uid = %d AND module = '%s'", $account->uid, $module[1]); 1267 } 1268 } 1269 } 1270 1271 /** 1272 * Form builder; the main user login form. 1273 * 1274 * @ingroup forms 1275 */ 1276 function user_login(&$form_state) { 1277 global $user; 1278 1279 // If we are already logged on, go to the user page instead. 1280 if ($user->uid) { 1281 drupal_goto('user/'. $user->uid); 1282 } 1283 1284 // Display login form: 1285 $form['name'] = array('#type' => 'textfield', 1286 '#title' => t('Username'), 1287 '#size' => 60, 1288 '#maxlength' => USERNAME_MAX_LENGTH, 1289 '#required' => TRUE, 1290 ); 1291 1292 $form['name']['#description'] = t('Enter your @s username.', array('@s' => variable_get('site_name', 'Drupal'))); 1293 $form['pass'] = array('#type' => 'password', 1294 '#title' => t('Password'), 1295 '#description' => t('Enter the password that accompanies your username.'), 1296 '#required' => TRUE, 1297 ); 1298 $form['#validate'] = user_login_default_validators(); 1299 $form['submit'] = array('#type' => 'submit', '#value' => t('Log in'), '#weight' => 2); 1300 1301 return $form; 1302 } 1303 1304 /** 1305 * Set up a series for validators which check for blocked/denied users, 1306 * then authenticate against local database, then return an error if 1307 * authentication fails. Distributed authentication modules are welcome 1308 * to use hook_form_alter() to change this series in order to 1309 * authenticate against their user database instead of the local users 1310 * table. 1311 * 1312 * We use three validators instead of one since external authentication 1313 * modules usually only need to alter the second validator. 1314 * 1315 * @see user_login_name_validate() 1316 * @see user_login_authenticate_validate() 1317 * @see user_login_final_validate() 1318 * @return array 1319 * A simple list of validate functions. 1320 */ 1321 function user_login_default_validators() { 1322 return array('user_login_name_validate', 'user_login_authenticate_validate', 'user_login_final_validate'); 1323 } 1324 1325 /** 1326 * A FAPI validate handler. Sets an error if supplied username has been blocked 1327 * or denied access. 1328 */ 1329 function user_login_name_validate($form, &$form_state) { 1330 if (isset($form_state['values']['name'])) { 1331 if (user_is_blocked($form_state['values']['name'])) { 1332 // blocked in user administration 1333 form_set_error('name', t('The username %name has not been activated or is blocked.', array('%name' => $form_state['values']['name']))); 1334 } 1335 else if (drupal_is_denied('user', $form_state['values']['name'])) { 1336 // denied by access controls 1337 form_set_error('name', t('The name %name is a reserved username.', array('%name' => $form_state['values']['name']))); 1338 } 1339 } 1340 } 1341 1342 /** 1343 * A validate handler on the login form. Check supplied username/password 1344 * against local users table. If successful, sets the global $user object. 1345 */ 1346 function user_login_authenticate_validate($form, &$form_state) { 1347 user_authenticate($form_state['values']); 1348 } 1349 1350 /** 1351 * A validate handler on the login form. Should be the last validator. Sets an 1352 * error if user has not been authenticated yet. 1353 */ 1354 function user_login_final_validate($form, &$form_state) { 1355 global $user; 1356 if (!$user->uid) { 1357 form_set_error('name', t('Sorry, unrecognized username or password. <a href="@password">Have you forgotten your password?</a>', array('@password' => url('user/password')))); 1358 } 1359 } 1360 1361 /** 1362 * Try to log in the user locally. 1363 * 1364 * @param $form_values 1365 * Form values with at least 'name' and 'pass' keys, as well as anything else 1366 * which should be passed along to hook_user op 'login'. 1367 * 1368 * @return 1369 * A $user object, if successful. 1370 */ 1371 function user_authenticate($form_values = array()) { 1372 global $user; 1373 1374 // Load the account to check if the e-mail is denied by an access rule. 1375 // Doing this check here saves us a user_load() in user_login_name_validate() 1376 // and introduces less code change for a security fix. 1377 $account = user_load(array('name' => $form_values['name'], 'pass' => trim($form_values['pass']), 'status' => 1)); 1378 if ($account && drupal_is_denied('mail', $account->mail)) { 1379 form_set_error('name', t('The name %name is registered using a reserved e-mail address and therefore could not be logged in.', array('%name' => $account->name))); 1380 } 1381 1382 // Name and pass keys are required. 1383 // The user is about to be logged in, so make sure no error was previously 1384 // encountered in the validation process. 1385 if (!form_get_errors() && !empty($form_values['name']) && !empty($form_values['pass']) && $account) { 1386 $user = $account; 1387 user_authenticate_finalize($form_values); 1388 return $user; 1389 } 1390 else { 1391 watchdog('user', 'Login attempt failed for %user.', array('%user' => $form_values['name'])); 1392 } 1393 } 1394 1395 /** 1396 * Finalize the login process. Must be called when logging in a user. 1397 * 1398 * The function records a watchdog message about the new session, saves the 1399 * login timestamp, calls hook_user op 'login' and generates a new session. 1400 * 1401 * $param $edit 1402 * This array is passed to hook_user op login. 1403 */ 1404 function user_authenticate_finalize(&$edit) { 1405 global $user; 1406 watchdog('user', 'Session opened for %name.', array('%name' => $user->name)); 1407 // Update the user table timestamp noting user has logged in. 1408 // This is also used to invalidate one-time login links. 1409 $user->login = time(); 1410 db_query("UPDATE {users} SET login = %d WHERE uid = %d", $user->login, $user->uid); 1411 1412 // Regenerate the session ID to prevent against session fixation attacks. 1413 sess_regenerate(); 1414 user_module_invoke('login', $edit, $user); 1415 } 1416 1417 /** 1418 * Submit handler for the login form. Redirects the user to a page. 1419 * 1420 * The user is redirected to the My Account page. Setting the destination in 1421 * the query string (as done by the user login block) overrides the redirect. 1422 */ 1423 function user_login_submit($form, &$form_state) { 1424 global $user; 1425 if ($user->uid) { 1426 $form_state['redirect'] = 'user/'. $user->uid; 1427 return; 1428 } 1429 } 1430 1431 /** 1432 * Helper function for authentication modules. Either login in or registers 1433 * the current user, based on username. Either way, the global $user object is 1434 * populated based on $name. 1435 */ 1436 function user_external_login_register($name, $module) { 1437 global $user; 1438 1439 $existing_user = user_load(array('name' => $name)); 1440 if (isset($existing_user->uid)) { 1441 $user = $existing_user; 1442 } 1443 else { 1444 // Register this new user. 1445 $userinfo = array( 1446 'name' => $name, 1447 'pass' => user_password(), 1448 'init' => $name, 1449 'status' => 1, 1450 "authname_$module" => $name, 1451 'access' => time() 1452 ); 1453 $account = user_save('', $userinfo); 1454 // Terminate if an error occured during user_save(). 1455 if (!$account) { 1456 drupal_set_message(t("Error saving user account."), 'error'); 1457 return; 1458 } 1459 $user = $account; 1460 watchdog('user', 'New external user: %name using module %module.', array('%name' => $name, '%module' => $module), WATCHDOG_NOTICE, l(t('edit'), 'user/'. $user->uid .'/edit')); 1461 } 1462 } 1463 1464 /** 1465 * Generates a unique URL for a user to login and reset their password. 1466 * 1467 * @param object $account 1468 * An object containing the user account. 1469 * 1470 * @return 1471 * A unique URL that provides a one-time log in for the user, from which 1472 * they can change their password. 1473 */ 1474 function user_pass_reset_url($account) { 1475 $timestamp = time(); 1476 return url("user/reset/$account->uid/$timestamp/". user_pass_rehash($account->pass, $timestamp, $account->login), array('absolute' => TRUE)); 1477 } 1478 1479 function user_pass_rehash($password, $timestamp, $login) { 1480 return md5($timestamp . $password . $login); 1481 } 1482 1483 function user_edit_form(&$form_state, $uid, $edit, $register = FALSE) { 1484 _user_password_dynamic_validation(); 1485 $admin = user_access('administer users'); 1486 1487 // Account information: 1488 $form['account'] = array('#type' => 'fieldset', 1489 '#title' => t('Account information'), 1490 '#weight' => -10, 1491 ); 1492 // Only show name field when: registration page; or user is editing own account and can change username; or an admin user. 1493 if ($register || ($GLOBALS['user']->uid == $uid && user_access('change own username')) || $admin) { 1494 $form['account']['name'] = array('#type' => 'textfield', 1495 '#title' => t('Username'), 1496 '#default_value' => $edit['name'], 1497 '#maxlength' => USERNAME_MAX_LENGTH, 1498 '#description' => t('Spaces are allowed; punctuation is not allowed except for periods, hyphens, and underscores.'), 1499 '#required' => TRUE, 1500 ); 1501 } 1502 $form['account']['mail'] = array('#type' => 'textfield', 1503 '#title' => t('E-mail address'), 1504 '#default_value' => $edit['mail'], 1505 '#maxlength' => EMAIL_MAX_LENGTH, 1506 '#description' => t('A valid e-mail address. All e-mails from the system will be sent to this address. The e-mail address is not made public and will only be used if you wish to receive a new password or wish to receive certain news or notifications by e-mail.'), 1507 '#required' => TRUE, 1508 ); 1509 if (!$register) { 1510 $form['account']['pass'] = array('#type' => 'password_confirm', 1511 '#description' => t('To change the current user password, enter the new password in both fields.'), 1512 '#size' => 25, 1513 ); 1514 } 1515 elseif (!variable_get('user_email_verification', TRUE) || $admin) { 1516 $form['account']['pass'] = array( 1517 '#type' => 'password_confirm', 1518 '#description' => t('Provide a password for the new account in both fields.'), 1519 '#required' => TRUE, 1520 '#size' => 25, 1521 ); 1522 } 1523 if ($admin) { 1524 $form['account']['status'] = array( 1525 '#type' => 'radios', 1526 '#title' => t('Status'), 1527 '#default_value' => isset($edit['status']) ? $edit['status'] : 1, 1528 '#options' => array(t('Blocked'), t('Active')) 1529 ); 1530 } 1531 if (user_access('administer permissions')) { 1532 $roles = user_roles(TRUE); 1533 1534 // The disabled checkbox subelement for the 'authenticated user' role 1535 // must be generated separately and added to the checkboxes element, 1536 // because of a limitation in D6 FormAPI not supporting a single disabled 1537 // checkbox within a set of checkboxes. 1538 // TODO: This should be solved more elegantly. See issue #119038. 1539 $checkbox_authenticated = array( 1540 '#type' => 'checkbox', 1541 '#title' => $roles[DRUPAL_AUTHENTICATED_RID], 1542 '#default_value' => TRUE, 1543 '#disabled' => TRUE, 1544 ); 1545 1546 unset($roles[DRUPAL_AUTHENTICATED_RID]); 1547 if ($roles) { 1548 $default = empty($edit['roles']) ? array() : array_keys($edit['roles']); 1549 $form['account']['roles'] = array( 1550 '#type' => 'checkboxes', 1551 '#title' => t('Roles'), 1552 '#default_value' => $default, 1553 '#options' => $roles, 1554 DRUPAL_AUTHENTICATED_RID => $checkbox_authenticated, 1555 ); 1556 } 1557 } 1558 1559 // Signature: 1560 if (variable_get('user_signatures', 0) && module_exists('comment') && !$register) { 1561 $form['signature_settings'] = array( 1562 '#type' => 'fieldset', 1563 '#title' => t('Signature settings'), 1564 '#weight' => 1, 1565 ); 1566 $form['signature_settings']['signature'] = array( 1567 '#type' => 'textarea', 1568 '#title' => t('Signature'), 1569 '#default_value' => $edit['signature'], 1570 '#description' => t('Your signature will be publicly displayed at the end of your comments.'), 1571 ); 1572 1573 // Prevent a "validation error" message when the user attempts to save with a default value they 1574 // do not have access to. 1575 if (!filter_access($edit['signature_format']) && empty($_POST)) { 1576 drupal_set_message(t("The signature input format has been set to a format you don't have access to. It will be changed to a format you have access to when you save this page.")); 1577 $edit['signature_format'] = FILTER_FORMAT_DEFAULT; 1578 } 1579 1580 $form['signature_settings']['signature_format'] = filter_form($edit['signature_format'], NULL, array('signature_format')); 1581 } 1582 1583 // Picture/avatar: 1584 if (variable_get('user_pictures', 0) && !$register) { 1585 $form['picture'] = array('#type' => 'fieldset', '#title' => t('Picture'), '#weight' => 1); 1586 $picture = theme('user_picture', (object)$edit); 1587 if ($edit['picture']) { 1588 $form['picture']['current_picture'] = array('#value' => $picture); 1589 $form['picture']['picture_delete'] = array('#type' => 'checkbox', '#title' => t('Delete picture'), '#description' => t('Check this box to delete your current picture.')); 1590 } 1591 else { 1592 $form['picture']['picture_delete'] = array('#type' => 'hidden'); 1593 } 1594 $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', '')); 1595 $form['#validate'][] = 'user_profile_form_validate'; 1596 $form['#validate'][] = 'user_validate_picture'; 1597 } 1598 $form['#uid'] = $uid; 1599 1600 return $form; 1601 } 1602 1603 function _user_edit_validate($uid, &$edit) { 1604 // Validate the username when: new user account; or user is editing own account and can change username; or an admin user. 1605 if (!$uid || ($GLOBALS['user']->uid == $uid && user_access('change own username')) || user_access('administer users')) { 1606 if ($error = user_validate_name($edit['name'])) { 1607 form_set_error('name', $error); 1608 } 1609 else if (db_result(db_query("SELECT COUNT(*) FROM {users} WHERE uid != %d AND LOWER(name) = LOWER('%s')", $uid, $edit['name'])) > 0) { 1610 form_set_error('name', t('The name %name is already taken.', array('%name' => $edit['name']))); 1611 } 1612 else if (drupal_is_denied('user', $edit['name'])) { 1613 form_set_error('name', t('The name %name has been denied access.', array('%name' => $edit['name']))); 1614 } 1615 } 1616 1617 // Validate the e-mail address: 1618 if ($error = user_validate_mail($edit['mail'])) { 1619 form_set_error('mail', $error); 1620 } 1621 else if (db_result(db_query("SELECT COUNT(*) FROM {users} WHERE uid != %d AND LOWER(mail) = LOWER('%s')", $uid, $edit['mail'])) > 0) { 1622 form_set_error('mail', t('The e-mail address %email is already registered. <a href="@password">Have you forgotten your password?</a>', array('%email' => $edit['mail'], '@password' => url('user/password')))); 1623 } 1624 else if (drupal_is_denied('mail', $edit['mail'])) { 1625 form_set_error('mail', t('The e-mail address %email has been denied access.', array('%email' => $edit['mail']))); 1626 } 1627 } 1628 1629 function _user_edit_submit($uid, &$edit) { 1630 $account = user_load($uid); 1631 // Delete picture if requested, and if no replacement picture was given. 1632 if (!empty($edit['picture_delete'])) { 1633 if ($account->picture && file_exists($account->picture)) { 1634 file_delete($account->picture); 1635 } 1636 $edit['picture'] = ''; 1637 } 1638 if (isset($edit['roles'])) { 1639 $edit['roles'] = array_filter($edit['roles']); 1640 } 1641 } 1642 1643 /** 1644 * Delete a user. 1645 * 1646 * @param $edit An array of submitted form values. 1647 * @param $uid The user ID of the user to delete. 1648 */ 1649 function user_delete($edit, $uid) { 1650 $account = user_load(array('uid' => $uid)); 1651 sess_destroy_uid($uid); 1652 _user_mail_notify('status_deleted', $account); 1653 db_query('DELETE FROM {users} WHERE uid = %d', $uid); 1654 db_query('DELETE FROM {users_roles} WHERE uid = %d', $uid); 1655 db_query('DELETE FROM {authmap} WHERE uid = %d', $uid); 1656 $variables = array('%name' => $account->name, '%email' => '<'. $account->mail .'>'); 1657 watchdog('user', 'Deleted user: %name %email.', $variables, WATCHDOG_NOTICE); 1658 user_module_invoke('delete', $edit, $account); 1659 } 1660 1661 /** 1662 * Builds a structured array representing the profile content. 1663 * 1664 * @param $account 1665 * A user object. 1666 * 1667 * @return 1668 * A structured array containing the individual elements of the profile. 1669 */ 1670 function user_build_content(&$account) { 1671 $edit = NULL; 1672 user_module_invoke('view', $edit, $account); 1673 // Allow modules to modify the fully-built profile. 1674 drupal_alter('profile', $account); 1675 1676 return $account->content; 1677 } 1678 1679 /** 1680 * Implementation of hook_mail(). 1681 */ 1682 function user_mail($key, &$message, $params) { 1683 $language = $message['language']; 1684 $variables = user_mail_tokens($params['account'], $language); 1685 $message['subject'] .= _user_mail_text($key .'_subject', $language, $variables); 1686 $message['body'][] = _user_mail_text($key .'_body', $language, $variables); 1687 } 1688 1689 /** 1690 * Returns a mail string for a variable name. 1691 * 1692 * Used by user_mail() and the settings forms to retrieve strings. 1693 */ 1694 function _user_mail_text($key, $language = NULL, $variables = array()) { 1695 $langcode = isset($language) ? $language->language : NULL; 1696 1697 if ($admin_setting = variable_get('user_mail_'. $key, FALSE)) { 1698 // An admin setting overrides the default string. 1699 return strtr($admin_setting, $variables); 1700 } 1701 else { 1702 // No override, return default string. 1703 switch ($key) { 1704 case 'register_no_approval_required_subject': 1705 return t('Account details for !username at !site', $variables, $langcode); 1706 case 'register_no_approval_required_body': 1707 return t("!username,\n\nThank you for registering at !site. You may now log in to !login_uri using the following username and password:\n\nusername: !username\npassword: !password\n\nYou may also log in by clicking on this link or copying and pasting it in your browser:\n\n!login_url\n\nThis is a one-time login, so it can be used only once.\n\nAfter logging in, you will be redirected to !edit_uri so you can change your password.\n\n\n-- !site team", $variables, $langcode); 1708 case 'register_admin_created_subject': 1709 return t('An administrator created an account for you at !site', $variables, $langcode); 1710 case 'register_admin_created_body': 1711 return t("!username,\n\nA site administrator at !site has created an account for you. You may now log in to !login_uri using the following username and password:\n\nusername: !username\npassword: !password\n\nYou may also log in by clicking on this link or copying and pasting it in your browser:\n\n!login_url\n\nThis is a one-time login, so it can be used only once.\n\nAfter logging in, you will be redirected to !edit_uri so you can change your password.\n\n\n-- !site team", $variables, $langcode); 1712 case 'register_pending_approval_subject': 1713 case 'register_pending_approval_admin_subject': 1714 return t('Account details for !username at !site (pending admin approval)', $variables, $langcode); 1715 case 'register_pending_approval_body': 1716 return t("!username,\n\nThank you for registering at !site. Your application for an account is currently pending approval. Once it has been approved, you will receive another e-mail containing information about how to log in, set your password, and other details.\n\n\n-- !site team", $variables, $langcode); 1717 case 'register_pending_approval_admin_body': 1718 return t("!username has applied for an account.\n\n!edit_uri", $variables, $langcode); 1719 case 'password_reset_subject': 1720 return t('Replacement login information for !username at !site', $variables, $langcode); 1721 case 'password_reset_body': 1722 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 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. 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, $langcode); 1723 case 'status_activated_subject': 1724 return t('Account details for !username at !site (approved)', $variables, $langcode); 1725 case 'status_activated_body': 1726 return t("!username,\n\nYour account at !site has been activated.\n\nYou may now 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\nOnce you have set your own password, you will be able to log in to !login_uri in the future using:\n\nusername: !username\n", $variables, $langcode); 1727 case 'status_blocked_subject': 1728 return t('Account details for !username at !site (blocked)', $variables, $langcode); 1729 case 'status_blocked_body': 1730 return t("!username,\n\nYour account on !site has been blocked.", $variables, $langcode); 1731 case 'status_deleted_subject': 1732 return t('Account details for !username at !site (deleted)', $variables, $langcode); 1733 case 'status_deleted_body': 1734 return t("!username,\n\nYour account on !site has been deleted.", $variables, $langcode); 1735 } 1736 } 1737 } 1738 1739 /*** Administrative features ***********************************************/ 1740 1741 /** 1742 * Retrieve an array of roles matching specified conditions. 1743 * 1744 * @param $membersonly 1745 * Set this to TRUE to exclude the 'anonymous' role. 1746 * @param $permission 1747 * A string containing a permission. If set, only roles containing that 1748 * permission are returned. 1749 * 1750 * @return 1751 * An associative array with the role id as the key and the role name as 1752 * value. 1753 */ 1754 function user_roles($membersonly = FALSE, $permission = NULL) { 1755 // System roles take the first two positions. 1756 $roles = array( 1757 DRUPAL_ANONYMOUS_RID => NULL, 1758 DRUPAL_AUTHENTICATED_RID => NULL, 1759 ); 1760 1761 if (!empty($permission)) { 1762 $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); 1763 } 1764 else { 1765 $result = db_query('SELECT * FROM {role} ORDER BY name'); 1766 } 1767 1768 while ($role = db_fetch_object($result)) { 1769 switch ($role->rid) { 1770 // We only translate the built in role names 1771 case DRUPAL_ANONYMOUS_RID: 1772 if (!$membersonly) { 1773 $roles[$role->rid] = t($role->name); 1774 } 1775 break; 1776 case DRUPAL_AUTHENTICATED_RID: 1777 $roles[$role->rid] = t($role->name); 1778 break; 1779 default: 1780 $roles[$role->rid] = $role->name; 1781 } 1782 } 1783 1784 // Filter to remove unmatched system roles. 1785 return array_filter($roles); 1786 } 1787 1788 /** 1789 * Implementation of hook_user_operations(). 1790 */ 1791 function user_user_operations($form_state = array()) { 1792 $operations = array( 1793 'unblock' => array( 1794 'label' => t('Unblock the selected users'), 1795 'callback' => 'user_user_operations_unblock', 1796 ), 1797 'block' => array( 1798 'label' => t('Block the selected users'), 1799 'callback' => 'user_user_operations_block', 1800 ), 1801 'delete' => array( 1802 'label' => t('Delete the selected users'), 1803 ), 1804 ); 1805 1806 if (user_access('administer permissions')) { 1807 $roles = user_roles(TRUE); 1808 unset($roles[DRUPAL_AUTHENTICATED_RID]); // Can't edit authenticated role. 1809 1810 $add_roles = array(); 1811 foreach ($roles as $key => $value) { 1812 $add_roles['add_role-'. $key] = $value; 1813 } 1814 1815 $remove_roles = array(); 1816 foreach ($roles as $key => $value) { 1817 $remove_roles['remove_role-'. $key] = $value; 1818 } 1819 1820 if (count($roles)) { 1821 $role_operations = array( 1822 t('Add a role to the selected users') => array( 1823 'label' => $add_roles, 1824 ), 1825 t('Remove a role from the selected users') => array( 1826 'label' => $remove_roles, 1827 ), 1828 ); 1829 1830 $operations += $role_operations; 1831 } 1832 } 1833 1834 // If the form has been posted, we need to insert the proper data for 1835 // role editing if necessary. 1836 if (!empty($form_state['submitted'])) { 1837 $operation_rid = explode('-', $form_state['values']['operation']); 1838 $operation = $operation_rid[0]; 1839 if ($operation == 'add_role' || $operation == 'remove_role') { 1840 $rid = $operation_rid[1]; 1841 if (user_access('administer permissions')) { 1842 $operations[$form_state['values']['operation']] = array( 1843 'callback' => 'user_multiple_role_edit', 1844 'callback arguments' => array($operation, $rid), 1845 ); 1846 } 1847 else { 1848 watchdog('security', 'Detected malicious attempt to alter protected user fields.', array(), WATCHDOG_WARNING); 1849 return; 1850 } 1851 } 1852 } 1853 1854 return $operations; 1855 } 1856 1857 /** 1858 * Callback function for admin mass unblocking users. 1859 */ 1860 function user_user_operations_unblock($accounts) { 1861 foreach ($accounts as $uid) { 1862 $account = user_load(array('uid' => (int)$uid)); 1863 // Skip unblocking user if they are already unblocked. 1864 if ($account !== FALSE && $account->status == 0) { 1865 user_save($account, array('status' => 1)); 1866 } 1867 } 1868 } 1869 1870 /** 1871 * Callback function for admin mass blocking users. 1872 */ 1873 function user_user_operations_block($accounts) { 1874 foreach ($accounts as $uid) { 1875 $account = user_load(array('uid' => (int)$uid)); 1876 // Skip blocking user if they are already blocked. 1877 if ($account !== FALSE && $account->status == 1) { 1878 user_save($account, array('status' => 0)); 1879 } 1880 } 1881 } 1882 1883 /** 1884 * Callback function for admin mass adding/deleting a user role. 1885 */ 1886 function user_multiple_role_edit($accounts, $operation, $rid) { 1887 // The role name is not necessary as user_save() will reload the user 1888 // object, but some modules' hook_user() may look at this first. 1889 $role_name = db_result(db_query('SELECT name FROM {role} WHERE rid = %d', $rid)); 1890 1891 switch ($operation) { 1892 case 'add_role': 1893 foreach ($accounts as $uid) { 1894 $account = user_load(array('uid' => (int)$uid)); 1895 // Skip adding the role to the user if they already have it. 1896 if ($account !== FALSE && !isset($account->roles[$rid])) { 1897 $roles = $account->roles + array($rid => $role_name); 1898 user_save($account, array('roles' => $roles)); 1899 } 1900 } 1901 break; 1902 case 'remove_role': 1903 foreach ($accounts as $uid) { 1904 $account = user_load(array('uid' => (int)$uid)); 1905 // Skip removing the role from the user if they already don't have it. 1906 if ($account !== FALSE && isset($account->roles[$rid])) { 1907 $roles = array_diff($account->roles, array($rid => $role_name)); 1908 user_save($account, array('roles' => $roles)); 1909 } 1910 } 1911 break; 1912 } 1913 } 1914 1915 function user_multiple_delete_confirm(&$form_state) { 1916 $edit = $form_state['post']; 1917 1918 $form['accounts'] = array('#prefix' => '<ul>', '#suffix' => '</ul>', '#tree' => TRUE); 1919 // array_filter() returns only elements with TRUE values. 1920 foreach (array_filter($edit['accounts']) as $uid => $value) { 1921 $user = db_result(db_query('SELECT name FROM {users} WHERE uid = %d', $uid)); 1922 $form['accounts'][$uid] = array('#type' => 'hidden', '#value' => $uid, '#prefix' => '<li>', '#suffix' => check_plain($user) ."</li>\n"); 1923 } 1924 $form['operation'] = array('#type' => 'hidden', '#value' => 'delete'); 1925 1926 return confirm_form($form, 1927 t('Are you sure you want to delete these users?'), 1928 'admin/user/user', t('This action cannot be undone.'), 1929 t('Delete all'), t('Cancel')); 1930 } 1931 1932 function user_multiple_delete_confirm_submit($form, &$form_state) { 1933 if ($form_state['values']['confirm']) { 1934 foreach ($form_state['values']['accounts'] as $uid => $value) { 1935 user_delete($form_state['values'], $uid); 1936 } 1937 drupal_set_message(t('The users have been deleted.')); 1938 } 1939 $form_state['redirect'] = 'admin/user/user'; 1940 return; 1941 } 1942 1943 /** 1944 * Implementation of hook_help(). 1945 */ 1946 function user_help($path, $arg) { 1947 global $user; 1948 1949 switch ($path) { 1950 case 'admin/help#user': 1951 $output = '<p>'. t('The user module allows users to register, login, and log out. Users benefit from being able to sign on because it associates content they create with their account and allows various permissions to be set for their roles. The user module supports user roles which establish 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>'; 1952 $output .= '<p>'. t("Users can use their own name or handle and can specify personal configuration settings through their individual <em>My account</em> page. Users must authenticate by supplying a local username and password or through their OpenID, an optional and secure method for logging into many websites with a single username and password. In some configurations, users may authenticate using a username and password from another Drupal site, or through some other site-specific mechanism.") .'</p>'; 1953 $output .= '<p>'. t('A visitor accessing your website is assigned a unique ID, or session ID, which is stored in a cookie. The cookie does not contain personal information, but acts as a key to retrieve information from your site. Users should have cookies enabled in their web browser when using your site.') .'</p>'; 1954 $output .= '<p>'. t('For more information, see the online handbook entry for <a href="@user">User module</a>.', array('@user' => 'http://drupal.org/handbook/modules/user/')) .'</p>'; 1955 return $output; 1956 case 'admin/user/user': 1957 return '<p>'. t('Drupal allows users to register, login, log out, maintain user profiles, etc. Users of the site may not use their own names to post content until they have signed up for a user account.') .'</p>'; 1958 case 'admin/user/user/create': 1959 case 'admin/user/user/account/create': 1960 return '<p>'. t("This web page allows administrators to register new users. Users' e-mail addresses and usernames must be unique.") .'</p>'; 1961 case 'admin/user/rules': 1962 return '<p>'. t('Set up username and e-mail address access rules for new <em>and</em> existing accounts (currently logged in accounts will not be logged out). If a username or e-mail address for an account matches any deny rule, but not an allow rule, then the account will not be allowed to be created or to log in. A host rule is effective for every page view, not just registrations.') .'</p>'; 1963 case 'admin/user/permissions': 1964 return '<p>'. t('Permissions let you control what users can do on your site. Each user role (defined on the <a href="@role">user roles page</a>) has its own set of permissions. For example, you could give users classified as "Administrators" permission to "administer nodes" but deny this power to ordinary, "authenticated" users. You can use permissions to reveal new features to privileged users (those with subscriptions, for example). Permissions also allow trusted users to share the administrative burden of running a busy site.', array('@role' => url('admin/user/roles'))) .'</p>'; 1965 case 'admin/user/roles': 1966 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> 1967 <ul> 1968 <li>Anonymous user: this role is used for users that don\'t have a user account or that are not authenticated.</li> 1969 <li>Authenticated user: this role is automatically granted to all logged in users.</li> 1970 </ul>', array('@permissions' => url('admin/user/permissions'))); 1971 case 'admin/user/search': 1972 return '<p>'. t('Enter a simple pattern ("*" may be used as a wildcard match) to search for a username or e-mail address. For example, one may search for "br" and Drupal might return "brian", "brad", and "brenda@example.com".') .'</p>'; 1973 } 1974 } 1975 1976 /** 1977 * Retrieve a list of all user setting/information categories and sort them by weight. 1978 */ 1979 function _user_categories($account) { 1980 $categories = array(); 1981 1982 // Only variables can be passed by reference workaround. 1983 $null = NULL; 1984 foreach (module_list() as $module) { 1985 $function = $module .'_user'; 1986 // $null and $account need to be passed by reference. 1987 if (function_exists($function) && ($data = $function('categories', $null, $account, ''))) { 1988 $categories = array_merge($data, $categories); 1989 } 1990 } 1991 1992 usort($categories, '_user_sort'); 1993 1994 return $categories; 1995 } 1996 1997 function _user_sort($a, $b) { 1998 $a = (array)$a + array('weight' => 0, 'title' => ''); 1999 $b = (array)$b + array('weight' => 0, 'title' => ''); 2000 return $a['weight'] < $b['weight'] ? -1 : ($a['weight'] > $b['weight'] ? 1 : ($a['title'] < $b['title'] ? -1 : 1)); 2001 } 2002 2003 /** 2004 * List user administration filters that can be applied. 2005 */ 2006 function user_filters() { 2007 // Regular filters 2008 $filters = array(); 2009 $roles = user_roles(TRUE); 2010 unset($roles[DRUPAL_AUTHENTICATED_RID]); // Don't list authorized role. 2011 if (count($roles)) { 2012 $filters['role'] = array( 2013 'title' => t('role'), 2014 'where' => "ur.rid = %d", 2015 'options' => $roles, 2016 'join' => '', 2017 ); 2018 } 2019 2020 $options = array(); 2021 foreach (module_list() as $module) { 2022 if ($permissions = module_invoke($module, 'perm')) { 2023 asort($permissions); 2024 foreach ($permissions as $permission) { 2025 $options[t('@module module', array('@module' => $module))][$permission] = t($permission); 2026 } 2027 } 2028 } 2029 ksort($options); 2030 $filters['permission'] = array( 2031 'title' => t('permission'), 2032 'join' => 'LEFT JOIN {permission} p ON ur.rid = p.rid', 2033 'where' => " ((p.perm IS NOT NULL AND p.perm LIKE '%%%s%%') OR u.uid = 1) ", 2034 'options' => $options, 2035 ); 2036 2037 $filters['status'] = array( 2038 'title' => t('status'), 2039 'where' => 'u.status = %d', 2040 'join' => '', 2041 'options' => array(1 => t('active'), 0 => t('blocked')), 2042 ); 2043 return $filters; 2044 } 2045 2046 /** 2047 * Build query for user administration filters based on session. 2048 */ 2049 function user_build_filter_query() { 2050 $filters = user_filters(); 2051 2052 // Build query 2053 $where = $args = $join = array(); 2054 foreach ($_SESSION['user_overview_filter'] as $filter) { 2055 list($key, $value) = $filter; 2056 // This checks to see if this permission filter is an enabled permission for 2057 // the authenticated role. If so, then all users would be listed, and we can 2058 // skip adding it to the filter query. 2059 if ($key == 'permission') { 2060 $account = new stdClass(); 2061 $account->uid = 'user_filter'; 2062 $account->roles = array(DRUPAL_AUTHENTICATED_RID => 1); 2063 if (user_access($value, $account)) { 2064 continue; 2065 } 2066 } 2067 $where[] = $filters[$key]['where']; 2068 $args[] = $value; 2069 $join[] = $filters[$key]['join']; 2070 } 2071 $where = !empty($where) ? 'AND '. implode(' AND ', $where) : ''; 2072 $join = !empty($join) ? ' '. implode(' ', array_unique($join)) : ''; 2073 2074 return array('where' => $where, 2075 'join' => $join, 2076 'args' => $args, 2077 ); 2078 } 2079 2080 /** 2081 * Implementation of hook_forms(). 2082 */ 2083 function user_forms() { 2084 $forms['user_admin_access_add_form']['callback'] = 'user_admin_access_form'; 2085 $forms['user_admin_access_edit_form']['callback'] = 'user_admin_access_form'; 2086 $forms['user_admin_new_role']['callback'] = 'user_admin_role'; 2087 return $forms; 2088 } 2089 2090 /** 2091 * Implementation of hook_comment(). 2092 */ 2093 function user_comment(&$comment, $op) { 2094 // Validate signature. 2095 if ($op == 'view') { 2096 if (variable_get('user_signatures', 0) && !empty($comment->signature)) { 2097 $comment->signature = check_markup($comment->signature, $comment->signature_format, FALSE); 2098 } 2099 else { 2100 $comment->signature = ''; 2101 } 2102 } 2103 } 2104 2105 /** 2106 * Theme output of user signature. 2107 * 2108 * @ingroup themeable 2109 */ 2110 function theme_user_signature($signature) { 2111 $output = ''; 2112 if ($signature) { 2113 $output .= '<div class="clear">'; 2114 $output .= '<div>—</div>'; 2115 $output .= $signature; 2116 $output .= '</div>'; 2117 } 2118 2119 return $output; 2120 } 2121 2122 /** 2123 * Return an array of token to value mappings for user e-mail messages. 2124 * 2125 * @param $account 2126 * The user object of the account being notified. Must contain at 2127 * least the fields 'uid', 'name', 'pass', 'login', and 'mail'. 2128 * @param $language 2129 * Language object to generate the tokens with. 2130 * @return 2131 * Array of mappings from token names to values (for use with strtr()). 2132 */ 2133 function user_mail_tokens($account, $language) { 2134 global $base_url; 2135 $tokens = array( 2136 '!username' => $account->name, 2137 '!site' => variable_get('site_name', 'Drupal'), 2138 '!login_url' => user_pass_reset_url($account), 2139 '!uri' => $base_url, 2140 '!uri_brief' => preg_replace('!^https?://!', '', $base_url), 2141 '!mailto' => $account->mail, 2142 '!date' => format_date(time(), 'medium', '', NULL, $language->language), 2143 '!login_uri' => url('user', array('absolute' => TRUE, 'language' => $language)), 2144 '!edit_uri' => url('user/'. $account->uid .'/edit', array('absolute' => TRUE, 'language' => $language)), 2145 ); 2146 if (!empty($account->password)) { 2147 $tokens['!password'] = $account->password; 2148 } 2149 return $tokens; 2150 } 2151 2152 /** 2153 * Get the language object preferred by the user. This user preference can 2154 * be set on the user account editing page, and is only available if there 2155 * are more than one languages enabled on the site. If the user did not 2156 * choose a preferred language, or is the anonymous user, the $default 2157 * value, or if it is not set, the site default language will be returned. 2158 * 2159 * @param $account 2160 * User account to look up language for. 2161 * @param $default 2162 * Optional default language object to return if the account 2163 * has no valid language. 2164 */ 2165 function user_preferred_language($account, $default = NULL) { 2166 $language_list = language_list(); 2167 if (!empty($account->language) && isset($language_list[$account->language])) { 2168 return $language_list[$account->language]; 2169 } 2170 else { 2171 return $default ? $default : language_default(); 2172 } 2173 } 2174 2175 /** 2176 * Conditionally create and send a notification email when a certain 2177 * operation happens on the given user account. 2178 * 2179 * @see user_mail_tokens() 2180 * @see drupal_mail() 2181 * 2182 * @param $op 2183 * The operation being performed on the account. Possible values: 2184 * 'register_admin_created': Welcome message for user created by the admin 2185 * 'register_no_approval_required': Welcome message when user self-registers 2186 * 'register_pending_approval': Welcome message, user pending admin approval 2187 * 'password_reset': Password recovery request 2188 * 'status_activated': Account activated 2189 * 'status_blocked': Account blocked 2190 * 'status_deleted': Account deleted 2191 * 2192 * @param $account 2193 * The user object of the account being notified. Must contain at 2194 * least the fields 'uid', 'name', and 'mail'. 2195 * @param $language 2196 * Optional language to use for the notification, overriding account language. 2197 * @return 2198 * The return value from drupal_mail_send(), if ends up being called. 2199 */ 2200 function _user_mail_notify($op, $account, $language = NULL) { 2201 // By default, we always notify except for deleted and blocked. 2202 $default_notify = ($op != 'status_deleted' && $op != 'status_blocked'); 2203 $notify = variable_get('user_mail_'. $op .'_notify', $default_notify); 2204 if ($notify) { 2205 $params['account'] = $account; 2206 $language = $language ? $language : user_preferred_language($account); 2207 $mail = drupal_mail('user', $op, $account->mail, $language, $params); 2208 if ($op == 'register_pending_approval') { 2209 // If a user registered requiring admin approval, notify the admin, too. 2210 // We use the site default language for this. 2211 drupal_mail('user', 'register_pending_approval_admin', variable_get('site_mail', ini_get('sendmail_from')), language_default(), $params); 2212 } 2213 } 2214 return empty($mail) ? NULL : $mail['result']; 2215 } 2216 2217 /** 2218 * Add javascript and string translations for dynamic password validation 2219 * (strength and confirmation checking). 2220 * 2221 * This is an internal function that makes it easier to manage the translation 2222 * strings that need to be passed to the javascript code. 2223 */ 2224 function _user_password_dynamic_validation() { 2225 static $complete = FALSE; 2226 global $user; 2227 // Only need to do once per page. 2228 if (!$complete) { 2229 drupal_add_js(drupal_get_path('module', 'user') .'/user.js', 'module'); 2230 2231 drupal_add_js(array( 2232 'password' => array( 2233 'strengthTitle' => t('Password strength:'), 2234 'lowStrength' => t('Low'), 2235 'mediumStrength' => t('Medium'), 2236 'highStrength' => t('High'), 2237 'tooShort' => t('It is recommended to choose a password that contains at least six characters. It should include numbers, punctuation, and both upper and lowercase letters.'), 2238 'needsMoreVariation' => t('The password does not include enough variation to be secure. Try:'), 2239 'addLetters' => t('Adding both upper and lowercase letters.'), 2240 'addNumbers' => t('Adding numbers.'), 2241 'addPunctuation' => t('Adding punctuation.'), 2242 'sameAsUsername' => t('It is recommended to choose a password different from the username.'), 2243 'confirmSuccess' => t('Yes'), 2244 'confirmFailure' => t('No'), 2245 'confirmTitle' => t('Passwords match:'), 2246 'username' => (isset($user->name) ? $user->name : ''))), 2247 'setting'); 2248 $complete = TRUE; 2249 } 2250 } 2251 2252 /** 2253 * Implementation of hook_hook_info(). 2254 */ 2255 function user_hook_info() { 2256 return array( 2257 'user' => array( 2258 'user' => array( 2259 'insert' => array( 2260 'runs when' => t('After a user account has been created'), 2261 ), 2262 'update' => array( 2263 'runs when' => t("After a user's profile has been updated"), 2264 ), 2265 'delete' => array( 2266 'runs when' => t('After a user has been deleted') 2267 ), 2268 'login' => array( 2269 'runs when' => t('After a user has logged in') 2270 ), 2271 'logout' => array( 2272 'runs when' => t('After a user has logged out') 2273 ), 2274 'view' => array( 2275 'runs when' => t("When a user's profile is being viewed") 2276 ), 2277 ), 2278 ), 2279 ); 2280 } 2281 2282 /** 2283 * Implementation of hook_action_info(). 2284 */ 2285 function user_action_info() { 2286 return array( 2287 'user_block_user_action' => array( 2288 'description' => t('Block current user'), 2289 'type' => 'user', 2290 'configurable' => FALSE, 2291 'hooks' => array(), 2292 ), 2293 'user_block_ip_action' => array( 2294 'description' => t('Ban IP address of current user'), 2295 'type' => 'user', 2296 'configurable' => FALSE, 2297 'hooks' => array(), 2298 ), 2299 ); 2300 } 2301 2302 /** 2303 * Implementation of a Drupal action. 2304 * Blocks the current user. 2305 */ 2306 function user_block_user_action(&$object, $context = array()) { 2307 if (isset($object->uid)) { 2308 $uid = $object->uid; 2309 } 2310 elseif (isset($context['uid'])) { 2311 $uid = $context['uid']; 2312 } 2313 else { 2314 global $user; 2315 $uid = $user->uid; 2316 } 2317 db_query("UPDATE {users} SET status = 0 WHERE uid = %d", $uid); 2318 sess_destroy_uid($uid); 2319 watchdog('action', 'Blocked user %name.', array('%name' => check_plain($user->name))); 2320 } 2321 2322 /** 2323 * Implementation of a Drupal action. 2324 * Adds an access rule that blocks the user's IP address. 2325 */ 2326 function user_block_ip_action() { 2327 $ip = ip_address(); 2328 db_query("INSERT INTO {access} (mask, type, status) VALUES ('%s', '%s', %d)", $ip, 'host', 0); 2329 watchdog('action', 'Banned IP address %ip', array('%ip' => $ip)); 2330 } 2331 2332 /** 2333 * Submit handler for the user registration form. 2334 * 2335 * This function is shared by the installation form and the normal registration form, 2336 * which is why it can't be in the user.pages.inc file. 2337 */ 2338 function user_register_submit($form, &$form_state) { 2339 global $base_url; 2340 $admin = user_access('administer users'); 2341 2342 $mail = $form_state['values']['mail']; 2343 $name = $form_state['values']['name']; 2344 if (!variable_get('user_email_verification', TRUE) || $admin) { 2345 $pass = $form_state['values']['pass']; 2346 } 2347 else { 2348 $pass = user_password(); 2349 }; 2350 $notify = isset($form_state['values']['notify']) ? $form_state['values']['notify'] : NULL; 2351 $from = variable_get('site_mail', ini_get('sendmail_from')); 2352 if (isset($form_state['values']['roles'])) { 2353 // Remove unset roles. 2354 $roles = array_filter($form_state['values']['roles']); 2355 } 2356 else { 2357 $roles = array(); 2358 } 2359 2360 if (!$admin && array_intersect(array_keys($form_state['values']), array('uid', 'roles', 'init', 'session', 'status'))) { 2361 watchdog('security', 'Detected malicious attempt to alter protected user fields.', array(), WATCHDOG_WARNING); 2362 $form_state['redirect'] = 'user/register'; 2363 return; 2364 } 2365 // The unset below is needed to prevent these form values from being saved as 2366 // user data. 2367 unset($form_state['values']['form_token'], $form_state['values']['submit'], $form_state['values']['op'], $form_state['values']['notify'], $form_state['values']['form_id'], $form_state['values']['affiliates'], $form_state['values']['destination']); 2368 2369 $merge_data = array('pass' => $pass, 'init' => $mail, 'roles' => $roles); 2370 if (!$admin) { 2371 // Set the user's status because it was not displayed in the form. 2372 $merge_data['status'] = variable_get('user_register', 1) == 1; 2373 } 2374 $account = user_save('', array_merge($form_state['values'], $merge_data)); 2375 // Terminate if an error occured during user_save(). 2376 if (!$account) { 2377 drupal_set_message(t("Error saving user account."), 'error'); 2378 $form_state['redirect'] = ''; 2379 return; 2380 } 2381 $form_state['user'] = $account; 2382 2383 watchdog('user', 'New user: %name (%email).', array('%name' => $name, '%email' => $mail), WATCHDOG_NOTICE, l(t('edit'), 'user/'. $account->uid .'/edit')); 2384 2385 // The first user may login immediately, and receives a customized welcome e-mail. 2386 if ($account->uid == 1) { 2387 drupal_set_message(t('Welcome to Drupal. You are now logged in as user #1, which gives you full control over your website.')); 2388 if (variable_get('user_email_verification', TRUE)) { 2389 drupal_set_message(t('</p><p> Your password is <strong>%pass</strong>. You may change your password below.</p>', array('%pass' => $pass))); 2390 } 2391 2392 user_authenticate(array_merge($form_state['values'], $merge_data)); 2393 2394 $form_state['redirect'] = 'user/1/edit'; 2395 return; 2396 } 2397 else { 2398 // Add plain text password into user account to generate mail tokens. 2399 $account->password = $pass; 2400 if ($admin && !$notify) { 2401 drupal_set_message(t('Created a new user account for <a href="@url">%name</a>. No e-mail has been sent.', array('@url' => url("user/$account->uid"), '%name' => $account->name))); 2402 } 2403 else if (!variable_get('user_email_verification', TRUE) && $account->status && !$admin) { 2404 // No e-mail verification is required, create new user account, and login 2405 // user immediately. 2406 _user_mail_notify('register_no_approval_required', $account); 2407 if (user_authenticate(array_merge($form_state['values'], $merge_data))) { 2408 drupal_set_message(t('Registration successful. You are now logged in.')); 2409 } 2410 $form_state['redirect'] = ''; 2411 return; 2412 } 2413 else if ($account->status || $notify) { 2414 // Create new user account, no administrator approval required. 2415 $op = $notify ? 'register_admin_created' : 'register_no_approval_required'; 2416 _user_mail_notify($op, $account); 2417 if ($notify) { 2418 drupal_set_message(t('Password and further instructions have been e-mailed to the new user <a href="@url">%name</a>.', array('@url' => url("user/$account->uid"), '%name' => $account->name))); 2419 } 2420 else { 2421 drupal_set_message(t('Your password and further instructions have been sent to your e-mail address.')); 2422 $form_state['redirect'] = ''; 2423 return; 2424 } 2425 } 2426 else { 2427 // Create new user account, administrator approval required. 2428 _user_mail_notify('register_pending_approval', $account); 2429 drupal_set_message(t('Thank you for applying for an account. Your account is currently pending approval by the site administrator.<br />In the meantime, a welcome message with further instructions has been sent to your e-mail address.')); 2430 $form_state['redirect'] = ''; 2431 return; 2432 2433 } 2434 } 2435 } 2436 2437 /** 2438 * Form builder; The user registration form. 2439 * 2440 * @ingroup forms 2441 * @see user_register_validate() 2442 * @see user_register_submit() 2443 */ 2444 function user_register() { 2445 global $user; 2446 2447 $admin = user_access('administer users'); 2448 2449 // If we aren't admin but already logged on, go to the user page instead. 2450 if (!$admin && $user->uid) { 2451 drupal_goto('user/'. $user->uid); 2452 } 2453 2454 $form = array(); 2455 2456 // Display the registration form. 2457 if (!$admin) { 2458 $form['user_registration_help'] = array( 2459 '#value' => filter_xss_admin(variable_get('user_registration_help', '')), 2460 // Ensure that user registration help appears above profile fields. 2461 '#weight' => -20, 2462 ); 2463 } 2464 2465 // Merge in the default user edit fields. 2466 $form = array_merge($form, user_edit_form($form_state, NULL, NULL, TRUE)); 2467 if ($admin) { 2468 $form['account']['notify'] = array( 2469 '#type' => 'checkbox', 2470 '#title' => t('Notify user of new account') 2471 ); 2472 // Redirect back to page which initiated the create request; 2473 // usually admin/user/user/create. 2474 $form['destination'] = array('#type' => 'hidden', '#value' => $_GET['q']); 2475 } 2476 2477 // Create a dummy variable for pass-by-reference parameters. 2478 $null = NULL; 2479 $extra = _user_forms($null, NULL, NULL, 'register'); 2480 2481 // Remove form_group around default fields if there are no other groups. 2482 if (!$extra) { 2483 foreach (array('name', 'mail', 'pass', 'status', 'roles', 'notify') as $key) { 2484 if (isset($form['account'][$key])) { 2485 $form[$key] = $form['account'][$key]; 2486 } 2487 } 2488 unset($form['account']); 2489 } 2490 else { 2491 $form = array_merge($form, $extra); 2492 } 2493 2494 if (variable_get('configurable_timezones', 1)) { 2495 // Override field ID, so we only change timezone on user registration, 2496 // and never touch it on user edit pages. 2497 $form['timezone'] = array( 2498 '#type' => 'hidden', 2499 '#default_value' => variable_get('date_default_timezone', NULL), 2500 '#id' => 'edit-user-register-timezone', 2501 ); 2502 2503 // Add the JavaScript callback to automatically set the timezone. 2504 drupal_add_js(' 2505 // Global Killswitch 2506 if (Drupal.jsEnabled) { 2507 $(document).ready(function() { 2508 Drupal.setDefaultTimezone(); 2509 }); 2510 }', 'inline'); 2511 } 2512 2513 $form['submit'] = array('#type' => 'submit', '#value' => t('Create new account'), '#weight' => 30); 2514 $form['#validate'][] = 'user_register_validate'; 2515 2516 return $form; 2517 } 2518 2519 function user_register_validate($form, &$form_state) { 2520 $account = (object) $form_state['values']; 2521 user_module_invoke('validate', $form_state['values'], $account, 'account'); 2522 } 2523 2524 /** 2525 * Retrieve a list of all form elements for the specified category. 2526 */ 2527 function _user_forms(&$edit, $account, $category, $hook = 'form') { 2528 $groups = array(); 2529 foreach (module_list() as $module) { 2530 $function = $module .'_user'; 2531 // $edit and $account need to be passed by reference. 2532 if (function_exists($function) && ($data = $function($hook, $edit, $account, $category))) { 2533 $groups = array_merge_recursive($data, $groups); 2534 } 2535 } 2536 uasort($groups, '_user_sort'); 2537 2538 return empty($groups) ? FALSE : $groups; 2539 } 2540 2541 /** 2542 * Prepare a destination query string for use in combination with drupal_goto(). 2543 * 2544 * Used to direct the user back to the referring page after completing 2545 * the openid login. This function prevents the login page from being 2546 * returned because that page will give an access denied message to an 2547 * authenticated user. 2548 * 2549 * @see drupal_get_destination() 2550 */ 2551 function user_login_destination() { 2552 $destination = drupal_get_destination(); 2553 return $destination == 'destination=user%2Flogin' ? 'destination=user' : $destination; 2554 } 2555 2556 /** 2557 * Menu access callback; limit access to account deletion pages. 2558 * 2559 * Limit access to administrative users, and prevent the anonymous user account 2560 * from being deleted. 2561 */ 2562 function user_delete_access($account) { 2563 return user_access('administer users') && $account->uid > 0; 2564 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
| Generated: Mon Jul 9 18:01:44 2012 | Cross-referenced by PHPXref 0.7 |