Newer
Older
/**
* Maximum length of username text field.
*/
define('USERNAME_MAX_LENGTH', 60);
/**
* Maximum length of user e-mail text field.
*/
Dries Buytaert
committed
define('EMAIL_MAX_LENGTH', 254);
Angie Byron
committed
/**
* Implement hook_help().
*/
function user_help($path, $arg) {
global $user;
switch ($path) {
case 'admin/help#user':
$output = '';
$output .= '<h3>' . t('About') . '</h3>';
$output .= '<p>' . t('The User module allows users to register, log in, and log out. It also allows users with proper permissions to manage user roles (used to classify users) and permissions associated with those roles. For more information, see the online handbook entry for <a href="@user">User module</a>.', array('@user' => 'http://drupal.org/handbook/modules/user')) . '</p>';
Angie Byron
committed
$output .= '<h3>' . t('Uses') . '</h3>';
$output .= '<dl>';
$output .= '<dt>' . t('Creating and managing users') . '</dt>';
Angie Byron
committed
$output .= '<dd>' . t('The User module allows users with the appropriate <a href="@permissions">permissions</a> to create user accounts through the <a href="@people">People administration page</a>, where they can also assign users to one or more roles, and block or delete user accounts. If allowed, users without accounts (anonymous users) can create their own accounts on the <a href="@register">Create new account</a> page.', array('@permissions' => url('admin/people/permissions', array('fragment' => 'module-user')), '@people' => url('admin/people'), '@register' => url('user/register'))) . '</dd>';
Angie Byron
committed
$output .= '<dt>' . t('User roles and permissions') . '</dt>';
Dries Buytaert
committed
$output .= '<dd>' . t('<em>Roles</em> are used to group and classify users; each user can be assigned one or more roles. By default there are two roles: <em>anonymous user</em> (users that are not logged in) and <em>authenticated user</em> (users that are registered and logged in). Depending on choices you made when you installed Drupal, the installation process may have defined more roles, and you can create additional custom roles on the <a href="@roles">Roles page</a>. After creating roles, you can set permissions for each role on the <a href="@permissions_user">Permissions page</a>. Granting a permission allows users who have been assigned a particular role to perform an action on the site, such as viewing a particular type of content, editing or creating content, administering settings for a particular module, or using a particular function of the site (such as search).', array('@permissions_user' => url('admin/people/permissions'), '@roles' => url('admin/people/permissions/roles'))) . '</dd>';
Angie Byron
committed
$output .= '<dt>' . t('Account settings') . '</dt>';
Dries Buytaert
committed
$output .= '<dd>' . t('The <a href="@accounts">Account settings page</a> allows you to manage settings for the displayed name of the anonymous user role, personal contact forms, user registration, and account cancellation. On this page you can also manage settings for account personalization (including signatures and user pictures), and adapt the text for the e-mail messages that are sent automatically during the user registration process.', array('@accounts' => url('admin/config/people/accounts'))) . '</dd>';
Angie Byron
committed
$output .= '</dl>';
return $output;
case 'admin/people/create':
return '<p>' . t("This web page allows administrators to register new users. Users' e-mail addresses and usernames must be unique.") . '</p>';
Angie Byron
committed
case 'admin/people/permissions':
Dries Buytaert
committed
return '<p>' . t('Permissions let you control what users can do and see on your site. You can define a specific set of permissions for each role. (See the <a href="@role">Roles</a> page to create a role). Two important roles to consider are Authenticated Users and Administrators. Any permissions granted to the Authenticated Users role will be given to any user who can log into your site. You can make any role the Administrator role for the site, meaning this will be granted all new permissions automatically. You can do this on the <a href="@settings">User Settings</a> page. You should be careful to ensure that only trusted users are given this access and level of control of your site.', array('@role' => url('admin/people/permissions/roles'), '@settings' => url('admin/config/people/accounts'))) . '</p>';
Angie Byron
committed
case 'admin/people/permissions/roles':
$output = '<p>' . t('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 on the <a href="@permissions">permissions page</a>. Examples of roles include: anonymous user, authenticated user, moderator, administrator and so on. In this area you will define the names and order of the roles on your site. It is recommended to order your roles from least permissive (anonymous user) to most permissive (administrator). To delete a role choose "edit role".', array('@permissions' => url('admin/people/permissions'))) . '</p>';
Angie Byron
committed
$output .= '<p>'. t('By default, Drupal comes with two user roles:') . '</p>';
$output .= '<ul>';
$output .= '<li>' . t("Anonymous user: this role is used for users that don't have a user account or that are not authenticated.") . '</li>';
$output .= '<li>' . t('Authenticated user: this role is automatically granted to all logged in users.') . '</li>';
$output .= '</ul>';
return $output;
case 'admin/config/people/accounts/fields':
return '<p>' . t('This form lets administrators add, edit, and arrange fields for storing user data.') . '</p>';
case 'admin/config/people/accounts/display':
return '<p>' . t('This form lets administrators configure how fields should be displayed when rendering a user profile page.') . '</p>';
case 'admin/people/search':
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>';
}
}
Angie Byron
committed
/**
* Invokes hook_user() in every module.
*
* We cannot use module_invoke() for this, because the arguments need to
Dries Buytaert
committed
function user_module_invoke($type, &$edit, $account, $category = NULL) {
Dries Buytaert
committed
foreach (module_implements('user_' . $type) as $module) {
Dries Buytaert
committed
$function = $module . '_user_' . $type;
Dries Buytaert
committed
$function($edit, $account, $category);
Dries Buytaert
committed
/**
Dries Buytaert
committed
* Implements hook_theme().
Dries Buytaert
committed
*/
function user_theme() {
return array(
'user_picture' => array(
'variables' => array('account' => NULL),
'template' => 'user-picture',
Dries Buytaert
committed
),
'user_profile' => array(
'render element' => 'elements',
'template' => 'user-profile',
'file' => 'user.pages.inc',
Steven Wittens
committed
),
'user_profile_category' => array(
'render element' => 'element',
'template' => 'user-profile-category',
'file' => 'user.pages.inc',
Steven Wittens
committed
),
'user_profile_item' => array(
'render element' => 'element',
'template' => 'user-profile-item',
'file' => 'user.pages.inc',
Dries Buytaert
committed
),
'user_list' => array(
'variables' => array('users' => NULL, 'title' => NULL),
Dries Buytaert
committed
),
Dries Buytaert
committed
'user_admin_permissions' => array(
'render element' => 'form',
'file' => 'user.admin.inc',
Dries Buytaert
committed
),
'user_admin_roles' => array(
'render element' => 'form',
'file' => 'user.admin.inc',
Dries Buytaert
committed
),
'user_filters' => array(
'render element' => 'form',
'file' => 'user.admin.inc',
Dries Buytaert
committed
),
Dries Buytaert
committed
'user_permission_description' => array(
'variables' => array('permission_item' => NULL, 'hide' => NULL),
'file' => 'user.admin.inc',
),
Dries Buytaert
committed
'user_signature' => array(
'variables' => array('signature' => NULL),
Dries Buytaert
committed
),
Dries Buytaert
committed
);
}
Dries Buytaert
committed
* Implements hook_entity_info().
Dries Buytaert
committed
function user_entity_info() {
'label' => t('User'),
Dries Buytaert
committed
'controller class' => 'UserController',
'base table' => 'users',
Angie Byron
committed
'uri callback' => 'user_uri',
Dries Buytaert
committed
'fieldable' => TRUE,
'entity keys' => array(
'id' => 'uid',
),
'bundles' => array(
'user' => array(
'label' => t('User'),
'admin' => array(
Dries Buytaert
committed
'path' => 'admin/config/people/accounts',
'access arguments' => array('administer users'),
),
),
),
'view modes' => array(
'full' => array(
'label' => t('User account'),
),
),
Angie Byron
committed
/**
Angie Byron
committed
* Entity uri callback.
Angie Byron
committed
*/
Angie Byron
committed
function user_uri($user) {
return array(
'path' => 'user/' . $user->uid,
);
Angie Byron
committed
}
Angie Byron
committed
/**
Dries Buytaert
committed
* Implements hook_field_extra_fields().
Angie Byron
committed
*/
function user_field_extra_fields() {
$return['user']['user'] = array(
'account' => array(
Angie Byron
committed
'label' => 'User name and password',
'description' => t('User module account form elements'),
'weight' => -10,
),
'timezone' => array(
Angie Byron
committed
'label' => 'Timezone',
'description' => t('User module timezone form element.'),
'weight' => 6,
),
'summary' => array(
Angie Byron
committed
'label' => 'History',
'description' => t('User module history view element.'),
'weight' => 5,
Angie Byron
committed
Angie Byron
committed
}
Angie Byron
committed
$uid = db_query("SELECT uid FROM {authmap} WHERE authname = :authname", array(':authname' => $authname))->fetchField();
Angie Byron
committed
if ($uid) {
return user_load($uid);
return FALSE;
Angie Byron
committed
* Load multiple users based on certain conditions.
Angie Byron
committed
* This function should be used whenever you need to load more than one user
* from the database. Users are loaded into memory and will not require
* database access if loaded again during the same page request.
Angie Byron
committed
* @param $uids
* An array of user IDs.
* @param $conditions
* An array of conditions to match against the {users} table. These
* should be supplied in the form array('field_name' => 'field_value').
* @param $reset
* A boolean indicating that the internal cache should be reset. Use this if
* loading a user object which has been altered during the page request.
* @return
Angie Byron
committed
* An array of user objects, indexed by uid.
*
Dries Buytaert
committed
* @see entity_load()
Angie Byron
committed
* @see user_load()
* @see user_load_by_mail()
* @see user_load_by_name()
Angie Byron
committed
function user_load_multiple($uids = array(), $conditions = array(), $reset = FALSE) {
Dries Buytaert
committed
return entity_load('user', $uids, $conditions, $reset);
}
Angie Byron
committed
Dries Buytaert
committed
/**
* Controller class for users.
*
* This extends the DrupalDefaultEntityController class, adding required
* special handling for user objects.
*/
class UserController extends DrupalDefaultEntityController {
function attachLoad(&$queried_users, $revision_id = FALSE) {
Angie Byron
committed
// Build an array of user picture IDs so that these can be fetched later.
$picture_fids = array();
Dries Buytaert
committed
foreach ($queried_users as $key => $record) {
Angie Byron
committed
$picture_fids[] = $record->picture;
Dries Buytaert
committed
$queried_users[$key] = drupal_unpack($record);
// As well as unpacking $user->data, also convert the property to an
// unserialized array. This ensures we can always safely reserialize it
// in user_save().
$queried_users[$key]->data = unserialize($record->data);
Dries Buytaert
committed
$queried_users[$key]->roles = array();
Angie Byron
committed
if ($record->uid) {
$queried_users[$record->uid]->roles[DRUPAL_AUTHENTICATED_RID] = 'authenticated user';
}
else {
$queried_users[$record->uid]->roles[DRUPAL_ANONYMOUS_RID] = 'anonymous user';
}
Steven Wittens
committed
}
Dries Buytaert
committed
// Add any additional roles from the database.
$result = db_query('SELECT r.rid, r.name, ur.uid FROM {role} r INNER JOIN {users_roles} ur ON ur.rid = r.rid WHERE ur.uid IN (:uids)', array(':uids' => array_keys($queried_users)));
foreach ($result as $record) {
$queried_users[$record->uid]->roles[$record->rid] = $record->name;
}
Dries Buytaert
committed
// Add the full file objects for user pictures if enabled.
if (!empty($picture_fids) && variable_get('user_pictures', 1) == 1) {
$pictures = file_load_multiple($picture_fids);
foreach ($queried_users as $account) {
if (!empty($account->picture) && isset($pictures[$account->picture])) {
$account->picture = $pictures[$account->picture];
}
else {
$account->picture = NULL;
Angie Byron
committed
}
}
}
Dries Buytaert
committed
// Call the default attachLoad() method. This will add fields and call
// hook_user_load().
parent::attachLoad($queried_users, $revision_id);
Angie Byron
committed
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
}
/**
* Fetch a user object.
*
* @param $uid
* Integer specifying the user id.
* @param $reset
* A boolean indicating that the internal cache should be reset.
* @return
* A fully-loaded $user object upon successful user load or FALSE if user
* cannot be loaded.
*
* @see user_load_multiple()
*/
function user_load($uid, $reset = FALSE) {
$users = user_load_multiple(array($uid), array(), $reset);
return reset($users);
}
/**
* Fetch a user object by email address.
*
* @param $mail
* String with the account's e-mail address.
* @return
* A fully-loaded $user object upon successful user load or FALSE if user
* cannot be loaded.
*
* @see user_load_multiple()
*/
function user_load_by_mail($mail) {
$users = user_load_multiple(array(), array('mail' => $mail));
return reset($users);
}
/**
* Fetch a user object by account name.
*
* @param $name
* String with the account's user name.
* @return
* A fully-loaded $user object upon successful user load or FALSE if user
* cannot be loaded.
*
* @see user_load_multiple()
*/
function user_load_by_name($name) {
$users = user_load_multiple(array(), array('name' => $name));
return reset($users);
* Save changes to a user account or add a new user.
*
* @param $account
* (optional) The user object 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. If you
* want to create a new user account, you can set $account->is_new to
* TRUE or omit the $account->uid field.
Dries Buytaert
committed
* @param $edit
Dries Buytaert
committed
* An array of fields and values to save. For example array('name'
* => 'My name'). Key / value pairs added to the $edit['data'] will be
* serialized and saved in the {users.data} column.
* @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.
Dries Buytaert
committed
function user_save($account, $edit = array(), $category = 'account') {
Angie Byron
committed
$transaction = db_transaction();
try {
$table = drupal_get_schema('users');
if (!empty($edit['pass'])) {
// Allow alternate password hashing schemes.
require_once DRUPAL_ROOT . '/' . variable_get('password_inc', 'includes/password.inc');
$edit['pass'] = user_hash_password(trim($edit['pass']));
// Abort if the hashing failed and returned FALSE.
if (!$edit['pass']) {
return FALSE;
}
}
else {
// Avoid overwriting an existing password with a blank password.
unset($edit['pass']);
}
Dries Buytaert
committed
Dries Buytaert
committed
// Presave field allowing changing of $edit.
Angie Byron
committed
$edit = (object) $edit;
field_attach_presave('user', $edit);
$edit = (array) $edit;
Angie Byron
committed
if (!isset($account->is_new)) {
$account->is_new = empty($account->uid);
}
Dries Buytaert
committed
// Prepopulate $edit['data'] with the current value of $account->data.
// Modules can add to or remove from this array in hook_user_presave().
if (!empty($account->data)) {
$edit['data'] = !empty($edit['data']) ? array_merge($account->data, $edit['data']) : $account->data;
Dries Buytaert
committed
}
Angie Byron
committed
user_module_invoke('presave', $edit, $account, $category);
Angie Byron
committed
if (is_object($account) && !$account->is_new) {
// 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($edit['access']) && empty($account->access) && user_access('administer users')) {
$edit['access'] = REQUEST_TIME;
}
Angie Byron
committed
// Process picture uploads.
if (!empty($edit['picture']->fid)) {
$picture = $edit['picture'];
// If the picture is a temporary file move it to its final location and
// make it permanent.
if (($picture->status & FILE_STATUS_PERMANENT) == 0) {
$info = image_get_info($picture->uri);
$picture_directory = variable_get('file_default_scheme', 'public') . '://' . variable_get('user_picture_path', 'pictures');
// Prepare the pictures directory.
file_prepare_directory($picture_directory, FILE_CREATE_DIRECTORY);
$destination = file_stream_wrapper_uri_normalize($picture_directory . '/picture-' . $account->uid . '.' . $info['extension']);
if ($picture = file_move($picture, $destination, FILE_EXISTS_REPLACE)) {
$picture->status |= FILE_STATUS_PERMANENT;
$edit['picture'] = file_save($picture);
}
Angie Byron
committed
$edit['picture'] = empty($edit['picture']->fid) ? 0 : $edit['picture']->fid;
// Do not allow 'uid' to be changed.
$edit['uid'] = $account->uid;
// Save changes to the user table.
$success = drupal_write_record('users', $edit, 'uid');
if ($success === FALSE) {
// The query failed - better to abort the save than risk further
// data loss.
return FALSE;
}
Angie Byron
committed
// If the picture changed or was unset, remove the old one. This step needs
// to occur after updating the {users} record so that user_file_references()
// doesn't report it in use and block the deletion.
if (!empty($account->picture->fid) && ($edit['picture'] != $account->picture->fid)) {
file_delete($account->picture);
}
Angie Byron
committed
// Reload user roles if provided.
if (isset($edit['roles']) && is_array($edit['roles'])) {
db_delete('users_roles')
->condition('uid', $account->uid)
->execute();
$query = db_insert('users_roles')->fields(array('uid', 'rid'));
foreach (array_keys($edit['roles']) as $rid) {
if (!in_array($rid, array(DRUPAL_ANONYMOUS_RID, DRUPAL_AUTHENTICATED_RID))) {
$query->values(array(
'uid' => $account->uid,
'rid' => $rid,
));
}
Dries Buytaert
committed
}
Angie Byron
committed
$query->execute();
Angie Byron
committed
// Delete a blocked user's sessions to kick them if they are online.
if (isset($edit['status']) && $edit['status'] == 0) {
drupal_session_destroy_uid($account->uid);
}
Angie Byron
committed
// If the password changed, delete all open sessions and recreate
// the current one.
if (!empty($edit['pass'])) {
drupal_session_destroy_uid($account->uid);
if ($account->uid == $GLOBALS['user']->uid) {
drupal_session_regenerate();
}
Dries Buytaert
committed
}
Dries Buytaert
committed
Angie Byron
committed
// Save Field data.
$entity = (object) $edit;
field_attach_update('user', $entity);
Angie Byron
committed
// Refresh user object.
$user = user_load($account->uid, TRUE);
Gábor Hojtsy
committed
Angie Byron
committed
// Send emails after we have the new user object.
if (isset($edit['status']) && $edit['status'] != $account->status) {
// The user's status is changing; conditionally send notification email.
$op = $edit['status'] == 1 ? 'status_activated' : 'status_blocked';
_user_mail_notify($op, $user);
}
Gábor Hojtsy
committed
Angie Byron
committed
user_module_invoke('update', $edit, $user, $category);
Angie Byron
committed
entity_invoke('update', 'user', $user);
Gábor Hojtsy
committed
}
Angie Byron
committed
else {
// Allow 'uid' to be set by the caller. There is no danger of writing an
// existing user as drupal_write_record will do an INSERT.
if (empty($edit['uid'])) {
$edit['uid'] = db_next_id(db_query('SELECT MAX(uid) FROM {users}')->fetchField());
}
// Allow 'created' to be set by the caller.
if (!isset($edit['created'])) {
$edit['created'] = REQUEST_TIME;
}
// Consider users created by an administrator as already logged in, so
// anonymous users can view the profile (if allowed).
if (empty($edit['access']) && user_access('administer users')) {
$edit['access'] = REQUEST_TIME;
}
Angie Byron
committed
$edit['mail'] = trim($edit['mail']);
$success = drupal_write_record('users', $edit);
if ($success === FALSE) {
// On a failed INSERT some other existing user's uid may be returned.
// We must abort to avoid overwriting their account.
return FALSE;
}
Gábor Hojtsy
committed
// Build a stub user object.
$user = (object) $edit;
$user->roles[DRUPAL_AUTHENTICATED_RID] = 'authenticated user';
field_attach_insert('user', $user);
Angie Byron
committed
user_module_invoke('insert', $edit, $user, $category);
Angie Byron
committed
entity_invoke('insert', 'user', $user);
Dries Buytaert
committed
// Save user roles.
Angie Byron
committed
if (isset($edit['roles']) && is_array($edit['roles'])) {
$query = db_insert('users_roles')->fields(array('uid', 'rid'));
foreach (array_keys($edit['roles']) as $rid) {
if (!in_array($rid, array(DRUPAL_ANONYMOUS_RID, DRUPAL_AUTHENTICATED_RID))) {
$query->values(array(
'uid' => $edit['uid'],
'rid' => $rid,
));
}
Angie Byron
committed
$query->execute();
Dries Buytaert
committed
}
}
Angie Byron
committed
return $user;
}
catch (Exception $e) {
$transaction->rollback('user', $e->getMessage(), array(), WATCHDOG_ERROR);
/**
* Verify the syntax of the given name.
*/
if (!$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));
}
Angie Byron
committed
$mail = trim($mail);
if (!$mail) {
return t('You must enter an e-mail address.');
}
return t('The e-mail address %mail is not valid.', array('%mail' => $mail));
Dries Buytaert
committed
function user_validate_picture(&$form, &$form_state) {
Dries Buytaert
committed
// 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),
);
Gábor Hojtsy
committed
// Save the file as a temporary file.
$file = file_save_upload('picture_upload', $validators);
if ($file === FALSE) {
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'))));
}
elseif ($file !== NULL) {
$form_state['values']['picture_upload'] = $file;
/**
* Generate a random alphanumeric password.
*/
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
Gábor Hojtsy
committed
// of 'I', 1, and 'l'.
$allowable_characters = 'abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789';
// Zero-based count of characters in the allowable list:
$len = strlen($allowable_characters) - 1;
// Declare the password as a blank string.
$pass = '';
// Loop the number of times specified by $length.
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)];
/**
* Determine the permissions for one or more roles.
*
* @param $roles
* An array whose keys are the role IDs of interest, such as $user->roles.
*
* @return
* An array indexed by role ID. Each value is an array whose keys are the
* permission strings for the given role ID.
*/
function user_role_permissions($roles = array()) {
$cache = &drupal_static(__FUNCTION__, array());
$role_permissions = $fetch = array();
if ($roles) {
foreach ($roles as $rid => $name) {
if (isset($cache[$rid])) {
$role_permissions[$rid] = $cache[$rid];
}
else {
// Add this rid to the list of those needing to be fetched.
$fetch[] = $rid;
// Prepare in case no permissions are returned.
$cache[$rid] = array();
}
}
if ($fetch) {
// Get from the database permissions that were not in the static variable.
// Only role IDs with at least one permission assigned will return rows.
$result = db_query("SELECT rid, permission FROM {role_permission} WHERE rid IN (:fetch)", array(':fetch' => $fetch));
foreach ($result as $row) {
$cache[$row->rid][$row->permission] = TRUE;
}
foreach ($fetch as $rid) {
// For every rid, we know we at least assigned an empty array.
$role_permissions[$rid] = $cache[$rid];
}
}
}
return $role_permissions;
}
/**
* Determine whether the user has a given privilege.
*
* @param $string
* The permission, such as "administer nodes", being checked for.
* @param $account
* (optional) The account to check, if not given use currently logged in user.
Gábor Hojtsy
committed
* 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) {
Gábor Hojtsy
committed
if (!isset($account)) {
$account = $user;
}
Dries Buytaert
committed
// User #1 has all privileges:
Dries Buytaert
committed
if ($account->uid == 1) {
Dries Buytaert
committed
return TRUE;
// To reduce the number of SQL queries, we cache the user's permissions
// in a static variable.
// Use the advanced drupal_static() pattern, since this is called very often.
Angie Byron
committed
static $drupal_static_fast;
if (!isset($drupal_static_fast)) {
$drupal_static_fast['perm'] = &drupal_static(__FUNCTION__);
}
$perm = &$drupal_static_fast['perm'];
Dries Buytaert
committed
if (!isset($perm[$account->uid])) {
$role_permissions = user_role_permissions($account->roles);
Dries Buytaert
committed
$perms = array();
foreach ($role_permissions as $one_role) {
$perms += $one_role;
Dries Buytaert
committed
$perm[$account->uid] = $perms;
Dries Buytaert
committed
Dries Buytaert
committed
return isset($perm[$account->uid][$string]);
Dries Buytaert
committed
/**
Gábor Hojtsy
committed
* Checks for usernames blocked by user administration.
Dries Buytaert
committed
*
Gábor Hojtsy
committed
* @return boolean TRUE for blocked users, FALSE for active.
Dries Buytaert
committed
*/
function user_is_blocked($name) {
Angie Byron
committed
return db_select('users')
->fields('users', array('name'))
->condition('name', db_like($name), 'LIKE')
->condition('status', 0)
->execute()->fetchObject();
Dries Buytaert
committed
}
Dries Buytaert
committed
* Implements hook_permission().
function user_permission() {
return array(
'administer permissions' => array(
'title' => t('Administer permissions'),
Dries Buytaert
committed
'restrict access' => TRUE,
),
'administer users' => array(
'title' => t('Administer users'),
Dries Buytaert
committed
'restrict access' => TRUE,
),
'access user profiles' => array(
'title' => t('View user profiles'),
),
'change own username' => array(
'title' => t('Change own username'),
),
'cancel account' => array(
'title' => t('Cancel own user account'),
'description' => t('Note: content may be kept, unpublished, deleted or transferred to the %anonymous-name user depending on the configured <a href="@user-settings-url">user settings</a>.', array('%anonymous-name' => variable_get('anonymous', t('Anonymous')), '@user-settings-url' => url('admin/config/people/accounts'))),
),
'select account cancellation method' => array(
'title' => t('Select method for cancelling own account'),
Dries Buytaert
committed
'restrict access' => TRUE,
Dries Buytaert
committed
* Implements hook_file_download().
*
* Ensure that user pictures (avatars) are always downloadable.
*/
Dries Buytaert
committed
function user_file_download($uri) {
if (strpos(file_uri_target($uri), variable_get('user_picture_path', 'pictures') . '/picture-') === 0) {
$info = image_get_info($uri);
Dries Buytaert
committed
return array('Content-Type' => $info['mime_type']);
Dries Buytaert
committed
* Implements hook_file_references().
*/
function user_file_references($file) {
// Determine if the file is used by this module.
$file_used = (bool) db_query_range('SELECT 1 FROM {users} WHERE picture = :fid', 0, 1, array(':fid' => $file->fid))->fetchField();
if ($file_used) {
// Return the name of the module and how many references it has to the file.
// If file is still used then 1 is enough to indicate this.
return array('user' => 1);
Dries Buytaert
committed
* Implements hook_file_delete().
*/
function user_file_delete($file) {
// Remove any references to the file.
Angie Byron
committed
db_update('users')
->fields(array('picture' => 0))
->condition('picture', $file->fid)
->execute();
}
Dries Buytaert
committed
* Implements hook_search_info().
Dries Buytaert
committed
function user_search_info() {
return array(
'title' => 'Users',
);
}
/**
Dries Buytaert
committed
* Implements hook_search_access().
Dries Buytaert
committed
*/
function user_search_access() {
return user_access('access user profiles');
}
/**
Dries Buytaert
committed
* Implements hook_search_execute().
Dries Buytaert
committed
*/
function user_search_execute($keys = NULL) {
$find = array();
// Replace wildcards with MySQL/PostgreSQL wildcards.
$keys = preg_replace('!\*+!', '%', $keys);
$query = db_select('users')->extend('PagerDefault');
$query->fields('users', array('name', 'uid', 'mail'));
if (user_access('administer users')) {
// Administrators can also search in the otherwise private email field.
$query->condition(db_or()->
Dries Buytaert
committed
condition('name', '%' . db_like($keys) . '%', 'LIKE')->
condition('mail', '%' . db_like($keys) . '%', 'LIKE'));
Dries Buytaert
committed
}
else {
Dries Buytaert
committed
$query->condition('name', '%' . db_like($keys) . '%', 'LIKE');
Dries Buytaert
committed
}
$result = $query
->limit(15)
->execute();
foreach ($result as $account) {
$find[] = array('title' => $account->name . ' (' . $account->mail . ')', 'link' => url('user/' . $account->uid, array('absolute' => TRUE)));
Dries Buytaert
committed
return $find;
Dries Buytaert
committed
* Implements hook_element_info().
Dries Buytaert
committed
function user_element_info() {
$types['user_profile_category'] = array(
'#theme_wrappers' => array('user_profile_category'),
);
$types['user_profile_item'] = array(
'#theme' => 'user_profile_item',
Dries Buytaert
committed
return $types;
Dries Buytaert
committed
* Implements hook_user_view().
Dries Buytaert
committed
function user_user_view($account) {
Dries Buytaert
committed
$account->content['user_picture'] = array(
Dries Buytaert
committed
'#markup' => theme('user_picture', array('account' => $account)),
Dries Buytaert
committed
'#weight' => -10,
);
if (!isset($account->content['summary'])) {
$account->content['summary'] = array();
}
$account->content['summary'] += array(
'#type' => 'user_profile_category',
'#attributes' => array('class' => array('user-member')),
Dries Buytaert
committed
'#weight' => 5,
'#title' => t('History'),
);
$account->content['summary']['member_for'] = array(
Dries Buytaert
committed
'#type' => 'user_profile_item',
'#title' => t('Member for'),
'#markup' => format_interval(REQUEST_TIME - $account->created),
);
}
/**
* Helper function to add default user account fields to user registration and edit form.
Dries Buytaert
committed
*/
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
function user_account_form(&$form, &$form_state) {
global $user;
$account = $form['#user'];
$register = ($form['#user']->uid > 0 ? FALSE : TRUE);
$admin = user_access('administer users');
$form['#validate'][] = 'user_account_form_validate';
// Account information.
$form['account'] = array(
'#type' => 'fieldset',
'#title' => t('Account information'),
'#weight' => -10,
);
// Only show name field on registration form or user can change own username.
$form['account']['name'] = array(
'#type' => 'textfield',
'#title' => t('Username'),
'#maxlength' => USERNAME_MAX_LENGTH,
'#description' => t('Spaces are allowed; punctuation is not allowed except for periods, hyphens, apostrophes, and underscores.'),
'#required' => TRUE,
'#attributes' => array('class' => array('username')),
'#default_value' => (!$register ? $account->name : ''),
'#access' => ($register || ($user->uid == $account->uid && user_access('change own username')) || $admin),
Angie Byron
committed
'#weight' => -10,
);
$form['account']['mail'] = array(
'#type' => 'textfield',
'#title' => t('E-mail address'),
'#maxlength' => EMAIL_MAX_LENGTH,
'#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.'),
'#required' => TRUE,
'#default_value' => (!$register ? $account->mail : ''),
);
// Display password field only for existing users or when user is allowed to
// assign a password during registration.
if (!$register) {
$form['account']['pass'] = array(
'#type' => 'password_confirm',
'#size' => 25,
'#description' => t('To change the current user password, enter the new password in both fields.'),
);
Angie Byron
committed
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
// To skip the current password field, the user must have logged in via a
// one-time link and have the token in the URL.
$pass_reset = isset($_SESSION['pass_reset_' . $account->uid]) && isset($_GET['pass-reset-token']) && ($_GET['pass-reset-token'] == $_SESSION['pass_reset_' . $account->uid]);
$protected_values = array();
$current_pass_description = '';
// The user may only change their own password without their current
// password if they logged in via a one-time login link.
if (!$pass_reset) {
$protected_values['mail'] = $form['account']['mail']['#title'];
$protected_values['pass'] = t('Password');
$request_new = l(t('Request new password'), 'user/password', array('attributes' => array('title' => t('Request new password via e-mail.'))));
$current_pass_description = t('Enter your current password to change the %mail or %pass. !request_new.', array('%mail' => $protected_values['mail'], '%pass' => $protected_values['pass'], '!request_new' => $request_new));
}
// The user must enter their current password to change to a new one.
if ($user->uid == $account->uid) {
$form['account']['current_pass_required_values'] = array(
'#type' => 'value',
'#value' => $protected_values,
);
$form['account']['current_pass'] = array(
'#type' => 'password',
'#title' => t('Current password'),
'#size' => 25,
'#access' => !empty($protected_values),
'#description' => $current_pass_description,
'#weight' => -5,
);
$form['#validate'][] = 'user_validate_current_pass';
}
}
elseif (!variable_get('user_email_verification', TRUE) || $admin) {
$form['account']['pass'] = array(
'#type' => 'password_confirm',
'#size' => 25,
'#description' => t('Provide a password for the new account in both fields.'),
'#required' => TRUE,
);
}
if ($admin) {
Angie Byron
committed
$status = isset($account->status) ? $account->status : 1;
Angie Byron
committed
$status = $register ? variable_get('user_register', 1) == 1 : $account->status;
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
}
$form['account']['status'] = array(
'#type' => 'radios',
'#title' => t('Status'),
'#default_value' => $status,
'#options' => array(t('Blocked'), t('Active')),
'#access' => $admin,
);
$roles = user_roles(TRUE);
// The disabled checkbox subelement for the 'authenticated user' role
// must be generated separately and added to the checkboxes element,
// because of a limitation in Form API not supporting a single disabled
// checkbox within a set of checkboxes.
// @todo This should be solved more elegantly. See issue #119038.
$checkbox_authenticated = array(
'#type' => 'checkbox',
'#title' => $roles[DRUPAL_AUTHENTICATED_RID],
'#default_value' => TRUE,
'#disabled' => TRUE,
);
unset($roles[DRUPAL_AUTHENTICATED_RID]);
$form['account']['roles'] = array(
'#type' => 'checkboxes',
'#title' => t('Roles'),
'#default_value' => (!$register && isset($account->roles) ? array_keys($account->roles) : array()),
'#options' => $roles,
'#access' => $roles && user_access('administer permissions'),
DRUPAL_AUTHENTICATED_RID => $checkbox_authenticated,
);
$form['account']['notify'] = array(