Skip to content
user.module 93.4 KiB
Newer Older
Dries Buytaert's avatar
 
Dries Buytaert committed
<?php

Dries Buytaert's avatar
 
Dries Buytaert committed
/**
 * @file
 * Enables the user registration and login system.
 */

define('USERNAME_MAX_LENGTH', 60);
define('EMAIL_MAX_LENGTH', 64);

/**
 * Invokes hook_user() in every module.
 *
 * We cannot use module_invoke() for this, because the arguments need to
 * be passed by reference.
 *
 * @param $op
 *   The operation to be passed as the first parameter of the hook function.
 * @param $edit
 *   An associative array variable containing form values to be passed
 *   as the second parameter of the hook function.
 * @param $account
 *   The user account object to be passed as the third parameter of the hook
 *   function.
 * @param $category
 *   The category of user information being acted upon.
function user_module_invoke($op, &$edit, &$account, $category = NULL) {
Dries Buytaert's avatar
 
Dries Buytaert committed
  foreach (module_list() as $module) {
    $function = $module .'_user';
    if (function_exists($function)) {
      $function($op, $edit, $account, $category);
Dries Buytaert's avatar
 
Dries Buytaert committed
  }
}

 */
function user_theme() {
  return array(
    'user_picture' => array(
      'arguments' => array('account' => NULL),
    ),
    'user_profile_category' => array(
      'arguments' => array('element' => NULL),
      'template' => 'user-profile-category',
    ),
    'user_profile_item' => array(
      'arguments' => array('element' => NULL),
    ),
    'user_list' => array(
      'arguments' => array('users' => NULL, 'title' => NULL),
    ),
    'user_admin_perm' => array(
      'arguments' => array('form' => NULL),
    ),
    'user_admin_new_role' => array(
      'arguments' => array('form' => NULL),
    ),
    'user_admin_account' => array(
      'arguments' => array('form' => NULL),
    ),
    'user_filter_form' => array(
      'arguments' => array('form' => NULL),
    ),
    'user_filters' => array(
      'arguments' => array('form' => NULL),
    'user_signature' => array(
      'arguments' => array('signature' => NULL),
    ),
Dries Buytaert's avatar
 
Dries Buytaert committed
function user_external_load($authname) {
Dries Buytaert's avatar
 
Dries Buytaert committed
  $result = db_query("SELECT uid FROM {authmap} WHERE authname = '%s'", $authname);
Dries Buytaert's avatar
 
Dries Buytaert committed

  if ($user = db_fetch_array($result)) {
Dries Buytaert's avatar
 
Dries Buytaert committed
    return user_load($user);
Dries Buytaert's avatar
 
Dries Buytaert committed
  }
  else {
    return 0;
  }
}

 * Perform standard Drupal login operations for a user object.
 *
 * The user object must already be authenticated. This function verifies
 * that the user account is not blocked/denied and then performs the login,
 * updates the login timestamp in the database, invokes hook_user('login'),
 *
 * @param $account
 *    An authenticated user object to be set as the currently logged
 *    in user.
 * @param $edit
 *    The array of form values submitted by the user, if any.
 *    This array is passed to hook_user op login.
 * @return boolean
 *    TRUE if the login succeeds, FALSE otherwise.
 */
function user_external_login($account, $edit = array()) {
  $state['values'] = $edit;
  if (empty($state['values']['name'])) {
    $state['values']['name'] = $account->name;
  }

  // Check if user is blocked or denied by access rules.
  user_login_name_validate($form, $state, (array)$account);
  if (form_get_errors()) {
  user_authenticate_finalize($state['values']);
/**
 * Fetch a user object.
 *
 * @param $user_info
 *   Information about the user to load, consisting of one of the following:
 *   - An associative array whose keys are fields in the {users} table (such as
 *     uid, name, pass, mail, status) and whose values are the field's value.
 *   - A numeric user ID.
 *   A fully-loaded $user object upon successful user load or FALSE if user
 *   cannot be loaded.
  // Dynamically compose a SQL query:
  if (is_numeric($user_info)) {
    $user_info = array('uid' => $user_info);
    if ($key == 'uid' || $key == 'status') {
      $query[] = "$key = %d";
    else if ($key == 'pass') {
      $query[] = "pass = '%s'";
      $params[] = md5($value);
    }
Dries Buytaert's avatar
 
Dries Buytaert committed
    else {
      $query[]= "LOWER($key) = LOWER('%s')";
Dries Buytaert's avatar
 
Dries Buytaert committed
    }
  }
  $result = db_query('SELECT * FROM {users} u WHERE '. implode(' AND ', $query), $params);
Dries Buytaert's avatar
 
Dries Buytaert committed

  if ($user = db_fetch_object($result)) {
Dries Buytaert's avatar
 
Dries Buytaert committed

    if ($user->uid) {
      $user->roles[DRUPAL_AUTHENTICATED_RID] = 'authenticated user';
    }
    else {
      $user->roles[DRUPAL_ANONYMOUS_RID] = 'anonymous user';
    }
    $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);
    while ($role = db_fetch_object($result)) {
      $user->roles[$role->rid] = $role->name;
    }
    user_module_invoke('load', $user_info, $user);
Dries Buytaert's avatar
 
Dries Buytaert committed
  }
Dries Buytaert's avatar
 
Dries Buytaert committed

  return $user;
}

 * Save changes to a user account or add a new user.
 *   The user object for to modify or add. If you want to modify an existing
 *   user account, you will need to ensure that (a) $account is an object, and
 *   (b) you have set $account->uid to the numeric user ID of the user account
 *   you wish to modify. Pass in NULL or any non-object to add a new user.
 *   (optional) An array of fields and values to save. For example,
 *   array('name' => 'My name'); Keys that do not belong to columns
 *   in the user-related tables are added to the a serialized array
 *   in the 'data' column and will be loaded in the $user->data array by
 *   user_load(). Setting a field to NULL deletes it from the data column,
 *   if you are modifying an existing user account.
 * @param $category
 *   (optional) The category for storing profile information in.
 *
 * @return
 *   A fully-loaded $user object upon successful save or FALSE if the save failed.
function user_save($account, $array = array(), $category = 'account') {
  // Dynamically compose a SQL query:
  $user_fields = user_fields();
  if (is_object($account) && $account->uid) {
    user_module_invoke('update', $array, $account, $category);
    $data = unserialize(db_result(db_query('SELECT data FROM {users} WHERE uid = %d', $account->uid)));
    // Consider users edited by an administrator as logged in, if they haven't
    // already, so anonymous users can view the profile (if allowed).
    if (empty($array['access']) && empty($account->access) && user_access('administer users')) {
      $array['access'] = time();
    }
Dries Buytaert's avatar
 
Dries Buytaert committed
    foreach ($array as $key => $value) {
      if ($key == 'pass' && !empty($value)) {
Dries Buytaert's avatar
 
Dries Buytaert committed
        $query .= "$key = '%s', ";
        $v[] = md5($value);
Dries Buytaert's avatar
 
Dries Buytaert committed
      }
      else if ((substr($key, 0, 4) !== 'auth') && ($key != 'pass')) {
        if (in_array($key, $user_fields)) {
Dries Buytaert's avatar
 
Dries Buytaert committed
          $query .= "$key = '%s', ";
          $v[] = $value;
Dries Buytaert's avatar
 
Dries Buytaert committed
        }
Dries Buytaert's avatar
 
Dries Buytaert committed
        else if ($key != 'roles') {
Dries Buytaert's avatar
 
Dries Buytaert committed
        }
Dries Buytaert's avatar
 
Dries Buytaert committed
      }
    }
Dries Buytaert's avatar
 
Dries Buytaert committed
    $v[] = serialize($data);
Dries Buytaert's avatar
 
Dries Buytaert committed

    $success = db_query("UPDATE {users} SET $query WHERE uid = %d", array_merge($v, array($account->uid)));
    if (!$success) {
      // The query failed - better to abort the save than risk further data loss.
      return FALSE;
    }
Dries Buytaert's avatar
 
Dries Buytaert committed

    if (isset($array['roles']) && is_array($array['roles'])) {
      db_query('DELETE FROM {users_roles} WHERE uid = %d', $account->uid);
Dries Buytaert's avatar
 
Dries Buytaert committed

      foreach (array_keys($array['roles']) as $rid) {
        if (!in_array($rid, array(DRUPAL_ANONYMOUS_RID, DRUPAL_AUTHENTICATED_RID))) {
          db_query('INSERT INTO {users_roles} (uid, rid) VALUES (%d, %d)', $account->uid, $rid);
        }
Dries Buytaert's avatar
 
Dries Buytaert committed
    }

    // Delete a blocked user's sessions to kick them if they are online.
    if (isset($array['status']) && $array['status'] == 0) {
    // If the password changed, delete all open sessions and recreate
    // the current one.
      if ($account->uid == $GLOBALS['user']->uid) {
        sess_regenerate();
      }
Dries Buytaert's avatar
 
Dries Buytaert committed
    $user = user_load(array('uid' => $account->uid));

    // Send emails after we have the new user object.
    if (isset($array['status']) && $array['status'] != $account->status) {
      // The user's status is changing; conditionally send notification email.
      $op = $array['status'] == 1 ? 'status_activated' : 'status_blocked';
      _user_mail_notify($op, $user);
    }

    user_module_invoke('after_update', $array, $user, $category);
Dries Buytaert's avatar
 
Dries Buytaert committed
  }
  else {
    // Allow 'created' to be set by the caller.
    if (!isset($array['created'])) {
      $array['created'] = time();
    }
    // Consider users created by an administrator as already logged in, so
    // anonymous users can view the profile (if allowed).
    if (empty($array['access']) && user_access('administer users')) {
      $array['access'] = time();
    }
    // Note: we wait to save the data column to prevent module-handled
    // fields from being saved there. We cannot invoke hook_user('insert') here
    // because we don't have a fully initialized user object yet.
Dries Buytaert's avatar
 
Dries Buytaert committed
    foreach ($array as $key => $value) {
Dries Buytaert's avatar
 
Dries Buytaert committed
          $s[] = "'%s'";
        case 'mode':       case 'sort':     case 'timezone':
        case 'threshold':  case 'created':  case 'access':
        case 'login':      case 'status':
          $fields[] = $key;
          $values[] = $value;
          $s[] = "%d";
          break;
        default:
          if (substr($key, 0, 4) !== 'auth' && in_array($key, $user_fields)) {
            $fields[] = $key;
            $values[] = $value;
            $s[] = "'%s'";
          }
          break;
Dries Buytaert's avatar
 
Dries Buytaert committed
      }
    }
    $success = db_query('INSERT INTO {users} ('. implode(', ', $fields) .') VALUES ('. implode(', ', $s) .')', $values);
    if (!$success) {
      // On a failed INSERT some other existing user's uid may be returned.
      // We must abort to avoid overwriting their account.
    // Build the initial user object.
    $array['uid'] = db_last_insert_id('users', 'uid');
    $user = user_load(array('uid' => $array['uid']));
Dries Buytaert's avatar
 
Dries Buytaert committed

    user_module_invoke('insert', $array, $user, $category);

    // Build and save the serialized data field now.
    $data = array();
    foreach ($array as $key => $value) {
      if ((substr($key, 0, 4) !== 'auth') && ($key != 'roles') && (!in_array($key, $user_fields)) && ($value !== NULL)) {
        $data[$key] = $value;
      }
    }
    db_query("UPDATE {users} SET data = '%s' WHERE uid = %d", serialize($data), $user->uid);

    // Save user roles (delete just to be safe).
    if (isset($array['roles']) && is_array($array['roles'])) {
      db_query('DELETE FROM {users_roles} WHERE uid = %d', $array['uid']);
      foreach (array_keys($array['roles']) as $rid) {
        if (!in_array($rid, array(DRUPAL_ANONYMOUS_RID, DRUPAL_AUTHENTICATED_RID))) {
          db_query('INSERT INTO {users_roles} (uid, rid) VALUES (%d, %d)', $array['uid'], $rid);
        }
    // Build the finished user object.
    $user = user_load(array('uid' => $array['uid']));
Dries Buytaert's avatar
 
Dries Buytaert committed
  }

  $authmaps = array();
Dries Buytaert's avatar
 
Dries Buytaert committed
  foreach ($array as $key => $value) {
Dries Buytaert's avatar
 
Dries Buytaert committed
    if (substr($key, 0, 4) == 'auth') {
Dries Buytaert's avatar
 
Dries Buytaert committed
      $authmaps[$key] = $value;
    }
  }
  if (sizeof($authmaps) > 0) {
Dries Buytaert's avatar
 
Dries Buytaert committed
    user_set_authmaps($user, $authmaps);
Dries Buytaert's avatar
 
Dries Buytaert committed
  }

  return $user;
}

/**
 * Verify the syntax of the given name.
 */
Dries Buytaert's avatar
 
Dries Buytaert committed
function user_validate_name($name) {
  if (!strlen($name)) {
    return t('You must enter a username.');
  }
  if (substr($name, 0, 1) == ' ') {
    return t('The username cannot begin with a space.');
  }
  if (substr($name, -1) == ' ') {
    return t('The username cannot end with a space.');
  }
  if (strpos($name, '  ') !== FALSE) {
    return t('The username cannot contain multiple spaces in a row.');
  }
  if (preg_match('/[^\x{80}-\x{F7} a-z0-9@_.\'-]/i', $name)) {
    return t('The username contains an illegal character.');
  }
  if (preg_match('/[\x{80}-\x{A0}'.          // Non-printable ISO-8859-1 + NBSP
                   '\x{AD}'.                 // Soft-hyphen
                   '\x{2000}-\x{200F}'.      // Various space characters
                   '\x{2028}-\x{202F}'.      // Bidirectional text overrides
                   '\x{205F}-\x{206F}'.      // Various text hinting characters
                   '\x{FEFF}'.               // Byte order mark
                   '\x{FF01}-\x{FF60}'.      // Full-width latin
                   '\x{FFF9}-\x{FFFD}'.      // Replacement characters
                   '\x{0}-\x{1F}]/u',        // NULL byte and control characters
                   $name)) {
    return t('The username contains an illegal character.');
  }
  if (drupal_strlen($name) > USERNAME_MAX_LENGTH) {
    return t('The username %name is too long: it must be %max characters or less.', array('%name' => $name, '%max' => USERNAME_MAX_LENGTH));
  }
Dries Buytaert's avatar
 
Dries Buytaert committed
}

function user_validate_mail($mail) {
  if (!$mail) return t('You must enter an e-mail address.');
  if (!valid_email_address($mail)) {
    return t('The e-mail address %mail is not valid.', array('%mail' => $mail));
Dries Buytaert's avatar
 
Dries Buytaert committed
  }
}

function user_validate_picture(&$form, &$form_state) {
  // If required, validate the uploaded picture.
  $validators = array(
    'file_validate_is_image' => array(),
    'file_validate_image_resolution' => array(variable_get('user_picture_dimensions', '85x85')),
    'file_validate_size' => array(variable_get('user_picture_file_size', '30') * 1024),
  );
  if ($file = file_save_upload('picture_upload', $validators)) {
    // Remove the old picture.
    if (isset($form_state['values']['_account']->picture) && file_exists($form_state['values']['_account']->picture)) {
      file_delete($form_state['values']['_account']->picture);
    }

    // The image was saved using file_save_upload() and was added to the
    // files table as a temporary file. We'll make a copy and let the garbage
    // collector delete the original upload.
    $info = image_get_info($file->filepath);
    $destination = variable_get('user_picture_path', 'pictures') .'/picture-'. $form['#uid'] .'.'. $info['extension'];
    if (file_copy($file, $destination, FILE_EXISTS_REPLACE)) {
      $form_state['values']['picture'] = $file->filepath;
    else {
      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'))));
Dries Buytaert's avatar
 
Dries Buytaert committed
  }
}

/**
 * Generate a random alphanumeric password.
 */
Dries Buytaert's avatar
 
Dries Buytaert committed
function user_password($length = 10) {
  // This variable contains the list of allowable characters for the
  // password. Note that the number 0 and the letter 'O' have been
  // removed to avoid confusion between the two. The same is true
  $allowable_characters = 'abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789';
  // Zero-based count of characters in the allowable list:
  $len = strlen($allowable_characters) - 1;
Dries Buytaert's avatar
 
Dries Buytaert committed

  // Declare the password as a blank string.
  $pass = '';
Dries Buytaert's avatar
 
Dries Buytaert committed

  // Loop the number of times specified by $length.
Dries Buytaert's avatar
 
Dries Buytaert committed
  for ($i = 0; $i < $length; $i++) {

    // Each iteration, pick a random character from the
    // allowable string and append it to the password:
    $pass .= $allowable_characters[mt_rand(0, $len)];
Dries Buytaert's avatar
 
Dries Buytaert committed
  }

  return $pass;
Dries Buytaert's avatar
 
Dries Buytaert committed
}

/**
 * Determine whether the user has a given privilege.
 *
 * @param $string
 *   The permission, such as "administer nodes", being checked for.
Dries Buytaert's avatar
 
Dries Buytaert committed
 * @param $account
 *   (optional) The account to check, if not given use currently logged in user.
 * @param $reset
 *   (optional) Resets the user's permissions cache, which will result in a
 *   recalculation of the user's permissions. This is necessary to support
 *   dynamically added user roles.
 *   Boolean TRUE if the current user has the requested permission.
 *
 * All permission checks in Drupal should go through this function. This
 * way, we guarantee consistent behavior, and ensure that the superuser
 * can perform all actions.
 */
function user_access($string, $account = NULL, $reset = FALSE) {
Dries Buytaert's avatar
 
Dries Buytaert committed
  global $user;
Dries Buytaert's avatar
 
Dries Buytaert committed
  static $perm = array();
Dries Buytaert's avatar
 
Dries Buytaert committed

Dries Buytaert's avatar
 
Dries Buytaert committed
  }

  // To reduce the number of SQL queries, we cache the user's permissions
  // in a static variable.
    $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));
Dries Buytaert's avatar
 
Dries Buytaert committed

Dries Buytaert's avatar
 
Dries Buytaert committed
    while ($row = db_fetch_object($result)) {
      $perms += array_flip(explode(', ', $row->perm));
Dries Buytaert's avatar
 
Dries Buytaert committed
    }
Dries Buytaert's avatar
 
Dries Buytaert committed
  }
  return isset($perm[$account->uid][$string]);
Dries Buytaert's avatar
 
Dries Buytaert committed
}

 * Checks for usernames blocked by user administration.
 * @param $name
 *   A string containing a name of the user.
 *
 * @return
 *   Object with property 'name' (the user name), if the user is blocked;
 *   FALSE if the user is not blocked.
  $deny = db_fetch_object(db_query("SELECT name FROM {users} WHERE status = 0 AND name = LOWER('%s')", $name));
Dries Buytaert's avatar
 
Dries Buytaert committed
function user_fields() {
  static $fields;
Dries Buytaert's avatar
 
Dries Buytaert committed

Dries Buytaert's avatar
 
Dries Buytaert committed
  if (!$fields) {
    $result = db_query('SELECT * FROM {users} WHERE uid = 1');
    if ($field = db_fetch_array($result)) {
      $fields = array_keys($field);
Dries Buytaert's avatar
 
Dries Buytaert committed
    else {
      // Make sure we return the default fields at least.
Gábor Hojtsy's avatar
Gábor Hojtsy committed
      $fields = array('uid', 'name', 'pass', 'mail', 'picture', 'mode', 'sort', 'threshold', 'theme', 'signature', 'signature_format', 'created', 'access', 'login', 'status', 'timezone', 'language', 'init', 'data');
Dries Buytaert's avatar
 
Dries Buytaert committed
    }
Dries Buytaert's avatar
 
Dries Buytaert committed
  }
Dries Buytaert's avatar
 
Dries Buytaert committed

Dries Buytaert's avatar
 
Dries Buytaert committed
  return $fields;
Dries Buytaert's avatar
 
Dries Buytaert committed
}

/**
 * Implementation of hook_perm().
 */
Dries Buytaert's avatar
 
Dries Buytaert committed
function user_perm() {
  return array('administer permissions', 'administer users', 'access user profiles', 'change own username');
Dries Buytaert's avatar
 
Dries Buytaert committed
}

/**
 * Implementation of hook_file_download().
 *
 * Ensure that user pictures (avatars) are always downloadable.
 */
Dries Buytaert's avatar
 
Dries Buytaert committed
function user_file_download($file) {
Steven Wittens's avatar
Steven Wittens committed
  if (strpos($file, variable_get('user_picture_path', 'pictures') .'/picture-') === 0) {
    $info = image_get_info(file_create_path($file));
    return array('Content-type: '. $info['mime_type']);
Dries Buytaert's avatar
 
Dries Buytaert committed
  }
}

/**
 * Implementation of hook_search().
 */
function user_search($op = 'search', $keys = NULL, $skip_access_check = FALSE) {
      if ($skip_access_check || user_access('access user profiles')) {
      if (user_access('access user profiles')) {
        $find = array();
        // Replace wildcards with MySQL/PostgreSQL wildcards.
        $keys = preg_replace('!\*+!', '%', $keys);
Gábor Hojtsy's avatar
Gábor Hojtsy committed
          // Administrators can also search in the otherwise private email
          // field, and they don't need to be restricted to only active users.
          $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);
          while ($account = db_fetch_object($result)) {
            $find[] = array('title' => $account->name .' ('. $account->mail .')', 'link' => url('user/'. $account->uid, array('absolute' => TRUE)));
Gábor Hojtsy's avatar
Gábor Hojtsy committed
          // Regular users can only search via user names, and we do not show
          // them blocked accounts.
          $result = pager_query("SELECT name, uid FROM {users} WHERE status = 1 AND LOWER(name) LIKE LOWER('%%%s%%')", 15, 0, NULL, $keys);
            $find[] = array('title' => $account->name, 'link' => url('user/'. $account->uid, array('absolute' => TRUE)));
Dries Buytaert's avatar
 
Dries Buytaert committed
  }
}

/**
 * Implementation of hook_elements().
 */
function user_elements() {
  return array(
    'user_profile_category' => array(),
    'user_profile_item' => array(),
  );
}

/**
 * Implementation of hook_user().
 */
function user_user($type, &$edit, &$account, $category = NULL) {
  if ($type == 'view') {
    $account->content['user_picture'] = array(
      '#value' => theme('user_picture', $account),
      '#weight' => -10,
    );
    if (!isset($account->content['summary'])) {
      $account->content['summary'] = array();
    }
    $account->content['summary'] += array(
      '#type' => 'user_profile_category',
      '#attributes' => array('class' => 'user-member'),
    $account->content['summary']['member_for'] = array(
      '#type' => 'user_profile_item',
      '#title' => t('Member for'),
      '#value' => format_interval(time() - $account->created),
  if ($type == 'form' && $category == 'account') {
    return user_edit_form($form_state, (isset($account->uid) ? $account->uid : FALSE), $edit);
  }

  if ($type == 'validate' && $category == 'account') {
    return _user_edit_validate((isset($account->uid) ? $account->uid : FALSE), $edit);
  if ($type == 'submit' && $category == 'account') {
    return _user_edit_submit((isset($account->uid) ? $account->uid : FALSE), $edit);
  if ($type == 'categories') {
    return array(array('name' => 'account', 'title' => t('Account settings'), 'weight' => 1));
function user_login_block() {
  $form = array(
    '#action' => url($_GET['q'], array('query' => drupal_get_destination())),
    '#validate' => user_login_default_validators(),
    '#submit' => array('user_login_submit'),
  );
  $form['name'] = array('#type' => 'textfield',
    '#title' => t('Username'),
    '#size' => 15,
    '#required' => TRUE,
  );
  $form['pass'] = array('#type' => 'password',
    '#title' => t('Password'),
    '#size' => 15,
    '#required' => TRUE,
  );
  $form['submit'] = array('#type' => 'submit',
    '#value' => t('Log in'),
  );
  $items = array();
  if (variable_get('user_register', 1)) {
    $items[] = l(t('Create new account'), 'user/register', array('attributes' => array('title' => t('Create a new user account.'))));
  $items[] = l(t('Request new password'), 'user/password', array('attributes' => array('title' => t('Request new password via e-mail.'))));
  $form['links'] = array('#value' => theme('item_list', $items));
  return $form;
}

/**
 * Implementation of hook_block().
 */
function user_block($op = 'list', $delta = 0, $edit = array()) {
Dries Buytaert's avatar
 
Dries Buytaert committed
  global $user;

  if ($op == 'list') {
    $blocks[0]['info'] = t('User login');
    // Not worth caching.
    $blocks[0]['cache'] = BLOCK_NO_CACHE;
    $blocks[1]['info'] = t('Navigation');
    // Menu blocks can't be cached because each menu item can have
    // a custom access callback. menu.inc manages its own caching.
    $blocks[1]['cache'] = BLOCK_NO_CACHE;
    // Too dynamic to cache.
    $blocks[3]['info'] = t('Who\'s online');
    $blocks[3]['cache'] = BLOCK_NO_CACHE;
    return $blocks;
  else if ($op == 'configure' && $delta == 2) {
    $form['user_block_whois_new_count'] = array(
      '#type' => 'select',
      '#title' => t('Number of users to display'),
      '#default_value' => variable_get('user_block_whois_new_count', 5),
      '#options' => drupal_map_assoc(array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)),
    );
    return $form;
  }
  else if ($op == 'configure' && $delta == 3) {
    $period = drupal_map_assoc(array(30, 60, 120, 180, 300, 600, 900, 1800, 2700, 3600, 5400, 7200, 10800, 21600, 43200, 86400), 'format_interval');
    $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.'));
    $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.'));
  else if ($op == 'save' && $delta == 2) {
    variable_set('user_block_whois_new_count', $edit['user_block_whois_new_count']);
  }
  else if ($op == 'save' && $delta == 3) {
    variable_set('user_block_seconds_online', $edit['user_block_seconds_online']);
    variable_set('user_block_max_list_count', $edit['user_block_max_list_count']);
  }
  else if ($op == 'view') {
Dries Buytaert's avatar
 
Dries Buytaert committed
    $block = array();

Dries Buytaert's avatar
 
Dries Buytaert committed
    switch ($delta) {
      case 0:
Dries Buytaert's avatar
Dries Buytaert committed
        // For usability's sake, avoid showing two login forms on one page.
        if (!$user->uid && !(arg(0) == 'user' && !is_numeric(arg(1)))) {
Dries Buytaert's avatar
 
Dries Buytaert committed

          $block['subject'] = t('User login');
          $block['content'] = drupal_get_form('user_login_block');
Dries Buytaert's avatar
 
Dries Buytaert committed
        }
Dries Buytaert's avatar
Dries Buytaert committed
        return $block;
          $block['subject'] = $user->uid ? check_plain($user->name) : t('Navigation');
          $block['content'] = $menu;
Dries Buytaert's avatar
 
Dries Buytaert committed
        }
Dries Buytaert's avatar
 
Dries Buytaert committed
      case 2:
Steven Wittens's avatar
Steven Wittens committed
          // Retrieve a list of new users who have subsequently accessed the site successfully.
          $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));
          while ($account = db_fetch_object($result)) {
          $output = theme('user_list', $items);
Dries Buytaert's avatar
 
Dries Buytaert committed

          $block['subject'] = t('Who\'s new');
          $block['content'] = $output;
Dries Buytaert's avatar
Dries Buytaert committed
        return $block;

Dries Buytaert's avatar
 
Dries Buytaert committed
      case 3:
          // Count users active within the defined period.
          $interval = time() - variable_get('user_block_seconds_online', 900);
          // Perform database queries to gather online user lists.  We use s.timestamp
          // rather than u.access because it is much faster.
          $anonymous_count = sess_count($interval);
          $authenticated_count = db_result(db_query('SELECT COUNT(DISTINCT s.uid) FROM {sessions} s WHERE s.timestamp >= %d AND s.uid > 0', $interval));
Dries Buytaert's avatar
 
Dries Buytaert committed

          // Format the output with proper grammar.
          if ($anonymous_count == 1 && $authenticated_count == 1) {
            $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')));
Dries Buytaert's avatar
 
Dries Buytaert committed
          }
          else {
            $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')));
Dries Buytaert's avatar
 
Dries Buytaert committed
          }

          // Display a list of currently online users.
          $max_users = variable_get('user_block_max_list_count', 10);
          if ($authenticated_count && $max_users) {
            $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);
            while ($account = db_fetch_object($authenticated_users)) {
              $items[] = $account;
            }
            $output .= theme('user_list', $items, t('Online users'));
          }
          $block['subject'] = t('Who\'s online');
          $block['content'] = $output;
Dries Buytaert's avatar
 
Dries Buytaert committed
        }
Dries Buytaert's avatar
 
Dries Buytaert committed
        return $block;
Dries Buytaert's avatar
 
Dries Buytaert committed
    }
  }
/**
 * Process variables for user-picture.tpl.php.
 *
 * The $variables array contains the following arguments:
 * - $account
 *
 * @see user-picture.tpl.php
 */
function template_preprocess_user_picture(&$variables) {
  $variables['picture'] = '';
Dries Buytaert's avatar
 
Dries Buytaert committed
  if (variable_get('user_pictures', 0)) {
    $account = $variables['account'];
    if (!empty($account->picture) && file_exists($account->picture)) {
Dries Buytaert's avatar
 
Dries Buytaert committed
      $picture = file_create_url($account->picture);
    }
    else if (variable_get('user_picture_default', '')) {
      $picture = variable_get('user_picture_default', '');
    }

      $alt = t("@user's picture", array('@user' => $account->name ? $account->name : variable_get('anonymous', t('Anonymous'))));
      $variables['picture'] = theme('image', $picture, $alt, $alt, '', FALSE);
      if (!empty($account->uid) && user_access('access user profiles')) {
        $attributes = array('attributes' => array('title' => t('View user profile.')), 'html' => TRUE);
        $variables['picture'] = l($variables['picture'], "user/$account->uid", $attributes);
Dries Buytaert's avatar
 
Dries Buytaert committed
      }
    }
  }
}

 *
 * @param $users
 *   An array with user objects. Should contain at least the name and uid.
 * @param $title
 *  (optional) Title to pass on to theme_item_list().
 *
 * @ingroup themeable
 */
function theme_user_list($users, $title = NULL) {
  if (!empty($users)) {
    foreach ($users as $user) {
      $items[] = theme('username', $user);
    }
  return theme('item_list', $items, $title);
Dries Buytaert's avatar
 
Dries Buytaert committed
}

  // Menu administrators can see items for anonymous when administering.
  return !$GLOBALS['user']->uid || !empty($GLOBALS['menu_admin']);
}

function user_is_logged_in() {
  return (bool)$GLOBALS['user']->uid;
}

function user_register_access() {
  return user_is_anonymous() && variable_get('user_register', 1);
}

function user_view_access($account) {
  return $account && $account->uid &&
    (
      // Always let users view their own profile.
      ($GLOBALS['user']->uid == $account->uid) ||
      // Administrators can view all accounts.
      user_access('administer users') ||
      // The user is not blocked and logged in at least once.
      ($account->access && $account->status && user_access('access user profiles'))
    );
}

Gábor Hojtsy's avatar
Gábor Hojtsy committed
/**
 * Access callback for user account editing.
 */
  return (($GLOBALS['user']->uid == $account->uid) || user_access('administer users')) && $account->uid > 0;
}

function user_load_self($arg) {
  $arg[1] = user_load($GLOBALS['user']->uid);
  return $arg;
}

Dries Buytaert's avatar
 
Dries Buytaert committed
/**
Dries Buytaert's avatar
 
Dries Buytaert committed
 * Implementation of hook_menu().
Dries Buytaert's avatar
 
Dries Buytaert committed
 */
function user_menu() {
  $items['user/autocomplete'] = array(
    'access callback' => 'user_access',
    'access arguments' => array('access user profiles'),
    'type' => MENU_CALLBACK,
Dries Buytaert's avatar
 
Dries Buytaert committed

    'page callback' => 'user_page',
    'access callback' => TRUE,
    'type' => MENU_CALLBACK,
    'access callback' => 'user_is_anonymous',
Dries Buytaert's avatar
 
Dries Buytaert committed

    'page callback' => 'drupal_get_form',
    'page arguments' => array('user_register'),
    'access callback' => 'user_register_access',
    'type' => MENU_LOCAL_TASK,
    'page callback' => 'drupal_get_form',
    'page arguments' => array('user_pass'),
    'access callback' => 'user_is_anonymous',
    'page callback' => 'drupal_get_form',
    'page arguments' => array('user_pass_reset', 2, 3, 4),
    'access callback' => TRUE,
    'type' => MENU_CALLBACK,
    'title' => 'User management',
    'description' => "Manage your site's users, groups and access to site features.",
    'position' => 'left',
    'page callback' => 'system_admin_menu_block_page',
    'access arguments' => array('access administration pages'),
    'file' => 'system.admin.inc',
    'file path' => drupal_get_path('module', 'system'),
    'title' => 'Users',
    'description' => 'List, add, and edit users.',
    'page callback' => 'user_admin',
    'page arguments' => array('list'),
    'access arguments' => array('administer users'),
    'file' => 'user.admin.inc',
  );
    'type' => MENU_DEFAULT_LOCAL_TASK,
    'weight' => -10,
  );
  $items['admin/user/user/create'] = array(
Gábor Hojtsy's avatar
Gábor Hojtsy committed
    'access arguments' => array('administer users'),
    'title' => 'User settings',
    'description' => 'Configure default behavior of users, including registration requirements, e-mails, and user pictures.',
    'page callback' => 'drupal_get_form',
    'page arguments' => array('user_admin_settings'),