updated core to 7.73

This commit is contained in:
2020-09-24 17:04:08 +02:00
parent 084d28842a
commit 7d87153100
524 changed files with 25194 additions and 7745 deletions
+3 -4
View File
@@ -5,8 +5,7 @@ version = VERSION
core = 7.x
hidden = TRUE
; Information added by drupal.org packaging script on 2013-04-03
version = "7.22"
; Information added by Drupal.org packaging script on 2020-09-16
version = "7.73"
project = "drupal"
datestamp = "1365027012"
datestamp = "1600272641"
+18
View File
@@ -62,3 +62,21 @@ function user_form_test_current_password($form, &$form_state, $account) {
function user_form_test_current_password_submit($form, &$form_state) {
drupal_set_message(t('The password has been validated and the form submitted successfully.'));
}
/**
* Implements hook_form_FORM_ID_alter().
*/
function user_form_test_form_user_profile_form_alter(&$form, &$form_state) {
if (variable_get('user_form_test_user_profile_form_rebuild', FALSE)) {
$form['#submit'][] = 'user_form_test_user_account_submit';
}
}
/**
* Submit function for user_profile_form().
*/
function user_form_test_user_account_submit($form, &$form_state) {
// Rebuild the form instead of letting the process end. This allows us to
// test for bugs that can be triggered in contributed modules.
$form_state['rebuild'] = TRUE;
}
+11
View File
@@ -0,0 +1,11 @@
name = "User module session tests"
description = "Support module for user session testing."
package = Testing
version = VERSION
core = 7.x
hidden = TRUE
; Information added by Drupal.org packaging script on 2020-09-16
version = "7.73"
project = "drupal"
datestamp = "1600272641"
@@ -0,0 +1,29 @@
<?php
/**
* @file
* Dummy module implementing a page callback to create an anon session.
*/
/**
* Implements hook_menu().
*/
function user_session_test_menu() {
$items = array();
$items['user_session_test_anon_session'] = array(
'page callback' => 'user_session_test_anon_session',
'access callback' => TRUE,
);
return $items;
}
/**
* Page callback.
*
* Creates an anonymous user session.
*/
function user_session_test_anon_session() {
$data = 'This dummy data will be stored in a user session.';
$_SESSION[__FUNCTION__] = $data;
return $data;
}
+1 -1
View File
@@ -17,7 +17,7 @@
*/
?>
<?php if ($user_picture): ?>
<div class="user-picture">
<div class="<?php print $classes; ?>">
<?php print $user_picture; ?>
</div>
<?php endif; ?>
+1 -1
View File
@@ -406,7 +406,7 @@ function user_admin_settings() {
$form['personalization']['pictures']['settings']['user_picture_style'] = array(
'#type' => 'select',
'#title' => t('Picture display style'),
'#options' => image_style_options(TRUE),
'#options' => image_style_options(TRUE, PASS_THROUGH),
'#default_value' => variable_get('user_picture_style', ''),
'#description' => t('The style selected will be used on display, while the original image is retained. Styles may be configured in the <a href="!url">Image styles</a> administration area.', array('!url' => url('admin/config/media/image-styles'))),
);
+23 -15
View File
@@ -123,8 +123,8 @@ function hook_user_cancel($edit, $account, $method) {
* description is NOT used for the radio button, but instead should provide
* additional explanation to the user seeking to cancel their account.
* - access: (optional) A boolean value indicating whether the user can access
* a method. If #access is defined, the method cannot be configured as default
* method.
* a method. If access is defined, the method cannot be configured as the
* default method.
*
* @param $methods
* An array containing user account cancellation methods, keyed by method id.
@@ -183,7 +183,23 @@ function hook_user_operations() {
}
/**
* Retrieve a list of user setting or profile information categories.
* Define a list of user settings or profile information categories.
*
* There are two steps to using hook_user_categories():
* - Create the category with hook_user_categories().
* - Display that category on the form ID of "user_profile_form" with
* hook_form_FORM_ID_alter().
*
* Step one builds out the category but it won't be visible on your form until
* you explicitly tell it to do so.
*
* The function in step two should contain the following code in order to
* display your new category:
* @code
* if ($form['#user_category'] == 'mycategory') {
* // Return your form here.
* }
* @endcode
*
* @return
* An array of associative arrays. Each inner array has elements:
@@ -327,14 +343,6 @@ function hook_user_logout($account) {
* The module should format its custom additions for display and add them to the
* $account->content array.
*
* Note that when this hook is invoked, the changes have not yet been written to
* the database, because a database transaction is still in progress. The
* transaction is not finalized until the save operation is entirely completed
* and user_save() goes out of scope. You should not rely on data in the
* database at this time as it is not updated yet. You should also note that any
* write/update database queries executed from this hook are also not committed
* immediately. Check user_save() and db_transaction() for more info.
*
* @param $account
* The user object on which the operation is being performed.
* @param $view_mode
@@ -386,7 +394,7 @@ function hook_user_view_alter(&$build) {
}
/**
* Inform other modules that a user role is about to be saved.
* Act on a user role being inserted or updated.
*
* Modules implementing this hook can act on the user role object before
* it has been saved to the database.
@@ -405,7 +413,7 @@ function hook_user_role_presave($role) {
}
/**
* Inform other modules that a user role has been added.
* Respond to creation of a new user role.
*
* Modules implementing this hook can act on the user role object when saved to
* the database. It's recommended that you implement this hook if your module
@@ -426,7 +434,7 @@ function hook_user_role_insert($role) {
}
/**
* Inform other modules that a user role has been updated.
* Respond to updates to a user role.
*
* Modules implementing this hook can act on the user role object when updated.
* It's recommended that you implement this hook if your module adds additional
@@ -447,7 +455,7 @@ function hook_user_role_update($role) {
}
/**
* Inform other modules that a user role has been deleted.
* Respond to user role deletion.
*
* This hook allows you act when a user role has been deleted.
* If your module stores references to roles, it's recommended that you
+3 -4
View File
@@ -9,8 +9,7 @@ required = TRUE
configure = admin/config/people
stylesheets[all][] = user.css
; Information added by drupal.org packaging script on 2013-04-03
version = "7.22"
; Information added by Drupal.org packaging script on 2020-09-16
version = "7.73"
project = "drupal"
datestamp = "1365027012"
datestamp = "1600272641"
+21 -7
View File
@@ -49,6 +49,9 @@ function user_schema() {
'columns' => array('uid' => 'uid'),
),
),
'indexes' => array(
'uid_module' => array('uid', 'module'),
),
);
$schema['role_permission'] = array(
@@ -81,7 +84,7 @@ function user_schema() {
),
'foreign keys' => array(
'role' => array(
'table' => 'roles',
'table' => 'role',
'columns' => array('rid' => 'rid'),
),
),
@@ -278,7 +281,7 @@ function user_schema() {
'columns' => array('uid' => 'uid'),
),
'role' => array(
'table' => 'roles',
'table' => 'role',
'columns' => array('rid' => 'rid'),
),
),
@@ -356,11 +359,13 @@ function user_update_dependencies() {
'filter' => 7000,
);
// user_update_7012() uses the file API, which relies on the {file_managed}
// table, so it must run after system_update_7034(), which creates that
// table.
// user_update_7012() uses the file API and inserts records into the
// {file_managed} table, so it therefore must run after system_update_7061(),
// which inserts files with specific IDs into the table and therefore relies
// on the table being empty (otherwise it would accidentally overwrite
// existing records).
$dependencies['user'][7012] = array(
'system' => 7034,
'system' => 7061,
);
// user_update_7013() uses the file usage API, which relies on the
@@ -535,7 +540,7 @@ function user_update_7002(&$sandbox) {
if ($sandbox['user_from'] == $sandbox['user_count']) {
if ($sandbox['user_not_migrated'] > 0) {
variable_set('empty_timezone_message', 1);
drupal_set_message('Some user time zones have been emptied and need to be set to the correct values. Use the new ' . l('time zone options', 'admin/config/regional/settings') . ' to choose whether to remind users at login to set the correct time zone.', 'warning');
drupal_set_message(format_string('Some user time zones have been emptied and need to be set to the correct values. Use the new <a href="@config-url">time zone options</a> to choose whether to remind users at login to set the correct time zone.', array('@config-url' => url('admin/config/regional/settings'))), 'warning');
}
return t('Migrated user time zones');
}
@@ -908,6 +913,15 @@ function user_update_7018() {
}
}
/**
* Ensure there is a combined index on {authmap}.uid and {authmap}.module.
*/
function user_update_7019() {
// Check first in case it was already added manually.
if (!db_index_exists('authmap', 'uid_module')) {
db_add_index('authmap', 'uid_module', array('uid', 'module'));
}
}
/**
* @} End of "addtogroup updates-7.x-extra".
*/
+2
View File
@@ -93,6 +93,8 @@ Drupal.behaviors.password = {
* Returns the estimated strength and the relevant output message.
*/
Drupal.evaluatePasswordStrength = function (password, translate) {
password = $.trim(password);
var weaknesses = 0, strength = 100, msg = [];
var hasLowercase = /[a-z]+/.test(password);
+183 -83
View File
@@ -32,7 +32,7 @@ define('USER_REGISTER_VISITORS', 1);
define('USER_REGISTER_VISITORS_ADMINISTRATIVE_APPROVAL', 2);
/**
* Implement hook_help().
* Implements hook_help().
*/
function user_help($path, $arg) {
global $user;
@@ -187,7 +187,7 @@ function user_entity_info() {
}
/**
* Entity URI callback.
* Implements callback_entity_info_uri().
*/
function user_uri($user) {
return array(
@@ -321,7 +321,7 @@ class UserController extends DrupalDefaultEntityController {
}
// Add the full file objects for user pictures if enabled.
if (!empty($picture_fids) && variable_get('user_pictures', 1) == 1) {
if (!empty($picture_fids) && variable_get('user_pictures', 0)) {
$pictures = file_load_multiple($picture_fids);
foreach ($queried_users as $account) {
if (!empty($account->picture) && isset($pictures[$account->picture])) {
@@ -418,13 +418,11 @@ function user_load_by_name($name) {
*
* @return
* A fully-loaded $user object upon successful save or FALSE if the save failed.
*
* @todo D8: Drop $edit and fix user_save() to be consistent with others.
*/
function user_save($account, $edit = array(), $category = 'account') {
$transaction = db_transaction();
try {
if (!empty($edit['pass'])) {
if (isset($edit['pass']) && strlen(trim($edit['pass'])) > 0) {
// Allow alternate password hashing schemes.
require_once DRUPAL_ROOT . '/' . variable_get('password_inc', 'includes/password.inc');
$edit['pass'] = user_hash_password(trim($edit['pass']));
@@ -501,12 +499,17 @@ function user_save($account, $edit = array(), $category = 'account') {
file_usage_delete($account->original->picture, 'user', 'user', $account->uid);
file_delete($account->original->picture);
}
// Save the picture object, if it is set. drupal_write_record() expects
// $account->picture to be a FID.
$picture = empty($account->picture) ? NULL : $account->picture;
$account->picture = empty($account->picture->fid) ? 0 : $account->picture->fid;
// Do not allow 'uid' to be changed.
$account->uid = $account->original->uid;
// Save changes to the user table.
$success = drupal_write_record('users', $account, 'uid');
// Restore the picture object.
$account->picture = $picture;
if ($success === FALSE) {
// The query failed - better to abort the save than risk further
// data loss.
@@ -589,16 +592,16 @@ function user_save($account, $edit = array(), $category = 'account') {
user_module_invoke('insert', $edit, $account, $category);
module_invoke_all('entity_insert', $account, 'user');
// Save user roles.
if (count($account->roles) > 1) {
// Save user roles. Skip built-in roles, and ones that were already saved
// to the database during hook calls.
$rids_to_skip = array_merge(array(DRUPAL_ANONYMOUS_RID, DRUPAL_AUTHENTICATED_RID), db_query('SELECT rid FROM {users_roles} WHERE uid = :uid', array(':uid' => $account->uid))->fetchCol());
if ($rids_to_save = array_diff(array_keys($account->roles), $rids_to_skip)) {
$query = db_insert('users_roles')->fields(array('uid', 'rid'));
foreach (array_keys($account->roles) as $rid) {
if (!in_array($rid, array(DRUPAL_ANONYMOUS_RID, DRUPAL_AUTHENTICATED_RID))) {
$query->values(array(
'uid' => $account->uid,
'rid' => $rid,
));
}
foreach ($rids_to_save as $rid) {
$query->values(array(
'uid' => $account->uid,
'rid' => $rid,
));
}
$query->execute();
}
@@ -634,7 +637,7 @@ function user_validate_name($name) {
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)) {
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
@@ -686,7 +689,7 @@ function user_validate_picture(&$form, &$form_state) {
$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),
'file_validate_size' => array((int) variable_get('user_picture_file_size', '30') * 1024),
);
// Save the file as a temporary file.
@@ -717,10 +720,14 @@ function user_password($length = 10) {
// Loop the number of times specified by $length.
for ($i = 0; $i < $length; $i++) {
do {
// Find a secure random number within the range needed.
$index = ord(drupal_random_bytes(1));
} while ($index > $len);
// Each iteration, pick a random character from the
// allowable string and append it to the password:
$pass .= $allowable_characters[mt_rand(0, $len)];
$pass .= $allowable_characters[$index];
}
return $pass;
@@ -733,8 +740,9 @@ function user_password($length = 10) {
* 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.
* If $roles is a non-empty array, an array indexed by role ID is returned.
* Each value is an array whose keys are the permission strings for the given
* role ID. If $roles is empty nothing is returned.
*/
function user_role_permissions($roles = array()) {
$cache = &drupal_static(__FUNCTION__, array());
@@ -781,7 +789,7 @@ function user_role_permissions($roles = array()) {
* (optional) The account to check, if not given use currently logged in user.
*
* @return
* Boolean TRUE if the current user has the requested permission.
* Boolean TRUE if the 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
@@ -838,6 +846,26 @@ function user_is_blocked($name) {
->execute()->fetchObject();
}
/**
* Checks if a user has a role.
*
* @param int $rid
* A role ID.
*
* @param object|null $account
* (optional) A user account. Defaults to the current user.
*
* @return bool
* TRUE if the user has the role, or FALSE if not.
*/
function user_has_role($rid, $account = NULL) {
if (!$account) {
$account = $GLOBALS['user'];
}
return isset($account->roles[$rid]);
}
/**
* Implements hook_permission().
*/
@@ -928,6 +956,8 @@ function user_search_access() {
*/
function user_search_execute($keys = NULL, $conditions = NULL) {
$find = array();
// Escape for LIKE matching.
$keys = db_like($keys);
// Replace wildcards with MySQL/PostgreSQL wildcards.
$keys = preg_replace('!\*+!', '%', $keys);
$query = db_select('users')->extend('PagerDefault');
@@ -937,13 +967,13 @@ function user_search_execute($keys = NULL, $conditions = NULL) {
// and they don't need to be restricted to only active users.
$query->fields('users', array('mail'));
$query->condition(db_or()->
condition('name', '%' . db_like($keys) . '%', 'LIKE')->
condition('mail', '%' . db_like($keys) . '%', 'LIKE'));
condition('name', '%' . $keys . '%', 'LIKE')->
condition('mail', '%' . $keys . '%', 'LIKE'));
}
else {
// Regular users can only search via usernames, and we do not show them
// blocked accounts.
$query->condition('name', '%' . db_like($keys) . '%', 'LIKE')
$query->condition('name', '%' . $keys . '%', 'LIKE')
->condition('status', 1);
}
$uids = $query
@@ -1058,13 +1088,16 @@ function user_account_form(&$form, &$form_state) {
'#description' => t('To change the current user password, enter the new password in both fields.'),
);
// 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]);
// one-time link and have the token in the URL. Store this in $form_state
// so it persists even on subsequent Ajax requests.
if (!isset($form_state['user_pass_reset'])) {
$form_state['user_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) {
if (!$form_state['user_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.'))));
@@ -1083,6 +1116,9 @@ function user_account_form(&$form, &$form_state) {
'#access' => !empty($protected_values),
'#description' => $current_pass_description,
'#weight' => -5,
// Do not let web browsers remember this password, since we are trying
// to confirm that the person submitting the form actually knows the
// current one.
'#attributes' => array('autocomplete' => 'off'),
);
$form['#validate'][] = 'user_validate_current_pass';
@@ -1127,7 +1163,7 @@ function user_account_form(&$form, &$form_state) {
$form['account']['roles'] = array(
'#type' => 'checkboxes',
'#title' => t('Roles'),
'#default_value' => (!$register && isset($account->roles) ? array_keys($account->roles) : array()),
'#default_value' => (!$register && !empty($account->roles) ? array_keys(array_filter($account->roles)) : array()),
'#options' => $roles,
'#access' => $roles && user_access('administer permissions'),
DRUPAL_AUTHENTICATED_RID => $checkbox_authenticated,
@@ -1197,7 +1233,7 @@ function user_validate_current_pass(&$form, &$form_state) {
// that prevent them from being empty if they are changed.
if ((strlen(trim($form_state['values'][$key])) > 0) && ($form_state['values'][$key] != $account->$key)) {
require_once DRUPAL_ROOT . '/' . variable_get('password_inc', 'includes/password.inc');
$current_pass_failed = empty($form_state['values']['current_pass']) || !user_check_password($form_state['values']['current_pass'], $account);
$current_pass_failed = strlen(trim($form_state['values']['current_pass'])) == 0 || !user_check_password($form_state['values']['current_pass'], $account);
if ($current_pass_failed) {
form_set_error('current_pass', t("Your current password is missing or incorrect; it's required to change the %name.", array('%name' => $name)));
form_set_error($key);
@@ -1273,10 +1309,12 @@ function user_user_presave(&$edit, $account, $category) {
elseif (!empty($edit['picture_delete'])) {
$edit['picture'] = NULL;
}
// Prepare user roles.
if (isset($edit['roles'])) {
$edit['roles'] = array_filter($edit['roles']);
}
}
// Filter out roles with empty values to avoid granting extra roles when
// processing custom form submissions.
if (isset($edit['roles'])) {
$edit['roles'] = array_filter($edit['roles']);
}
// Move account cancellation information into $user->data.
@@ -1718,21 +1756,23 @@ function user_menu() {
$items['admin/people/create'] = array(
'title' => 'Add user',
'page callback' => 'user_admin',
'page arguments' => array('create'),
'access arguments' => array('administer users'),
'type' => MENU_LOCAL_ACTION,
'file' => 'user.admin.inc',
);
// Administration pages.
$items['admin/config/people'] = array(
'title' => 'People',
'description' => 'Configure user accounts.',
'position' => 'left',
'weight' => -20,
'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' => 'People',
'description' => 'Configure user accounts.',
'position' => 'left',
'weight' => -20,
'page callback' => 'system_admin_menu_block_page',
'access arguments' => array('access administration pages'),
'file' => 'system.admin.inc',
'file path' => drupal_get_path('module', 'system'),
);
$items['admin/config/people/accounts'] = array(
'title' => 'Account settings',
@@ -1878,13 +1918,13 @@ function user_menu_link_alter(&$link) {
// for authenticated users. Authenticated users should see "My account", but
// anonymous users should not see it at all. Therefore, invoke
// user_translated_menu_link_alter() to conditionally hide the link.
if ($link['link_path'] == 'user' && $link['module'] == 'system') {
if ($link['link_path'] == 'user' && isset($link['module']) && $link['module'] == 'system') {
$link['options']['alter'] = TRUE;
}
// Force the Logout link to appear on the top-level of 'user-menu' menu by
// default (i.e., unless it has been customized).
if ($link['link_path'] == 'user/logout' && $link['module'] == 'system' && empty($link['customized'])) {
if ($link['link_path'] == 'user/logout' && isset($link['module']) && $link['module'] == 'system' && empty($link['customized'])) {
$link['plid'] = 0;
}
}
@@ -2115,7 +2155,7 @@ function user_login_default_validators() {
* A FAPI validate handler. Sets an error if supplied username has been blocked.
*/
function user_login_name_validate($form, &$form_state) {
if (isset($form_state['values']['name']) && user_is_blocked($form_state['values']['name'])) {
if (!empty($form_state['values']['name']) && user_is_blocked($form_state['values']['name'])) {
// Blocked in user administration.
form_set_error('name', t('The username %name has not been activated or is blocked.', array('%name' => $form_state['values']['name'])));
}
@@ -2128,7 +2168,7 @@ function user_login_name_validate($form, &$form_state) {
*/
function user_login_authenticate_validate($form, &$form_state) {
$password = trim($form_state['values']['pass']);
if (!empty($form_state['values']['name']) && !empty($password)) {
if (!empty($form_state['values']['name']) && strlen(trim($password)) > 0) {
// Do not allow any login from the current user's IP if the limit has been
// reached. Default is 50 failed attempts allowed in one hour. This is
// independent of the per-user limit to catch attempts from one IP to log
@@ -2192,7 +2232,11 @@ function user_login_final_validate($form, &$form_state) {
}
}
else {
form_set_error('name', t('Sorry, unrecognized username or password. <a href="@password">Have you forgotten your password?</a>', array('@password' => url('user/password'))));
// Use $form_state['input']['name'] here to guarantee that we send
// exactly what the user typed in. $form_state['values']['name'] may have
// been modified by validation handlers that ran earlier than this one.
$query = isset($form_state['input']['name']) ? array('name' => $form_state['input']['name']) : array();
form_set_error('name', t('Sorry, unrecognized username or password. <a href="@password">Have you forgotten your password?</a>', array('@password' => url('user/password', array('query' => $query)))));
watchdog('user', 'Login attempt failed for %user.', array('%user' => $form_state['values']['name']));
}
}
@@ -2215,7 +2259,7 @@ function user_login_final_validate($form, &$form_state) {
*/
function user_authenticate($name, $password) {
$uid = FALSE;
if (!empty($name) && !empty($password)) {
if (!empty($name) && strlen(trim($password)) > 0) {
$account = user_load_by_name($name);
if ($account) {
// Allow alternate password hashing schemes.
@@ -2238,7 +2282,12 @@ function user_authenticate($name, $password) {
* Finalize the login process. Must be called when logging in a user.
*
* The function records a watchdog message about the new session, saves the
* login timestamp, calls hook_user op 'login' and generates a new session. *
* login timestamp, calls hook_user_login(), and generates a new session.
*
* @param array $edit
* The array of form values submitted by the user.
*
* @see hook_user_login()
*/
function user_login_finalize(&$edit = array()) {
global $user;
@@ -2306,7 +2355,10 @@ function user_external_login_register($name, $module) {
* Generates a unique URL for a user to login and reset their password.
*
* @param object $account
* An object containing the user account.
* An object containing the user account, which must contain at least the
* following properties:
* - uid: The user ID number.
* - login: The UNIX timestamp of the user's last login.
*
* @return
* A unique URL that provides a one-time log in for the user, from which
@@ -2314,7 +2366,7 @@ function user_external_login_register($name, $module) {
*/
function user_pass_reset_url($account) {
$timestamp = REQUEST_TIME;
return url("user/reset/$account->uid/$timestamp/" . user_pass_rehash($account->pass, $timestamp, $account->login), array('absolute' => TRUE));
return url("user/reset/$account->uid/$timestamp/" . user_pass_rehash($account->pass, $timestamp, $account->login, $account->uid), array('absolute' => TRUE));
}
/**
@@ -2323,9 +2375,9 @@ function user_pass_reset_url($account) {
* @param object $account
* The user account object, which must contain at least the following
* properties:
* - uid: The user uid number.
* - uid: The user ID number.
* - pass: The hashed user password string.
* - login: The user login name.
* - login: The UNIX timestamp of the user's last login.
*
* @return
* A unique URL that may be used to confirm the cancellation of the user
@@ -2336,7 +2388,7 @@ function user_pass_reset_url($account) {
*/
function user_cancel_url($account) {
$timestamp = REQUEST_TIME;
return url("user/$account->uid/cancel/confirm/$timestamp/" . user_pass_rehash($account->pass, $timestamp, $account->login), array('absolute' => TRUE));
return url("user/$account->uid/cancel/confirm/$timestamp/" . user_pass_rehash($account->pass, $timestamp, $account->login, $account->uid), array('absolute' => TRUE));
}
/**
@@ -2347,21 +2399,42 @@ function user_cancel_url($account) {
* order to validate the URL, the same hash can be generated again, from the
* same information, and compared to the hash value from the URL. The URL
* normally contains both the time stamp and the numeric user ID. The login
* name and hashed password are retrieved from the database as necessary. For a
* usage example, see user_cancel_url() and user_cancel_confirm().
* timestamp and hashed password are retrieved from the database as necessary.
* For a usage example, see user_cancel_url() and user_cancel_confirm().
*
* @param $password
* @param string $password
* The hashed user account password value.
* @param $timestamp
* A unix timestamp.
* @param $login
* The user account login name.
* @param int $timestamp
* A UNIX timestamp, typically REQUEST_TIME.
* @param int $login
* The UNIX timestamp of the user's last login.
* @param int $uid
* The user ID of the user account.
*
* @return
* A string that is safe for use in URLs and SQL statements.
*/
function user_pass_rehash($password, $timestamp, $login) {
return drupal_hmac_base64($timestamp . $login, drupal_get_hash_salt() . $password);
function user_pass_rehash($password, $timestamp, $login, $uid) {
// Backwards compatibility: Try to determine a $uid if one was not passed.
// (Since $uid is a required parameter to this function, a PHP warning will
// be generated if it's not provided, which is an indication that the calling
// code should be updated. But the code below will try to generate a correct
// hash in the meantime.)
if (!isset($uid)) {
$uids = db_query_range('SELECT uid FROM {users} WHERE pass = :password AND login = :login AND uid > 0', 0, 2, array(':password' => $password, ':login' => $login))->fetchCol();
// If exactly one user account matches the provided password and login
// timestamp, proceed with that $uid.
if (count($uids) == 1) {
$uid = reset($uids);
}
// Otherwise there is no safe hash to return, so return a random string
// that will never be treated as a valid token.
else {
return drupal_random_key();
}
}
return drupal_hmac_base64($timestamp . $login . $uid, drupal_get_hash_salt() . $password);
}
/**
@@ -2411,6 +2484,14 @@ function user_cancel($edit, $uid, $method) {
array('_user_cancel', array($edit, $account, $method)),
),
);
// After cancelling account, ensure that user is logged out.
if ($account->uid == $user->uid) {
// Batch API stores data in the session, so use the finished operation to
// manipulate the current user's session id.
$batch['finished'] = '_user_cancel_session_regenerate';
}
batch_set($batch);
// Batch processing is either handled via Form API or has to be invoked
@@ -2418,7 +2499,9 @@ function user_cancel($edit, $uid, $method) {
}
/**
* Last batch processing step for cancelling a user account.
* Implements callback_batch_operation().
*
* Last step for cancelling a user account.
*
* Since batch and session API require a valid user account, the actual
* cancellation of a user account needs to happen last.
@@ -2453,16 +2536,31 @@ function _user_cancel($edit, $account, $method) {
break;
}
// After cancelling account, ensure that user is logged out.
// After cancelling account, ensure that user is logged out. We can't destroy
// their session though, as we might have information in it, and we can't
// regenerate it because batch API uses the session ID, we will regenerate it
// in _user_cancel_session_regenerate().
if ($account->uid == $user->uid) {
// Destroy the current session, and reset $user to the anonymous user.
session_destroy();
$user = drupal_anonymous_user();
}
// Clear the cache for anonymous users.
cache_clear_all();
}
/**
* Implements callback_batch_finished().
*
* Finished batch processing callback for cancelling a user account.
*
* @see user_cancel()
*/
function _user_cancel_session_regenerate() {
// Regenerate the users session instead of calling session_destroy() as we
// want to preserve any messages that might have been set.
drupal_session_regenerate();
}
/**
* Delete a user.
*
@@ -2596,12 +2694,7 @@ function user_build_content($account, $view_mode = 'full', $langcode = NULL) {
$account->content = array();
// Allow modules to change the view mode.
$context = array(
'entity_type' => 'user',
'entity' => $account,
'langcode' => $langcode,
);
drupal_alter('entity_view_mode', $view_mode, $context);
$view_mode = key(entity_view_mode_prepare('user', array($account->uid => $account), $view_mode, $langcode));
// Build fields content.
field_attach_prepare_view('user', array($account->uid => $account), $view_mode, $langcode);
@@ -2805,7 +2898,7 @@ Your account on [site:name] has been canceled.
* An associative array of token replacement values. If the 'user' element
* exists, it must contain a user account object with the following
* properties:
* - login: The account login name.
* - login: The UNIX timestamp of the user's last login.
* - pass: The hashed account login password.
* @param $options
* Unused parameter required by the token_replace() function.
@@ -2961,6 +3054,11 @@ function user_role_delete($role) {
$role = user_role_load_by_name($role);
}
// If this is the administrator role, delete the user_admin_role variable.
if ($role->rid == variable_get('user_admin_role')) {
variable_del('user_admin_role');
}
db_delete('role')
->condition('rid', $role->rid)
->execute();
@@ -3576,12 +3674,7 @@ function user_form_process_password_confirm($element) {
);
$element['#attached']['js'][] = drupal_get_path('module', 'user') . '/user.js';
// Ensure settings are only added once per page.
static $already_added = FALSE;
if (!$already_added) {
$already_added = TRUE;
$element['#attached']['js'][] = array('data' => $js_settings, 'type' => 'setting');
}
$element['#attached']['js'][] = array('data' => $js_settings, 'type' => 'setting');
return $element;
}
@@ -3641,7 +3734,14 @@ function user_action_info() {
}
/**
* Blocks the current user.
* Blocks a specific user or the current user, if one is not specified.
*
* @param $entity
* (optional) An entity object; if it is provided and it has a uid property,
* the user with that ID is blocked.
* @param $context
* (optional) An associative array; if no user ID is found in $entity, the
* 'uid' element of this array determines the user to block.
*
* @ingroup actions
*/
@@ -3672,7 +3772,7 @@ function user_block_user_action(&$entity, $context = array()) {
function user_form_field_ui_field_edit_form_alter(&$form, &$form_state, $form_id) {
$instance = $form['#instance'];
if ($instance['entity_type'] == 'user') {
if ($instance['entity_type'] == 'user' && !$form['#field']['locked']) {
$form['instance']['settings']['user_register_form'] = array(
'#type' => 'checkbox',
'#title' => t('Display on user registration form.'),
@@ -3729,8 +3829,8 @@ function user_register_form($form, &$form_state) {
// inside the submit function interferes with form processing and breaks
// hook_form_alter().
$form['administer_users'] = array(
'#type' => 'value',
'#value' => $admin,
'#type' => 'value',
'#value' => $admin,
);
// If we aren't admin but already logged on, go to the user page instead.
+67 -20
View File
@@ -36,6 +36,7 @@ function user_pass() {
'#size' => 60,
'#maxlength' => max(USERNAME_MAX_LENGTH, EMAIL_MAX_LENGTH),
'#required' => TRUE,
'#default_value' => isset($_GET['name']) ? $_GET['name'] : '',
);
// Allow logged in users to request this also.
if ($user->uid > 0) {
@@ -43,6 +44,12 @@ function user_pass() {
$form['name']['#value'] = $user->mail;
$form['mail'] = array(
'#prefix' => '<p>',
// As of https://www.drupal.org/node/889772 the user no longer must log
// out (if they are still logged in when using the password reset link,
// they will be logged out automatically then), but this text is kept as
// is to avoid breaking translations as well as to encourage the user to
// log out manually at a time of their own choosing (when it will not
// interrupt anything else they may have been in the middle of doing).
'#markup' => t('Password reset instructions will be mailed to %email. You must log out to use the password reset link in the e-mail.', array('%email' => $user->mail)),
'#suffix' => '</p>',
);
@@ -53,6 +60,11 @@ function user_pass() {
return $form;
}
/**
* Form validation handler for user_pass().
*
* @see user_pass_submit()
*/
function user_pass_validate($form, &$form_state) {
$name = trim($form_state['values']['name']);
// Try to load by email.
@@ -71,6 +83,11 @@ function user_pass_validate($form, &$form_state) {
}
}
/**
* Form submission handler for user_pass().
*
* @see user_pass_validate()
*/
function user_pass_submit($form, &$form_state) {
global $language;
@@ -95,22 +112,33 @@ function user_pass_reset($form, &$form_state, $uid, $timestamp, $hashed_pass, $a
// When processing the one-time login link, we have to make sure that a user
// isn't already logged in.
if ($user->uid) {
// The existing user is already logged in.
// The existing user is already logged in. Log them out and reload the
// current page so the password reset process can continue.
if ($user->uid == $uid) {
drupal_set_message(t('You are logged in as %user. <a href="!user_edit">Change your password.</a>', array('%user' => $user->name, '!user_edit' => url("user/$user->uid/edit"))));
// Preserve the current destination (if any) and ensure the redirect goes
// back to the current page; any custom destination set in
// hook_user_logout() and intended for regular logouts would not be
// appropriate here.
$destination = array();
if (isset($_GET['destination'])) {
$destination = drupal_get_destination();
}
user_logout_current_user();
unset($_GET['destination']);
drupal_goto(current_path(), array('query' => drupal_get_query_parameters() + $destination));
}
// A different user is already logged in on the computer.
else {
$reset_link_account = user_load($uid);
if (!empty($reset_link_account)) {
drupal_set_message(t('Another user (%other_user) is already logged into the site on this computer, but you tried to use a one-time link for user %resetting_user. Please <a href="!logout">logout</a> and try using the link again.',
array('%other_user' => $user->name, '%resetting_user' => $reset_link_account->name, '!logout' => url('user/logout'))));
array('%other_user' => $user->name, '%resetting_user' => $reset_link_account->name, '!logout' => url('user/logout'))), 'warning');
} else {
// Invalid one-time link specifies an unknown user.
drupal_set_message(t('The one-time login link you clicked is invalid.'));
drupal_set_message(t('The one-time login link you clicked is invalid.'), 'error');
}
drupal_goto();
}
drupal_goto();
}
else {
// Time out, in seconds, until login URL expires. Defaults to 24 hours =
@@ -122,10 +150,10 @@ function user_pass_reset($form, &$form_state, $uid, $timestamp, $hashed_pass, $a
if ($timestamp <= $current && $account = reset($users)) {
// No time out for first time login.
if ($account->login && $current - $timestamp > $timeout) {
drupal_set_message(t('You have tried to use a one-time login link that has expired. Please request a new one using the form below.'));
drupal_set_message(t('You have tried to use a one-time login link that has expired. Please request a new one using the form below.'), 'error');
drupal_goto('user/password');
}
elseif ($account->uid && $timestamp >= $account->login && $timestamp <= $current && $hashed_pass == user_pass_rehash($account->pass, $timestamp, $account->login)) {
elseif ($account->uid && $timestamp >= $account->login && $timestamp <= $current && $hashed_pass == user_pass_rehash($account->pass, $timestamp, $account->login, $account->uid)) {
// First stage is a confirmation form, then login
if ($action == 'login') {
// Set the new user.
@@ -136,7 +164,7 @@ function user_pass_reset($form, &$form_state, $uid, $timestamp, $hashed_pass, $a
watchdog('user', 'User %name used one-time login link at time %timestamp.', array('%name' => $account->name, '%timestamp' => $timestamp));
drupal_set_message(t('You have just used your one-time login link. It is no longer necessary to use this link to log in. Please change your password.'));
// Let the user's password be changed without the current password check.
$token = drupal_hash_base64(drupal_random_bytes(55));
$token = drupal_random_key();
$_SESSION['pass_reset_' . $user->uid] = $token;
drupal_goto('user/' . $user->uid . '/edit', array('query' => array('pass-reset-token' => $token)));
}
@@ -150,7 +178,7 @@ function user_pass_reset($form, &$form_state, $uid, $timestamp, $hashed_pass, $a
}
}
else {
drupal_set_message(t('You have tried to use a one-time login link that has either been used or is no longer valid. Please request a new one using the form below.'));
drupal_set_message(t('You have tried to use a one-time login link that has either been used or is no longer valid. Please request a new one using the form below.'), 'error');
drupal_goto('user/password');
}
}
@@ -158,6 +186,7 @@ function user_pass_reset($form, &$form_state, $uid, $timestamp, $hashed_pass, $a
// Deny access, no more clues.
// Everything will be in the watchdog's URL for the administrator to check.
drupal_access_denied();
drupal_exit();
}
}
}
@@ -166,6 +195,14 @@ function user_pass_reset($form, &$form_state, $uid, $timestamp, $hashed_pass, $a
* Menu callback; logs the current user out, and redirects to the home page.
*/
function user_logout() {
user_logout_current_user();
drupal_goto();
}
/**
* Logs the current user out.
*/
function user_logout_current_user() {
global $user;
watchdog('user', 'Session closed for %name.', array('%name' => $user->name));
@@ -174,15 +211,16 @@ function user_logout() {
// Destroy the current session, and reset $user to the anonymous user.
session_destroy();
drupal_goto();
}
/**
* Process variables for user-profile.tpl.php.
*
* The $variables array contains the following arguments:
* - $account
* @param array $variables
* An associative array containing:
* - elements: An associative array containing the user information and any
* fields attached to the user. Properties used:
* - #account: The user account of the profile being viewed.
*
* @see user-profile.tpl.php
*/
@@ -289,14 +327,18 @@ function user_profile_form($form, &$form_state, $account, $category = 'account')
}
/**
* Validation function for the user account and profile editing form.
* Form validation handler for user_profile_form().
*
* @see user_profile_form_submit()
*/
function user_profile_form_validate($form, &$form_state) {
entity_form_field_validate('user', $form, $form_state);
}
/**
* Submit function for the user account and profile editing form.
* Form submission handler for user_profile_form().
*
* @see user_profile_form_validate()
*/
function user_profile_form_submit($form, &$form_state) {
$account = $form_state['user'];
@@ -354,7 +396,6 @@ function user_cancel_confirm_form($form, &$form_state, $account) {
$form['_account'] = array('#type' => 'value', '#value' => $account);
// Display account cancellation method selection, if allowed.
$default_method = variable_get('user_cancel_method', 'user_cancel_block');
$admin_access = user_access('administer users');
$can_select_method = $admin_access || user_access('select account cancellation method');
$form['user_cancel_method'] = array(
@@ -518,7 +559,7 @@ function user_cancel_confirm($account, $timestamp = 0, $hashed_pass = '') {
// Basic validation of arguments.
if (isset($account->data['user_cancel_method']) && !empty($timestamp) && !empty($hashed_pass)) {
// Validate expiration and hashed password/login.
if ($timestamp <= $current && $current - $timestamp < $timeout && $account->uid && $timestamp >= $account->login && $hashed_pass == user_pass_rehash($account->pass, $timestamp, $account->login)) {
if ($timestamp <= $current && $current - $timestamp < $timeout && $account->uid && $timestamp >= $account->login && $hashed_pass == user_pass_rehash($account->pass, $timestamp, $account->login, $account->uid)) {
$edit = array(
'user_cancel_notify' => isset($account->data['user_cancel_notify']) ? $account->data['user_cancel_notify'] : variable_get('user_mail_status_canceled_notify', FALSE),
);
@@ -529,18 +570,24 @@ function user_cancel_confirm($account, $timestamp = 0, $hashed_pass = '') {
batch_process('');
}
else {
drupal_set_message(t('You have tried to use an account cancellation link that has expired. Please request a new one using the form below.'));
drupal_set_message(t('You have tried to use an account cancellation link that has expired. Please request a new one using the form below.'), 'error');
drupal_goto("user/$account->uid/cancel");
}
}
drupal_access_denied();
return MENU_ACCESS_DENIED;
}
/**
* Access callback for path /user.
* Page callback: Displays the user page.
*
* Displays user profile if user is logged in, or login form for anonymous
* users.
*
* @return
* A render array for either a user profile or a login form.
*
* @see user_view_page()
* @see user_login()
*/
function user_page() {
global $user;
+512 -202
View File
File diff suppressed because it is too large Load Diff