Create a user account in Drupal 7 programmatically

By shane
Wed, 2012-06-27 21:18
25 comments

Share with Others

As a follow up to my post on how to create a user account in Drupal 6 programmatically, I ran into a situation where I needed to do this in Drupal 7. Pretty similar but a few differences. So here you go:
 
  //This will generate a random password, you could set your own here
  $password = user_password(8);
 
  //set up the user fields
  $fields = array(
    'name' => 'user_name',
    'mail' => 'user_name@example.com',
    'pass' => $password,
    'status' => 1,
    'init' => 'email address',
    'roles' => array(
      DRUPAL_AUTHENTICATED_RID => 'authenticated user',
    ),
  );
 
  //the first parameter is left blank so a new user is created
  $account = user_save('', $fields);
 
  // If you want to send the welcome email, use the following code
 
  // Manually set the password so it appears in the e-mail.
  $account->password = $fields['pass'];
 
  // Send the e-mail through the user module.
  drupal_mail('user', 'register_no_approval_required', $email, NULL, array('account' => $account), variable_get('site_mail', 'noreply@example..com'));
Note: You can add additional roles inside the role array using the role id as the array index and the role name as the value.
Questions? Let me know in the comments below.

Comments

I have not actually tested this, but I think something like the following might work. This is assuming you have added two fields to the user account entity in Drupal 7 called "field_first_name" and "field_last_name".

  $fields = array(
    'name' => 'user_name',
    'mail' => '<a href="mailto:user_name@example.com" rel="nofollow">user_name@example.com</a>',
    'pass' => $password,
    'status' => 1,
    'init' => 'email address',
    'roles' => array(
      DRUPAL_AUTHENTICATED_RID => 'authenticated user',
    ),
  );
 
  $fields['field_first_name'][LANGUAGE_NONE][0]['value'] = 'First Name';
  $fields['field_last_name'][LANGUAGE_NONE][0]['value'] = 'Last Name';

Let me know if that helps.

The above code didn't work.

Tried the following but also failed.

$fields = array(
    'name' => 'user_name',
    'mail' => '<a href="mailto:user_name@example.com" rel="nofollow">user_name@example.com</a>',
    'pass' => $password,
    'status' => 1,
    'init' => 'email address',
    'roles' => array(DRUPAL_AUTHENTICATED_RID => 'authenticated user',
    'field_first_name' => array(LANGUAGE_NONE => array(0 => array('value' => 'First Name'))),
    'field_last_name' => array(LANGUAGE_NONE => array(0 => array('value' => 'Last Name'))),
    ),
  );

