Newer
Older
/**
* Maximum length of username text field.
*/
define('USERNAME_MAX_LENGTH', 60);
/**
* Maximum length of user e-mail text field.
*/
define('EMAIL_MAX_LENGTH', 64);
Angie Byron
committed
/**
* Invokes hook_user() in every module.
*
* We cannot use module_invoke() for this, because the arguments need to
function user_module_invoke($type, &$array, &$user, $category = NULL) {
Dries Buytaert
committed
foreach (module_implements('user_' . $type) as $module) {
Dries Buytaert
committed
$function = $module . '_user_' . $type;
Dries Buytaert
committed
$function($array, $user, $category);
Dries Buytaert
committed
/**
Gábor Hojtsy
committed
* Implementation of hook_theme().
Dries Buytaert
committed
*/
function user_theme() {
return array(
'user_picture' => array(
'arguments' => array('account' => NULL),
'template' => 'user-picture',
Dries Buytaert
committed
),
'user_profile' => array(
'arguments' => array('elements' => NULL),
'template' => 'user-profile',
'file' => 'user.pages.inc',
Steven Wittens
committed
),
'user_profile_category' => array(
'arguments' => array('element' => NULL),
'template' => 'user-profile-category',
'file' => 'user.pages.inc',
Steven Wittens
committed
),
'user_profile_item' => array(
'arguments' => array('element' => NULL),
'template' => 'user-profile-item',
'file' => 'user.pages.inc',
Dries Buytaert
committed
),
'user_list' => array(
'arguments' => array('users' => NULL, 'title' => NULL),
),
'user_admin_perm' => array(
'arguments' => array('form' => NULL),
'file' => 'user.admin.inc',
Dries Buytaert
committed
),
'user_admin_new_role' => array(
'arguments' => array('form' => NULL),
'file' => 'user.admin.inc',
Dries Buytaert
committed
),
'user_admin_account' => array(
'arguments' => array('form' => NULL),
'file' => 'user.admin.inc',
Dries Buytaert
committed
),
'user_filter_form' => array(
'arguments' => array('form' => NULL),
'file' => 'user.admin.inc',
Dries Buytaert
committed
),
'user_filters' => array(
'arguments' => array('form' => NULL),
'file' => 'user.admin.inc',
Dries Buytaert
committed
),
Dries Buytaert
committed
'user_signature' => array(
'arguments' => array('signature' => NULL),
),
Dries Buytaert
committed
);
}
/**
* Implementation of hook_fieldable_info().
*/
function user_fieldable_info() {
$return = array(
'user' => array(
'name' => t('User'),
'id key' => 'uid',
),
);
return $return;
}
/**
* Implementation of hook_field_build_modes().
*/
function user_field_build_modes($obj_type) {
$modes = array();
if ($obj_type == 'user') {
$modes = array(
'full' => t('User account'),
);
}
return $modes;
}
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;
Dries Buytaert
committed
/**
Gábor Hojtsy
committed
* Perform standard Drupal login operations for a user object.
*
* The user object must already be authenticated. This function verifies
Dries Buytaert
committed
* that the user account is not blocked and then performs the login,
* updates the login timestamp in the database, invokes hook_user('login'),
Gábor Hojtsy
committed
* and regenerates the session.
*
* @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.
Gábor Hojtsy
committed
* 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()) {
Dries Buytaert
committed
$form = drupal_render(drupal_get_form('user_login'));
Dries Buytaert
committed
$state['values'] = $edit;
if (empty($state['values']['name'])) {
$state['values']['name'] = $account->name;
}
Dries Buytaert
committed
// Check if user is blocked.
Dries Buytaert
committed
user_login_name_validate($form, $state, (array)$account);
if (form_get_errors()) {
Gábor Hojtsy
committed
// Invalid login.
Dries Buytaert
committed
return FALSE;
}
Gábor Hojtsy
committed
// Valid login.
Dries Buytaert
committed
global $user;
$user = $account;
Gábor Hojtsy
committed
user_authenticate_finalize($state['values']);
Dries Buytaert
committed
return TRUE;
}
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.
*
* @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) {
static $user_cache = array();
if ($reset) {
$user_cache = array();
Steven Wittens
committed
}
Dries Buytaert
committed
Angie Byron
committed
$users = array();
// Create a new variable which is either a prepared version of the $uids
// array for later comparison with the user cache, or FALSE if no $uids were
// passed. The $uids array is reduced as items are loaded from cache, and we
// need to know if it's empty for this reason to avoid querying the database
// when all requested users are loaded from cache.
$passed_uids = !empty($uids) ? array_flip($uids) : FALSE;
// Load any available users from the internal cache.
if ($user_cache) {
if ($uids && !$conditions) {
$users += array_intersect_key($user_cache, $passed_uids);
// If any users were loaded, remove them from the $uids still to load.
$uids = array_keys(array_diff_key($passed_uids, $users));
Angie Byron
committed
// Load any remaining users from the database, this is necessary if we have
// $uids still to load, or if $conditions was passed without $uids.
if ($uids || ($conditions && !$passed_uids)) {
$query = db_select('users', 'u')->fields('u');
Angie Byron
committed
// If the $uids array is populated, add those to the query.
if ($uids) {
$query->condition('u.uid', $uids, 'IN');
Dries Buytaert
committed
}
Angie Byron
committed
// If the conditions array is populated, add those to the query.
if ($conditions) {
// TODO D7: Using LIKE() to get a case insensitive comparison because Crell
// and chx promise that dbtng will map it to ILIKE in postgres.
Angie Byron
committed
if (isset($conditions['name'])) {
$query->condition('u.name', $conditions['name'], 'LIKE');
Angie Byron
committed
unset($conditions['name']);
}
if (isset($conditions['mail'])) {
$query->condition('u.mail', $conditions['mail'], 'LIKE');
Angie Byron
committed
unset($conditions['mail']);
}
foreach ($conditions as $field => $value) {
$query->condition('u.' . $field, $value);
}
Dries Buytaert
committed
}
Angie Byron
committed
$result = $query->execute();
$queried_users = array();
// Build an array of user picture IDs so that these can be fetched later.
$picture_fids = array();
foreach ($result as $record) {
$picture_fids[] = $record->picture;
$queried_users[$record->uid] = drupal_unpack($record);
$queried_users[$record->uid]->roles = array();
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
}
Angie Byron
committed
if (!empty($queried_users)) {
// 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;
}
Angie Byron
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
field_attach_load('user', $queried_users);
Angie Byron
committed
// Invoke hook_user_load() on the users loaded from the database
// and add them to the static cache.
foreach (module_implements('user_load') as $module) {
$function = $module . '_user_load';
$function($queried_users);
}
Angie Byron
committed
Angie Byron
committed
$users = $users + $queried_users;
$user_cache = $user_cache + $queried_users;
}
Steven Wittens
committed
}
Angie Byron
committed
// Ensure that the returned array is ordered the same as the original $uids
// array if this was passed in and remove any invalid uids.
if ($passed_uids) {
// Remove any invalid uids from the array.
$passed_uids = array_intersect_key($passed_uids, $users);
foreach ($users as $user) {
$passed_uids[$user->uid] = $user;
}
$users = $passed_uids;
Angie Byron
committed
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
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
return $users;
}
/**
* 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
* The $user object for the user to modify or add. If $user->uid is
Angie Byron
committed
* omitted (or $user->is_new == TRUE), a new user will be added.
Dries Buytaert
committed
* @param $edit
Dries Buytaert
committed
* An array of fields and values to save. For example array('name'
Dries Buytaert
committed
* => 'My name'). Keys that do not belong to columns in the user-related
Dries Buytaert
committed
* 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.
*
* @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
$table = drupal_get_schema('users');
Dries Buytaert
committed
$user_fields = $table['fields'];
Dries Buytaert
committed
if (!empty($edit['pass'])) {
// Allow alternate password hashing schemes.
Angie Byron
committed
require_once DRUPAL_ROOT . '/' . variable_get('password_inc', 'includes/password.inc');
Dries Buytaert
committed
$edit['pass'] = user_hash_password(trim($edit['pass']));
// Abort if the hashing failed and returned FALSE.
Dries Buytaert
committed
if (!$edit['pass']) {
return FALSE;
}
Dries Buytaert
committed
}
else {
// Avoid overwriting an existing password with a blank password.
Dries Buytaert
committed
unset($edit['pass']);
Dries Buytaert
committed
}
// Get the fields form so we can recognize the fields in the $edit
// form that should not go into the serialized data array.
$field_form = array();
$field_form_state = array();
$edit = (object) $edit;
field_attach_form('user', $edit, $field_form, $field_form_state);
// Presave fields.
field_attach_presave('user', $edit);
$edit = (array) $edit;
Angie Byron
committed
if (!isset($account->is_new)) {
$account->is_new = empty($account->uid);
Angie Byron
committed
}
if (is_object($account) && !$account->is_new) {
Dries Buytaert
committed
user_module_invoke('update', $edit, $account, $category);
Dries Buytaert
committed
$data = unserialize(db_query('SELECT data FROM {users} WHERE uid = :uid', array(':uid' => $account->uid))->fetchField());
Gábor Hojtsy
committed
// Consider users edited by an administrator as logged in, if they haven't
// already, so anonymous users can view the profile (if allowed).
Dries Buytaert
committed
if (empty($edit['access']) && empty($account->access) && user_access('administer users')) {
Dries Buytaert
committed
$edit['access'] = REQUEST_TIME;
Gábor Hojtsy
committed
}
Dries Buytaert
committed
foreach ($edit as $key => $value) {
Angie Byron
committed
// Field API are automatically serialized into the users.data
Angie Byron
committed
if (!in_array($key, array('roles', 'is_new')) && empty($user_fields[$key]) && empty($field_form[$key])) {
Dries Buytaert
committed
if ($value === NULL) {
unset($data[$key]);
Dries Buytaert
committed
else {
$data[$key] = $value;
// 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->filepath);
$destination = file_create_path(variable_get('user_picture_path', 'pictures') . '/picture-' . $account->uid . '.' . $info['extension']);
if ($picture = file_move($picture, $destination, FILE_EXISTS_REPLACE)) {
$picture->status |= FILE_STATUS_PERMANENT;
$edit['picture'] = file_save($picture);
}
}
}
$edit['picture'] = empty($edit['picture']->fid) ? 0 : $edit['picture']->fid;
Dries Buytaert
committed
$edit['data'] = $data;
$edit['uid'] = $account->uid;
// Save changes to the user table.
Angie Byron
committed
$success = drupal_write_record('users', $edit, 'uid');
if (!$success) {
// The query failed - better to abort the save than risk further
// data loss.
// TODO: Fields change: I think this is a bug. If no columns in
// the user table are changed, drupal_write_record returns
Angie Byron
committed
// non-users data may have been changed, e.g. fields.
// If the picture changed or was unset, remove the old one. This step needs
Angie Byron
committed
// 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);
}
Gábor Hojtsy
committed
// Reload user roles if provided.
Dries Buytaert
committed
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'));
Dries Buytaert
committed
foreach (array_keys($edit['roles']) as $rid) {
Dries Buytaert
committed
if (!in_array($rid, array(DRUPAL_ANONYMOUS_RID, DRUPAL_AUTHENTICATED_RID))) {
$query->values(array(
'uid' => $account->uid,
'rid' => $rid,
));
Dries Buytaert
committed
}
$query->execute();
// Delete a blocked user's sessions to kick them if they are online.
Dries Buytaert
committed
if (isset($edit['status']) && $edit['status'] == 0) {
Dries Buytaert
committed
drupal_session_destroy_uid($account->uid);
Dries Buytaert
committed
// If the password changed, delete all open sessions and recreate
// the current one.
Dries Buytaert
committed
if (!empty($edit['pass'])) {
Dries Buytaert
committed
drupal_session_destroy_uid($account->uid);
Dries Buytaert
committed
if ($account->uid == $GLOBALS['user']->uid) {
drupal_session_regenerate();
}
Dries Buytaert
committed
}
Angie Byron
committed
$object = (object) $edit;
field_attach_update('user', $object);
Gábor Hojtsy
committed
// Refresh user object.
Angie Byron
committed
$user = user_load($account->uid, TRUE);
Gábor Hojtsy
committed
// Send emails after we have the new user object.
Dries Buytaert
committed
if (isset($edit['status']) && $edit['status'] != $account->status) {
Gábor Hojtsy
committed
// The user's status is changing; conditionally send notification email.
Dries Buytaert
committed
$op = $edit['status'] == 1 ? 'status_activated' : 'status_blocked';
Gábor Hojtsy
committed
_user_mail_notify($op, $user);
}
Dries Buytaert
committed
user_module_invoke('after_update', $edit, $user, $category);
Gábor Hojtsy
committed
// Allow 'created' to be set by the caller.
Dries Buytaert
committed
if (!isset($edit['created'])) {
Dries Buytaert
committed
$edit['created'] = REQUEST_TIME;
Gábor Hojtsy
committed
// Consider users created by an administrator as already logged in, so
// anonymous users can view the profile (if allowed).
Dries Buytaert
committed
if (empty($edit['access']) && user_access('administer users')) {
Dries Buytaert
committed
$edit['access'] = REQUEST_TIME;
Gábor Hojtsy
committed
}
Angie Byron
committed
$edit['mail'] = trim($edit['mail']);
Angie Byron
committed
$success = drupal_write_record('users', $edit);
if (!$success) {
// 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 the initial user object.
Angie Byron
committed
$user = user_load($edit['uid'], TRUE);
Angie Byron
committed
$object = (object) $edit;
field_attach_insert('user', $object);
Dries Buytaert
committed
user_module_invoke('insert', $edit, $user, $category);
Dries Buytaert
committed
// Note, we wait with saving the data column to prevent module-handled
// fields from being saved there.
$data = array();
Dries Buytaert
committed
foreach ($edit as $key => $value) {
Angie Byron
committed
// Form fields that don't pertain to the users, user_roles, or
// Field API are automatically serialized into the user.data
Angie Byron
committed
if ((!in_array($key, array('roles', 'is_new'))) && (empty($user_fields[$key]) && empty($field_form[$key])) && ($value !== NULL)) {
$data[$key] = $value;
}
}
Dries Buytaert
committed
if (!empty($data)) {
$data_array = array('uid' => $user->uid, 'data' => $data);
Angie Byron
committed
drupal_write_record('users', $data_array, 'uid');
Dries Buytaert
committed
}
Dries Buytaert
committed
// Save user roles (delete just to be safe).
Dries Buytaert
committed
if (isset($edit['roles']) && is_array($edit['roles'])) {
db_delete('users_roles')
->condition('uid', $edit['uid'])
->execute();
$query = db_insert('users_roles')->fields(array('uid', 'rid'));
Dries Buytaert
committed
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,
));
Dries Buytaert
committed
}
$query->execute();
Dries Buytaert
committed
}
// Build the finished user object.
Angie Byron
committed
$user = user_load($edit['uid'], TRUE);
/**
* 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)];
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
/**
* Determine the permissions for one or more roles.
*
* @param $roles
* An array whose keys are the role IDs of interest, such as $user->roles.
* @param $reset
* Optional parameter - if TRUE data in the static variable is rebuilt.
*
* @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(), $reset = FALSE) {
static $stored_permissions = array();
if ($reset) {
// Clear the data cached in the static variable.
$stored_permissions = array();
}
$role_permissions = $fetch = array();
if ($roles) {
foreach ($roles as $rid => $name) {
if (isset($stored_permissions[$rid])) {
$role_permissions[$rid] = $stored_permissions[$rid];
}
else {
// Add this rid to the list of those needing to be fetched.
$fetch[] = $rid;
// Prepare in case no permissions are returned.
$stored_permissions[$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) {
$stored_permissions[$row->rid][$row->permission] = TRUE;
}
foreach ($fetch as $rid) {
// For every rid, we know we at least assigned an empty array.
$role_permissions[$rid] = $stored_permissions[$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
* @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.
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.
*/
Gábor Hojtsy
committed
function user_access($string, $account = NULL, $reset = FALSE) {
Gábor Hojtsy
committed
if ($reset) {
$perm = array();
Gábor Hojtsy
committed
}
if (is_null($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.
Dries Buytaert
committed
if (!isset($perm[$account->uid])) {
$role_permissions = user_role_permissions($account->roles, $reset);
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) {
Dries Buytaert
committed
$deny = db_query("SELECT name FROM {users} WHERE status = 0 AND name = LOWER(:name)", array(':name' => $name))->fetchObject();
Dries Buytaert
committed
Dries Buytaert
committed
return $deny;
Dries Buytaert
committed
}
/**
* Implementation of hook_perm().
*/
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
return array(
'administer permissions' => array(
'title' => t('Administer permissions'),
'description' => t('Manage the permissions assigned to user roles. %warning', array('%warning' => t('Warning: Give to trusted roles only; this permission has security implications.'))),
),
'administer users' => array(
'title' => t('Administer users'),
'description' => t('Manage or block users, and manage their role assignments.'),
),
'access user profiles' => array(
'title' => t('Access user profiles'),
'description' => t('View profiles of users on the site, which may contain personal information.'),
),
'change own username' => array(
'title' => t('Change own username'),
'description' => t('Select a different username.'),
),
'cancel account' => array(
'title' => t('Cancel account'),
'description' => t('Remove or disable own user account and unpublish, anonymize, or remove own submissions depending on the configured <a href="@user-settings-url">user settings</a>.', array('@user-settings-url' => url('admin/user/settings'))),
),
'select account cancellation method' => array(
'title' => t('Select method for cancelling own account'),
'description' => t('Select the method for cancelling own user account. %warning', array('%warning' => t('Warning: Give to trusted roles only; this permission has security implications.'))),
),
);
/**
* Implementation of hook_file_download().
*
* Ensure that user pictures (avatars) are always downloadable.
*/
function user_file_download($filepath) {
if (strpos($filepath, variable_get('user_picture_path', 'pictures') . '/picture-') === 0) {
$info = image_get_info(file_create_path($filepath));
Dries Buytaert
committed
return array('Content-Type' => $info['mime_type']);
/**
* Implementation of hook_file_references().
*/
function user_file_references($file) {
// Determine if the file is used by this module.
Angie Byron
committed
$file_used = (bool) db_query_range('SELECT 1 FROM {users} WHERE picture = :fid', array(':fid' => $file->fid), 0, 1)->fetchField();
if ($file_used) {
// Return the name of the module and how many references it has to the file.
return array('user' => $count);
}
}
/**
* Implementation of 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();
}
/**
* Implementation of hook_search().
*/
function user_search($op = 'search', $keys = NULL, $skip_access_check = FALSE) {
switch ($op) {
case 'name':
if ($skip_access_check || user_access('access user profiles')) {
return t('Users');
case 'search':
if (user_access('access user profiles')) {
$find = array();
// Replace wildcards with MySQL/PostgreSQL wildcards.
$keys = preg_replace('!\*+!', '%', $keys);
$query = db_select('users')->extend('PagerDefault');
Dries Buytaert
committed
$query->fields('users', array('name', 'uid', 'mail'));
Gábor Hojtsy
committed
if (user_access('administer users')) {
// Administrators can also search in the otherwise private email field.
Dries Buytaert
committed
$query->condition(db_or()->
where('LOWER(name) LIKE LOWER(:name)', array(':name' => "%$keys%"))->
where('LOWER(mail) LIKE LOWER(:mail)', array(':mail' => "%$keys%")));
Gábor Hojtsy
committed
}
else {
Dries Buytaert
committed
$query->where('LOWER(name) LIKE LOWER(:name)', array(':name' => "%$keys%"));
}
$result = $query
->limit(15)
->execute();
Dries Buytaert
committed
foreach ($result as $account) {
$find[] = array('title' => $account->name . ' (' . $account->mail . ')', 'link' => url('user/' . $account->uid, array('absolute' => TRUE)));
}
return $find;
/**
* Implementation of hook_elements().
*/
function user_elements() {
return array(
'user_profile_category' => array(
'#theme_wrapper' => 'user_profile_category'
),
'user_profile_item' => array(
'#theme' => 'user_profile_item'
),
Dries Buytaert
committed
* Implementation of hook_user_view().
Dries Buytaert
committed
function user_user_view(&$edit, &$account, $category = NULL) {
$account->content['user_picture'] = array(
'#markup' => theme('user_picture', $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' => 'user-member'),
'#weight' => 5,
'#title' => t('History'),
);
$account->content['summary']['member_for'] = array(
'#type' => 'user_profile_item',
'#title' => t('Member for'),
'#markup' => format_interval(REQUEST_TIME - $account->created),
);
}
/**
* Implementation of hook_user_form.
*/
function user_user_form(&$edit, &$account, $category = NULL) {
if ($category == 'account') {
Dries Buytaert
committed
$form_state = array();
return user_edit_form($form_state, (isset($account->uid) ? $account->uid : FALSE), $edit);
Dries Buytaert
committed
}
Dries Buytaert
committed
/**
* Implementation of hook_user_validate().
Dries Buytaert
committed
*/
function user_user_validate(&$edit, &$account, $category = NULL) {
if ($category == 'account') {
$uid = isset($account->uid) ? $account->uid : FALSE;
// Validate the username when: new user account; or user is editing own account and can change username; or an admin user.
if (!$uid || ($GLOBALS['user']->uid == $uid && user_access('change own username')) || user_access('administer users')) {
if ($error = user_validate_name($edit['name'])) {
form_set_error('name', $error);
}
elseif ((bool) db_query_range("SELECT 1 FROM {users} WHERE uid <> :uid AND LOWER(name) = LOWER(:name)", array(':uid' => $uid, ':name' => $edit['name']), 0, 1)->fetchField()) {
form_set_error('name', t('The name %name is already taken.', array('%name' => $edit['name'])));
}
}
Dries Buytaert
committed
// Validate the e-mail address, and check if it is taken by an existing user.
if ($error = user_validate_mail($edit['mail'])) {
form_set_error('mail', $error);
}
elseif ((bool) db_query_range("SELECT 1 FROM {users} WHERE uid <> :uid AND LOWER(mail) = LOWER(:mail)", array(':uid' => $uid, ':mail' => $edit['mail']), 0, 1)->fetchField()) {
Dries Buytaert
committed
// Format error message dependent on whether the user is logged in or not.
if ($GLOBALS['user']->uid) {
form_set_error('mail', t('The e-mail address %email is already taken.', array('%email' => $edit['mail'])));
}
else {
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'))));
}
Dries Buytaert
committed
// Make sure the signature isn't longer than the size of the database field.
// Signatures are disabled by default, so make sure it exists first.
if (isset($edit['signature'])) {
$user_schema = drupal_get_schema('users');
if (strlen($edit['signature']) > $user_schema['fields']['signature']['length']) {
form_set_error('signature', t('The signature is too long: it must be %max characters or less.', array('%max' => $user_schema['fields']['signature']['length'])));
}
}
Dries Buytaert
committed
}
Dries Buytaert
committed
/**
* Implementation of hook_user_submit().
Dries Buytaert
committed
*/
function user_user_submit(&$edit, &$account, $category = NULL) {
if ($category == 'account') {
if (!empty($edit['picture_upload'])) {
$edit['picture'] = $edit['picture_upload'];
}
// Delete picture if requested, and if no replacement picture was given.
elseif (!empty($edit['picture_delete'])) {
$edit['picture'] = NULL;
// Remove these values so they don't end up serialized in the data field.
$edit['picture_upload'] = NULL;
$edit['picture_delete'] = NULL;
if (isset($edit['roles'])) {
$edit['roles'] = array_filter($edit['roles']);
}
}
Dries Buytaert
committed
}