Community Documentation

user_save

5 user.module user_save($account, $array = array(), $category = 'account')
6 user.module user_save($account, $array = array(), $category = 'account')
7 user.module user_save($account, $edit = array(), $category = 'account')
8 user.module user_save($account, $edit = array())

Save changes to a user account or add a new user.

Parameters

$account: The user object for to modify or add. If you want to modify an existing user account, you will need to ensure that (a) $account is an object, and (b) you have set $account->uid to the numeric user ID of the user account you wish to modify. Pass in NULL or any non-object to add a new user.

$array: (optional) An array of fields and values to save. For example, array('name' => 'My name'); Keys that do not belong to columns in the user-related tables are added to the a serialized array in the 'data' column and will be loaded in the $user->data array by user_load(). Setting a field to NULL deletes it from the data column, if you are modifying an existing user account.

$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.

▾ 11 functions call user_save()

comment_controls_submit in modules/comment/comment.module
Process comment_controls form submissions.
install_configure_form_submit in ./install.php
Form API submit for the site configuration form.
openid_authentication in modules/openid/openid.module
Authenticate a user or attempt registration.
system_admin_compact_page in modules/system/system.admin.inc
Menu callback; Sets whether the admin menu is in compact mode or not.
user_edit_submit in modules/user/user.pages.inc
user_external_login_register in modules/user/user.module
Helper function for authentication modules. Either login in or registers the current user, based on username. Either way, the global $user object is populated based on $name.
user_multiple_role_edit in modules/user/user.module
Callback function for admin mass adding/deleting a user role.
user_profile_form_submit in modules/user/user.pages.inc
Submit function for the user account and profile editing form.
user_register_submit in modules/user/user.module
Submit handler for the user registration form.
user_user_operations_block in modules/user/user.module
Callback function for admin mass blocking users.
user_user_operations_unblock in modules/user/user.module
Callback function for admin mass unblocking users.

File

modules/user/user.module, line 225
Enables the user registration and login system.

Code

