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