| 7 user.module | user_save($account, |
| 4.6 user.module | user_save($account, $array = array(), $category = 'account') |
| 4.7 user.module | user_save($account, $array = array(), $category = 'account') |
| 5 user.module | user_save($account, $array = array(), $category = 'account') |
| 6 user.module | user_save($account, $array = array(), $category = 'account') |
Save changes to a user account or add a new user.
@todo D8: Drop $edit and fix user_save() to be consistent with others.
Parameters
$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.
$edit: 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.
$category: (optional) The category for storing profile information in.
Return value
A fully-loaded $user object upon successful save or FALSE if the save failed.
- BlockCacheTestCase::setUp in modules/
block/ block.test - Sets up a Drupal site for running functional and integration tests.
- ContactPersonalTestCase::testPersonalContactAccess in modules/
contact/ contact.test - Tests access to the personal contact form.
- DrupalWebTestCase::drupalCreateUser in modules/
simpletest/ drupal_web_test_case.php - Create a user with a given set of permissions.
- EntityCrudHookTestCase::testUserHooks in modules/
simpletest/ tests/ entity_crud_hook_test.test - Tests hook invocations for CRUD operations on users.
- FileFieldRevisionTestCase::testRevisions in modules/
file/ tests/ file.test - Tests creating multiple revisions of a node and managing attached files.
File
- modules/
user/ user.module, line 424 - Enables the user registration and login system.
Code
function user_save($account, $edit = array(), $category = 'account') {
$transaction = db_transaction();
try {
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']);
}
if (isset($edit['mail'])) {
$edit['mail'] = trim($edit['mail']);
}
// Load the stored entity, if any.
if (!empty($account->uid) && !isset($account->original)) {
$account->original = entity_load_unchanged('user', $account->uid);
}
if (empty($account)) {
$account = new stdClass();
}
if (!isset($account->is_new)) {
$account->is_new = empty($account->uid);
}
// 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;
}
// Invoke hook_user_presave() for all modules.
user_module_invoke('presave', $edit, $account, $category);
// Invoke presave operations of Field Attach API and Entity API. Those APIs
// require a fully-fledged and updated entity object. Therefore, we need to
// copy any new property values of $edit into it.
foreach ($edit as $key => $value) {
$account->$key = $value;
}
field_attach_presave('user', $account);
module_invoke_all('entity_presave', $account, 'user');
if (is_object($account) && !$account->is_new) {
// Process picture uploads.
if (!empty($account->picture->fid) && (!isset($account->original->picture->fid) || $account->picture->fid != $account->original->picture->fid)) {
$picture = $account->picture;
// If the picture is a temporary file move it to its final location and
// make it permanent.
if (!$picture->status) {
$info = image_get_info($picture->uri);
$picture_directory = file_default_scheme() . '://' . 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 . '-' . REQUEST_TIME . '.' . $info['extension']);
// Move the temporary file into the final location.
if ($picture = file_move($picture, $destination, FILE_EXISTS_RENAME)) {
$picture->status = FILE_STATUS_PERMANENT;
$account->picture = file_save($picture);
file_usage_add($picture, 'user', 'user', $account->uid);
}
}
// Delete the previous picture if it was deleted or replaced.
if (!empty($account->original->picture->fid)) {
file_usage_delete($account->original->picture, 'user', 'user', $account->uid);
file_delete($account->original->picture);
}
}
elseif (isset($edit['picture_delete']) && $edit['picture_delete']) {
file_usage_delete($account->original->picture, 'user', 'user', $account->uid);
file_delete($account->original->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');
if ($success === FALSE) {
// The query failed - better to abort the save than risk further
// data loss.
return FALSE;
}
// Reload user roles if provided.
if ($account->roles != $account->original->roles) {
db_delete('users_roles')->condition('uid', $account->uid)->execute();
$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,
));
}
}
$query->execute();
}
// Delete a blocked user's sessions to kick them if they are online.
if ($account->original->status != $account->status && $account->status == 0) {
drupal_session_destroy_uid($account->uid);
}
// If the password changed, delete all open sessions and recreate
// the current one.
if ($account->pass != $account->original->pass) {
drupal_session_destroy_uid($account->uid);
if ($account->uid == $GLOBALS['user']->uid) {
drupal_session_regenerate();
}
}
// Save Field data.
field_attach_update('user', $account);
// Send emails after we have the new user object.
if ($account->status != $account->original->status) {
// The user's status is changing; conditionally send notification email.
$op = $account->status == 1 ? 'status_activated' : 'status_blocked';
_user_mail_notify($op, $account);
}
// Update $edit with any interim changes to $account.
foreach ($account as $key => $value) {
if (!property_exists($account->original, $key) || $value !== $account->original->$key) {
$edit[$key] = $value;
}
}
user_module_invoke('update', $edit, $account, $category);
module_invoke_all('entity_update', $account, 'user');
}
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($account->uid)) {
$account->uid = db_next_id(db_query('SELECT MAX(uid) FROM {users}')->fetchField());
}
// Allow 'created' to be set by the caller.
if (!isset($account->created)) {
$account->created = REQUEST_TIME;
}
$success = drupal_write_record('users', $account);
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;
}
// Make sure $account is properly initialized.
$account->roles[DRUPAL_AUTHENTICATED_RID] = 'authenticated user';
field_attach_insert('user', $account);
$edit = (array) $account;
user_module_invoke('insert', $edit, $account, $category);
module_invoke_all('entity_insert', $account, 'user');
// Save user roles.
if (count($account->roles) > 1) {
$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,
));
}
}
$query->execute();
}
}
// Clear internal properties.
unset($account->is_new);
unset($account->original);
// Clear the static loading cache.
entity_get_controller('user')->resetCache(array($account->uid));
return $account;
}
catch (Exception $e) {
$transaction->rollback();
watchdog_exception('user', $e);
throw $e;
}
}
Comments
Saving fields in user account
PermalinkTo save fields data in user account we can act this way:
$account = user_load($uid); // Loading account$edit = array(
'field_some_custom_field' => array(
'und' => array(
0 => array(
'value' => $new_value,
),
),
),
);
user_save($account, $edit);
Big typo
PermalinkDepends on Field type.
Some types want other than standard "value" key name:
Link - "url"
Email - "email"
taxonomy term reference
Permalink'tid' => $new_value,
Getting newly saved user id
PermalinkI was looking and looking to find out how to add a new user to an organic group via a custom form.
Here is what I found out.
$new_user = array('name' => $form_state['values']['name'],
'pass' => user_password(),
'mail' => $form_state['values']['mail'],
'init' => $form_state['values']['mail'],
'field_first_name' => array(LANGUAGE_NONE => array(array('value' => $form_state['values']['field_first_name']))),
'field_last_name' => array(LANGUAGE_NONE => array(array('value' => $form_state['values']['field_last_name']))),
'field_phone_number' => array(LANGUAGE_NONE => array(array('value' => $form_state['values']['field_phone_number']))),
'status' => 1,
'access' => REQUEST_TIME,
'roles' => $roles,
);
// $account returns user object
$account = user_save(null, $new_user);
// $group is organic group node I want to add the brand new user to
$group = og_get_group('node', $node->nid);
// This adds user to the group
og_group($group->gid, array('entity' => $account));
Hope this helps some folks along with adding a new user to a group!
Saving a new profile picture
PermalinkWorth noting:
Even though the user object that is returned from
user_load()(and by this function) stores an integer value in$user->picture(being the file'sfid), that is not the correct data type to use if you wish to update the profile picture using this function. If you try to do so, somehow this function silently fails, and none of your other attempted edits will be saved either (still not sure why there isn't instead an error somewhere).The correct way to update the profile picture is to pass its associated file object in the
$editarray, not its integerfid.user_save cannot be used to edit the anonymous user
PermalinkThe anonymous user in Drupal has a uid=0.
When execution reaches this line:
if (!empty($account->uid) && !isset($account->original)) {The call to empty returns true because of the zero value, and user_save decides it is a new user. This will fail because the new user has a duplicate username.
So if you need to edit all users (I am setting a default value for a custom field), you need to strip uid=0 from the list and deal with it as a special case.
User data going away
PermalinkUser data is going away in Drupal 8 and user data is difficult to list. Move your data into fields. You can then list users that have your data and you can list their values.
Each extra field will slow down your database a little bit. If you have several related items, you might want to group them the way the address field module groups address fields in one row.
User save trips up some other modules
PermalinkWhen you save a user, other modules have their user hooks called to modify the user. If you get weird results, such as missing fields, it can be another module responding to a hook and changing stuff.
Your save might be followed by another module changing the same field. Another module might respond as if you are editing the user in the admin page. A good test is to visit the user in the admin edit page, note all the values, run your save, then visit the user in the admin edit page and look for unexpected changes.
---
PermalinkIn Drupal 8, this function has been replaced from Entity::save().
save user field programatically
PermalinkThe example user_save($user, array("key" => "value")); is wrong! Instead do something like this
<?phpglobal $user;
$user_fields = user_load($user->uid);
$myfield = $user_fields->field_myfield;
$myfield['und'][0]['value'] = "This value was set programatically";
user_save($user,"field_myfield"=>$myfield);
?>
Inconsistancy in code examples
PermalinkWhen searching for examples of updating existing users programmatically you find many variations in code and in most cases they all work.
The reason for this is that $edit (should contain changes only) is copied into $account by user_save().
As a result if you assign a changed field to account instead of to the $edit the result will be the same
so:
$account = user_load($uid);$edit = array();
$edit['field_first_name'][LANGUAGE_NONE][0]['value'] = 'Guy';
$edit['field_last_name'][LANGUAGE_NONE][0]['value'] = 'Schneerson';
user_save($account, $edit);
and
$account = user_load($uid);$account->field_first_name[LANGUAGE_NONE][0]['value'] = 'Guy';
$account->field_last_name[LANGUAGE_NONE][0]['value'] = 'Schneerson';
$edit = array();
user_save($account, $edit);
Will both work, however the first one is the correct way of doing things.
Importent note about $edit
Permalink$edit should contain changes you want saved, however if you have a multi value element you need to include all its values
for example adding a role
Wrong way: will remove all roles except 'new role'
$account = user_load($uid);$edit = array();
$edit['roles'][NEW_ROLE] = 'new role';
user_save($account, $edit);
Correct way: will add 'new role' to existing roles
$account = user_load($uid);$edit = array();
$edit['roles'] = $account->roles;
$edit['roles'][NEW_ROLE] = 'new role';
user_save($account, $edit);
Use for Feeds Module to import user
PermalinkI wanna ask you something for this part:
$account = user_load($uid); // Loading account$edit = array(
'field_some_custom_field' => array(
'und' => array(
0 => array(
'value' => $new_value,
),
),
),
);
user_save($account, $edit);
What is 'field_some_custom_field' ? Where do i find, what name i have to write there? I want to add custom hidden fields as targets for Feeds Module (to import users automatically one time a day).
Maybe somebody can help me how to add this function in the FeedsUserProcessor.inc.php
I have found out, that you have to add 2 parts of code for every target you want to add. I have found the code for Adding User Roles for example:
if ($account->roles_list) {$roles = explode(',', $account->roles_list);
foreach ($roles as $role_name) {
$role_name = trim($role_name);
if (!$role = user_role_load_by_name($role_name)) {
// Create new role if role doesn't exist
$role = new stdClass();
$role->name = $role_name;
user_role_save($role);
$role = user_role_load_by_name($role->name);
}
$account->roles[$role->rid] = $role->name;
}
}
and
'roles_list' => array('name' => t('User roles'),
'description' => t('User roles'),
),
I also know, that the first part is to use / work with the the input (but i dont know where it gets saved) and the second part is for naming and descibing the target for the backend UI. But i am not good enough to use this knowledge for adding other/additional user fields.
Maybe somebody could make an example?
Create a new user with role
Permalink<?php$account->name = 'me';
$account->pass = 'xxx';
$account->mail = 'x@x.com';
$account->status = 1; // 3 and 4 are role id's
$roles = array(3 => true, 4 => true);
$account->roles = $roles; user_save($account);
?>
Beware. I tried this and the
PermalinkBeware. I tried this and the password was saved un-encrypted in the database. You need to add it to the second argument:
user_save($account, array('pass' => 'xxx'));