<?php
function user_save($account, $array = array(), $category = 'account') {
  // Dynamically compose a SQL query:
  $user_fields = user_fields();
  if (is_object($account) && $account->uid) {
    user_module_invoke('update', $array, $account, $category);
    $query = '';
    $data = unserialize(db_result(db_query('SELECT data FROM {users} WHERE uid = %d', $account->uid)));
    // Consider users edited by an administrator as logged in, if they haven't
    // already, so anonymous users can view the profile (if allowed).
    if (empty($array['access']) && empty($account->access) && user_access('administer users')) {
      $array['access'] = time();
    }
    foreach ($array as $key => $value) {
      if ($key == 'pass' && !empty($value)) {
        $query .= "$key = '%s', ";
        $v[] = md5($value);
      }
      else if ((substr($key, 0, 4) !== 'auth') && ($key != 'pass')) {
        if (in_array($key, $user_fields)) {
          // Save standard fields.
          $query .= "$key = '%s', ";
          $v[] = $value;
        }
        else if ($key != 'roles') {
          // Roles is a special case: it used below.
          if ($value === NULL) {
            unset($data[$key]);
          }
          elseif (!empty($key)) {
            $data[$key] = $value;
          }
        }
      }
    }
    $query .= "data = '%s' ";
    $v[] = serialize($data);

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

    // Reload user roles if provided.
    if (isset($array['roles']) && is_array($array['roles'])) {
      db_query('DELETE FROM {users_roles} WHERE uid = %d', $account->uid);

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

    // Delete a blocked user's sessions to kick them if they are online.
    if (isset($array['status']) && $array['status'] == 0) {
      sess_destroy_uid($account->uid);
    }

    // If the password changed, delete all open sessions and recreate
    // the current one.
    if (!empty($array['pass'])) {
      sess_destroy_uid($account->uid);
      if ($account->uid == $GLOBALS['user']->uid) {
        sess_regenerate();
      }
    }

    // Refresh user object.
    $user = user_load(array('uid' => $account->uid));

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

    user_module_invoke('after_update', $array, $user, $category);
  }
  else {
    // Allow 'created' to be set by the caller.
    if (!isset($array['created'])) {
      $array['created'] = time();
    }
    // Consider users created by an administrator as already logged in, so
    // anonymous users can view the profile (if allowed).
    if (empty($array['access']) && user_access('administer users')) {
      $array['access'] = time();
    }

    // Note: we wait to save the data column to prevent module-handled
    // fields from being saved there. We cannot invoke hook_user('insert') here
    // because we don't have a fully initialized user object yet.
    foreach ($array as $key => $value) {
      switch ($key) {
        case 'pass':
          $fields[] = $key;
          $values[] = md5($value);
          $s[] = "'%s'";
          break;
        case 'mode':
        case 'sort':
        case 'timezone':
        case 'threshold':
        case 'created':
        case 'access':
        case 'login':
        case 'status':
          $fields[] = $key;
          $values[] = $value;
          $s[] = "%d";
          break;
        default:
          if (substr($key, 0, 4) !== 'auth' && in_array($key, $user_fields)) {
            $fields[] = $key;
            $values[] = $value;
            $s[] = "'%s'";
          }
          break;
      }
    }
    $success = db_query('INSERT INTO {users} (' . implode(', ', $fields) . ') VALUES (' . implode(', ', $s) . ')', $values);
    if (!$success) {
      // On a failed INSERT some other existing user's uid may be returned.
      // We must abort to avoid overwriting their account.
      return FALSE;
    }

    // Build the initial user object.
    $array['uid'] = db_last_insert_id('users', 'uid');
    $user = user_load(array('uid' => $array['uid']));

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

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

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

    // Build the finished user object.
    $user = user_load(array('uid' => $array['uid']));
  }

  // Save distributed authentication mappings.
  $authmaps = array();
  foreach ($array as $key => $value) {
    if (substr($key, 0, 4) == 'auth') {
      $authmaps[$key] = $value;
    }
  }
  if (sizeof($authmaps) > 0) {
    user_set_authmaps($user, $authmaps);
  }

  return $user;
}
?>

Comments

Important information about the profile fields

When using this function to modify a user account that has some profile fields, 2 things may happen:

Case 1: You will lose the values stored in the other profile fields that are not included in the $array parameter (the fields that you are not trying to modify).

Solution:

You need to know that the profile module will delete all the existing profile values for the given user before saving them again. Very inefficient resource-wise, I know. But that's what happens. So, you need to load all the profile fields that you want to keep as well as the modified fields in the $array parameter before passing it to user_save(). IMHO, the normal behavior should be that the profile field simply update the provided fields.

Case 2: Some profile values are not making it to their corresponding fields in the database. Instead, they are being stored in a serialized array in the data field of the $user object. This will break things if you are using those profile fields in the views module as the views will not find the value of the field.

Solution:

This happens because some profile fields have not been made visible on the registration form. Because of that, even if a user is being created with user_save() by the admin (programmatically), the profile module will think that it is being done via the registration form and will NOT add the values of those fields. They will end up being stored in the $user->data field.

I hope this help.

Cheers

Asiby

Profile data not visible in Views

I red your #2 solution

"This happens because some profile fields have not been made visible on the registration form. Because of that, even if a user is being created with user_save() by the admin (programmatically), the profile module will think that it is being done via the registration form and will NOT add the values of those fields. They will end up being stored in the $user->data field."

I switched the "visible on the registration form" of any profile field to ON.

Then I programmatically inserted users and their profiles.

Anything works except that I cannot find profile data in Views.

Can you help help me please?

Thanks

luca

Asiby, you genius. Thanks for

Asiby, you genius. Thanks for breaking this down. I was running into Case 2 -- fields not visible on the registration page weren't being saved. I'll have to use db_query() to perform this step manually, unfortunately.

profile data, D6

if you want to save certain profile data fields without printing out and saving them all, you need to write a custom function that does an update, not a delete + insert, which profile_save_profile() does.

<?php
// your custom profile saving function
function mymodule_save_profile(&$edit, &$user, $category, $register = FALSE){
 
$result = _profile_get_fields($category, $register);
  while (
$field = db_fetch_object($result)) {
    if(isset(
$edit[$field->name])){
      if (
_profile_field_serialize($field->type)) {
       
$edit[$field->name] = serialize($edit[$field->name]);
      }
     
db_query("UPDATE {profile_values} SET value = '%s' WHERE fid = %d AND uid = %d", $edit[$field->name], $field->fid, $user->uid);
    }
   
// Mark field as handled (prevents saving to user->data).
   
$edit[$field->name] = NULL;
  }
}

// you just got some user data from a form...
global $user;
// load the profile data
profile_load_profile(&$user);
// your changes to resave into the profile without touching the other ones
$edit['profile_city'] = "Chicago";
$edit['profile_state'] = "IL";
// save just city and state
mymodule_save_profile(&$edit, &$user, "My Information");
?>

Thanks, but when profile field don't exist...

thanks,
if a user is being created with user_save() by the admin (programmatically), then the profile field don't exist, so it couldn't be updated. then i edit some code from yours:

<?php
function my_module_save_profile(&$edit, &$user, $category, $register = FALSE) {
 
$result = _profile_get_fields($category, $register);
  while (
$field = db_fetch_object($result)) {
    if(isset(
$edit[$field->name])){ // this prevent from deleting other stored fields
     
if (_profile_field_serialize($field->type)) {
       
$edit[$field->name] = serialize($edit[$field->name]);
      }
     
db_query("DELETE FROM {profile_values} WHERE fid = %d AND uid = %d", $field->fid, $user->uid);
     
db_query("INSERT INTO {profile_values} (fid, uid, value) VALUES (%d, %d, '%s')", $field->fid, $user->uid, $edit[$field->name]);
    }
   
// Mark field as handled (prevents saving to user->data).
   
$edit[$field->name] = NULL;
  }
}
?>

it's the same thing

you're doing the same thing as an update because your delete/insert is within the 'isset' check, but you are correct in that i'm assuming you have all the profile fields created before you start adding users into the system.

if you need to add an additional profile field at some later date, you'd just initialize it by inserting a empty row with corresponding fid into the profile values table for all users.

$category argument

The $category argument for this function is NOT optional if you have categories defined for the profile. If you don't give the profile category, the profile field will NOT be saved...argh! This means if you have more than one category to save, you have to make separate calls to this function...one call for each category. Also, very inefficient...sigh.

Issue

$category argument

>>if you have more than one category to save, you have to make separate calls to this function
if you have just one additional category of profile fields (except of 'account'), you can pass it in $category argument, and both, main fields, and additional, from profile module will updated/saved

Add/update user information by user_save().

I think this will solve your problem. Using this you can add/update user information coming from external source like XML or any other.

1. first create $user array() with your all required fields and append profile fields that you have newly created by using profile module.

$user = array();
$user['status'] = 1; //for active user
$user['mail'] = 'test@test.com';
//profile field
$user['profile_field_fname'] = 'Vikrant';

$user_account = array();
if($user_uid = module_name_get_uid_by_email($user['mail'])) {
//It will use for update.
$user_account = user_load(array(uid => $user_uid));
}
//save or update user information.
user_save($user_account, $user);

//Check existing record by email.
function module_name_get_uid_by_email($email){
$query = db_query("SELECT uid FROM {users} WHERE mail = '%s'",$email);
$result = db_fetch_object($query);
return $result->uid;
}

Use user_load intead

I think it's possible to use:

user_load(array('mail'=>$user['mail']));

insted of your module_name_get_uid_by_email function.

user_save returns user objects after save.

user_save returns user object after save. So you can return any value like name,email or uid etc.

$my_user = user_save($user_account, $user);
return $my_user->uid;

It may be obvious to some,

It may be obvious to some, but not to me...

If you want to change $user->status or add a $user->role -- you don't directly change the user object, you add these to an array at the end of the function, like so:

<?php
$account
= user_load(2); // load the user account you want to change
$update['status'] = 1;
$roles = user_roles(true); // load the site's roles
$update['roles'][2] = $roles[2]; // authenticated user
$update['roles'][4] = $roles[4]; // any other role you wish (could come from a variable)
$updated_account = user_save($account, $update);
?>

Thanks Josh, it was not

Thanks Josh, it was not obvious to me either.

Non persistence of modifications

Hi,

I have a big problem,

In a function called in ajax, I do that:

   $myuser = user_load('9');

    $id = $_POST['id'];
    $id = str_replace("editable_", "", $id);
  
    //$changes = get_object_vars($user);
    $changes[$id] = $_POST['value'];

    $myuser = user_save($myuser, $changes);

This code works great for some fields (for example profile_firstname) but for some other (like mail), the modification doesn't persist after a page reloading.

The modification of mail's field is correctly applied in the database, but when I reload a page, the modification is lost and the mail's field return to is original value....

PS: the problem is the same if this code is called without ajax...

My bad...

Sorry, after search it's because of a conflict with the module ldap_data...

Thanks

Login or register to post comments