I'm just working on a simple SHA module that adds a SHA hash to the user table that I could use by external programs for authentication. I've gotten the user table modified correctly (ALTER TABLE {users} ADD `pass_sha1` varchar(40) NOT NULL). Now what I'm having problems with are automatically updating the SHA1 field when a user is registered (either by admin or the user), password changed or reset, etc - whenever the password hash is updated. This is the code I have so far:

function sha_user($op, &$edit, &$account, $category = NULL) {
  switch ($op) {
    case 'form':
    case 'register':
      $form['pass_sha1'] = array(
        '#type' => 'hidden',
        '#value' => ''
      );
      return $form;
      break;
    case 'submit':
    case 'update':
    case 'insert':
      if (isset($edit['pass'])) {
        $edit['pass_sha1'] = sha1($edit['pass']);
        $account->pass_sha1 = $edit['pass_sha1'];
      }
      break;
   }
}

Yet the database fails to update the SHA hash except when I edit an account, not when one is created. Can someone lead me in the right direction?

Comments

coreb’s picture

I can't remember when the different $op codes are running, but I would think that it may be actually be running the password through the SHA hash function twice: Once for update, and once for submit. I'm likely to be wrong, though.

You say the database fails to update the hash, but does that mean you get an error back, or when you try to use a different password it doesn't work right?

try doing something like the code below, and see which of the three values is being inserted into the DB:

$pass = "mypass";
echo md5($pass) . "\n";
echo sha1($pass) . "\n";
echo sha1(sha1($pass)) . "\n";
dave reid’s picture

After looking further into user.module, I noticed that in the _user_save function, that if it is a update to an existing user, that the hook_user($op = 'update', &$edit, &$account, $category) is called before any database update queries. To change a value in the user table you only need to modify the $edit array.

However, when a new user is being inserted, the hook_user($op = 'insert', &$edit, &$account, $category) is called the database insert/update queries. Modifying the $edit array makes no changes to the database what-so-ever. If you want to insert your own data into the user table on a new user, you have to run your own database query.

So to summarize, this is the code I got to work:

if ($category == 'account' && isset($edit['pass']) && !empty($edit['pass'])) {
  if ($op == 'update') {
    $edit['pass_sha1'] = sha1($edit['pass']);
  }
  else if ($op == 'insert') {
    db_query("UPDATE {users} SET pass_sha1 = '%s' WHERE uid = %d", sha1($edit['pass']), $account->uid);
  }
}
dave reid’s picture

So now I'm wondering if there's a way to use hook_user() to be able to indirectly affect the database query like the $op == 'update' condition?

david strauss’s picture

Why indirectly? Just update the data as necessary when the hook gets called.