The user will be created but none will be supplied to First and Last name. :(

It might help to do something like this on a user that has the first and last name fields filled out to see how it is structured. It might help you figure out how you need to structure the fields when you save the user.

// load a user that has a first and last name field filled out
user_load(1);
print('<pre>'.print_r($user,1).'</pre>');

Let me know if that helps at all.

Hi shane! Just dropping by your site to tell you the solution I made.

Yes, by doing a print_r when a user is being programmatically created showed me that "field_first_name" & "field_last_name" has values. But the problem is, when you actually visit that account, those values for First Name and Last Name will not show on the account's info / profile. Even when you edit the info for that user, First Name and Last Name won't have anything. So I assumed at first that "field_first_name" & "field_last_name" don't have anything.

Anyway, my problem is fixed. Full code below.

$new_user = array(
		'name' => 'Username',
		'pass' => 'Password',
		'mail' => 'Email',
		'signature_format' => 'full_html',
		'status' => 1,
		'timezone' => 'America/New_York',
		'init' => 'Email',
		'roles' => 'Roles',
		'field_first_name' =>
			array(LANGUAGE_NONE =>
			array(0 =>
			array('value' => 'First Name'))),
		'field_last_name' =>
			array(LANGUAGE_NONE =>
			array(0 =>
			array('value' => 'Last Name'))),
);
$account= user_save(NULL, $new_user);
 
db_insert('field_data_field_first_name')
	->fields(array(
	'entity_type' => 'user',
	'bundle' => 'user',
	'deleted' => 0,
	'entity_id' => $account->uid,
	'language' => 'und',
	'delta' => 0,
	'field_first_name_value' => 'First Name',
	))
	->execute();
 
db_insert('field_data_field_last_name')
	->fields(array(
	'entity_type' => 'user',
	'bundle' => 'user',
	'deleted' => 0,
	'entity_id' => $account->uid,
	'language' => 'und',
	'delta' => 0,
	'field_last_name_value' => 'Last Name',
	))
	->execute();

Thanks for the help man!

Seems to me that it's better to use the Entity API for this.
So instead of setting fields manually or entering stuff in db manually, i'd rather do something like this (not tested), after $account = user_save(...):

$wrapper = entity_metadata_wrapper('user', $account);
$wrapper->field_firstname->set('John');
$wrapper->field_lastname->set('Doe');
$wrapper->save;

Much cleaner, I think.


$new_user = array(
'name' => 'Username',
'pass' => 'Password',
'mail' => 'Email',
'signature_format' => 'full_html',
'status' => 1,
'timezone' => 'America/New_York',
'init' => 'Email',
'roles' => 'Roles',
'field_first_name' => array(
'und' => array(
0 => array(
'value' => 'First Name',
),
),
'field_last_name' => array(
'und' => array(
0 => array(
'value' => 'Last Name',
),
),
);
$account= user_save(NULL, $new_user);

This will do the trick without the need for db_insert(). Check your database for the custom field column name. Depending on entity type it is not always 'value', eg it could be 'fid' for file id.

where should i put above programmatically user account creation code
actually i created one newuser.php page in drupal folder root directory
in that which reference files i need to include for below php code..

new_user = array(
'name' => 'Username',
'pass' => 'Password',
'mail' => 'Email',
'signature_format' => 'full_html',
'status' => 1,
'timezone' => 'America/New_York',
'init' => 'Email',
'roles' => 'Roles',
'field_first_name' => array(
'und' => array(
0 => array(
'value' => 'First Name',
),
),
'field_last_name' => array(
'und' => array(
0 => array(
'value' => 'Last Name',
),
),
);
$account= user_save(NULL, $new_user);
// Send the e-mail through the user module.
  drupal_mail('Username', 'register_no_approval_required', $email, NULL, array('account' => $account), variable_get('site_mail', '<a href="mailto:noreply@example..com" rel="nofollow">noreply@example..com</a>'));

It depends on what you are doing with the code as to where it needs to be placed. Generally you don't want to create a .php page within a Drupal module. Drupal module files generally should have the extension of .module or .inc.

If you can provide some details on what you are trying to accomplish I may be able to provide some more help.

Thanks for the comment.

I used the above method to add the user and its successfully registered, After logged into the admin panel, i cannot able to submit any form (ex: edit profile ) it throws an error as,

The form has become outdated. Copy any unsaved work in the form below and then reload this page.

please help me on this.

Can you provide some more details as to what the problem is? Is it only profile forms for that specific user that was created or is it all forms on the site? If you log in as that specific user and try to edit any of the user profile forms, are you still getting the same error? What about if you try it as the administrative user?

I might be able to help you out if I can get a few more details.

Thanks for the comment.

Hi guys
Just found this site. Thanks for the great tutorials and discussion.
Have a project where people become members on a Wordpress site at a different domain. Then we are building an "online university" to support the other site.

Need to access user database on Wordpress site and authenticate the user exists there, then see if user also exists on our site and log them in (after they have entered email and pass on a login form).
If user exists on our site but with different pass than on WP site, update account and let them in. If they exist on WP site but not yet on our site, register them and let them in.

Right now it's working between WP and a temporary Joomla version of the site, but need to have this working on Drupal version being developed.

Any ideas???

Thanks for your help

JEO

Hi this is ko,I like know ,how to create the user with multiple roles via code....
what is the data structure to roles key ?
how to declare the multiple roles...?

The data structure is an array with the role id being the array key and the role name being the array value. Something like this:

'roles' => array(
  DRUPAL_AUTHENTICATED_RID => 'authenticated user',
  5 => 'test role',
  6 => 'another role',
),

Hi, it does not make sense for me: Why you need both role id and name for it.
I did not find ant reference for it? Does anyone has one?

Also, another great tool for messing around with users and adding custom fields is the Features module.

It always you to save your custom user fields, modify them and install them on other drupal installs or whatever.

It's also super helpful in figuring out what data structure you need to use to save and update users. Aside from the stock user fields, everything with a user's custom fields is no different than messing around with a node or other entity.

How do I check if the user name already exists?

You could use following code to send the email which is cleaner

  $op = 'register_no_approval_required';
  $account = $user;
  $language = 'fi';
  _user_mail_notify($op, $account, $language);

I am not sure about the time of writting, but for now the following line will not work.
$account= user_save(NULL, $new_user);
As you can see in the user_save function, the first argument is an account object; the second one is an $edit array. If an account object gets passed in the place of $edit, we get an error of attempt to use object as an array. The solution lies in adding the is_new property to an account object.
...
$account->is_new = TRUE;
user_save($account);

If you follow the code above, the $new_user variable would be an array of account fields. The first argument to the user_save function is an optional $account object. So in the example above, since there is no account yet, we leave that one blank. We then pass in an array of account fields that will be used when creating and returning the new account object.

Looking at your example though, it looks like your method should work too if you are creating an account object, rather than using an array syntax. Both should work, its just a matter of preference on which method you prefer to use.

Hi Shane,
I've a requirement where I want to create a temporary users who can create a content in the system.
The flow goes like this:

1. System generated mail will be sent to user's email id with some URL.
2. This URL will allow that user to add specific content.
3. This URL will be expired after the user adds the content.

Thanks Shane for all the help you provided over the last years.

Regards,
Rahul

This one could be a little tricky but should be possible. If you want to stick to this exact flow, you probably will not be able to use a traditional Drupal user account (especially if you don't want the user to have to log in with a username and password).

If you want the exact flow you mentioned, you will need to create a custom module with a custom database table. This database table will need to keep track of information such as the temporary user email, a randomly generated URL, and a status (to track when the URL is expired). You might also need additional columns to keep track of the content that user is supposed to have access to edit.

You will then need to implement hook_menu and create a custom menu item. This menu item should accept a parameter. This parameter will be the random string that will match an item in the database. You will want to implement an access callback to verify that this random string is in the database table and the status is still active. If so, the access check should pass.

The menu callback will need to load the content edit form. If this is a node form, then you will need to store the node id (or other information) in the database so the page knows what content this user can access. You may be able to use drupal_get_form to load this node. You will need to append the random string information to the form so you can check for it later.

You will need to then implement the hook_form_alter function to check if the random string information is available when the content was saved. If it is, then the database entry will need to be updated so the content is no longer accessible by this URL.

This is just a few quick ideas on how this might work. I don't know for sure how much work it would be to get around all of the node_access checks to allow an anonymous user to bypass the permissions and edit the content.

WARNING: If you do this, you are bypassing the node access checks and the Drupal permissions system. You will want to make sure you test this thoroughly and make sure it is actually what you want to do. If you don't mind making the user log in with a username and password first, you might be able to still give them temporary access, but it might be a little more secure.

Good luck and let me know how it goes.

Hi,
When creating a user using wrappers, I use the next code. Note the password encryption, and filling soma basic/fixed configurations, as language or signup/signin dates.

   // This is needed for user_hash_password()
   require_once($GLOBALS['_SERVER']['DOCUMENT_ROOT'] . "/includes/password.inc");
 
   // Prepare the entity
   $newUser = 
      entity_create(
         'user', 
         array('created' => strtotime($date)));
    // Try to fill it in
   try {
      $newUser->name     = $username;
      $newUser->pass     = user_hash_password($password);
      $newUser->mail     = $email;
      $newUser->init     = $email;
      $newUser->status   = 1;
      $newUser->roles    = drupal_map_assoc(array(6) + array(DRUPAL_AUTHENTICATED_RID));
      $newUser->signature_format = 'filtered_html';
      $newUser->timezone = 'Europe/Madrid';
      $newUser->language = 'ca';
 
      $newUser->access = strtotime($lastAccess);
      $newUser->login = strtotime($lastAccess);
   } catch (Exception $e) {
      dpm(array(
         'Error' => "filling user data: '" . $username . "': " . $e->getMessage(),
         'Exception' => $e,
      ));
   }
 
   try {
      entity_save('user', $newUser);
   } catch (Exception $e) {
      dpm(array(
         'Error' => "saving user data: '" . $username . "': " . $e->getMessage(),
         'Exception' => $e,
      ));
   }

Post new comment