I need to be able to save users who already have encrypted passwords. It seems to be a common need, perhaps not as much for people using this with profiles but more with people (like me) using the module to move data between drupal sites or migrate from other platforms.
I wrote the following function to facilitate saving a user with a password that is already encrypted (not by default but by specifying it as an option). Instead of creating a user with user_save(), it does a drupal_write to add the user (thus allowing it to bypass the md5, if needed) and then updates the user via user_save() so it can take advantage of the hook_user 'save' operation. It is working pretty well for me but could really benefit from additional eyes looking at it.
The function will also check against existing user names and optionally overwrite the user. It will also add roles if necessary, if specifying roles by name.
/**
* Save a user
*
* @param $user
* An array of user properties
* - uid // if uid is present, will overwrite existing user
* - name
* - pass
* - mail
* - mode //comment display mode
* - sort //comment sort order
* - threshold // not used?
* - theme //user's default theme
* - signature
* - created
* - access
* - login
* - status
* - timezone
* - language
* - picture //path to user's picture
* - init
* - data //serialized array of other data
* - roles // An array of rids to assign to the user
* - role_names //an array of role names to assign to user
* (Additional array elements can be included from user form)
*
* @param $options
* An array of options when saving
* - encrypted // is the password already encrypted
* - overwrite // overwrite user if same user name already exists
* - add_role // add role if it doesn't exist
*
* @return
* The $user object
*/
function install_save_user($user, $options = array()){
// Check to see if user name exists
if ($user['name']){
$uid = db_result(db_query("SELECT uid FROM {users} WHERE name = '%s'", $user['name']));
if ($options['overwrite']){
if ($uid){
$user['uid'] = $uid;
}
}
}
// The user already exists
if ($user['uid']){
$account = array(
'uid' => $user['uid'],
);
$account['access'] = $user['access'] ? $user['access'] : time();
$account['status'] = $user['status'] ? $user['status'] : TRUE;
//Even if an account already exists, the password may need to be updated
if (!$options['md5']){
// drupal_write_record() wants $user to be object
$user_object = (object) $user;
drupal_write_record('users', $user_object, 'uid');
//Don't run the risk of the password getting encrypted and re-inserted
unset($user['pass'], $account['pass']);
}
}
// The user doesn't exist
elseif (!$uid) {
$defaults = array(
'created' => time(),
'access' => time(),
'login' => time(),
'status' => TRUE,
);
$user = array_merge($defaults, $user);
// Password needs to be encrypted
if (!$options['encrypted'] && $user['pass']){
$user['pass'] = md5($user['pass']);
}
// drupal_write_record() wants $user to be object
$user_object = (object) $user;
drupal_write_record('users', $user_object);
$uid = db_last_insert_id('users', 'uid');
$account = array(
'uid' => $uid,
'status' => TRUE,
'access' => time(),
'created' => time(),
);
$user['uid'] = $uid;
}
// The user exists but is not going to be overwritten
else {
drupal_set_message(t('The name %name is already taken.', array('%name' => $user['name'])));
return FALSE;
}
// Get data ready for user_save()
if ($user['category']){
$category = $user['category'];
unset($user['category']);
}
else {
$category = 'account';
}
// Different sites may have different role rids and need to use role names
if ($user['role_names']){
$names = $user['role_names'];
unset($user['role_names']);
foreach($names As $name){
unset($rid);
$rid = db_result(db_query("SELECT rid FROM {role} WHERE name = '%s'", $name));
if (!$rid && $options['add_role']){
$rid = install_add_role($name);
}
if ($rid){
$user['roles'][$rid] = $name;
}
}
}
// user_save() wants account to be object
$account = (object) $account;
$user = user_save($account, $user, $category);
return $user;
}
Comments
Comment #1
dww#309042: Insert users with already-hashed passwords