[ Index ]

PHP Cross Reference of Drupal 6 (yi-drupal)

title

Body

[close]

/modules/user/ -> user.module (source)

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


Generated: Mon Jul 9 18:01:44 2012 Cross-referenced by PHPXref 0.7