Checking if a Drupal User has a Role

UPDATE: Over five years later, this post is still one of the most highly trafficked on my blog. Since then I've learned a lot and shared many other tips and modules. This past year I was honored to be a contributor to The Definitive Guide to Drupal 7, which includes many other great tips like this. I highly recommend it if you want to get the latest and greatest information on developing for Drupal.

I'm a little curious why a simple function to check if a user has a role doesn't exist in Drupal yet. Such curiosity that makes me wonder if I've just managed to miss it as long as I've been working with Drupal, so someone feel free to enlighten me. If anyone is looking for the same, please read on...

A fairly common task for me when adding PHP to CCK fields, Views arguments, content templates, etc. is to check whether the current user has been assigned a certain role. Generally in module development you're dealing with permissions and use user_access(), but when you're just customizing a site you often need such role based logic. (Drupal core has some, like the access settings for blocks.)

Use the following simple snippet to check if a user (in this example, it's the logged in user since I'm getting the global $user) has been assigned a certain role on your site:

<?php
 
global $user;

 
// Check to see if $user has the administrator role.
 
if (in_array('administrator', array_values($user->roles))) {
   
// Do something.
 
}
?>

Replace 'administrator' with whatever role it is you're trying to check against. Alternatively, if you keep a helper module for use on your projects, go ahead and drop this function in it:

<?php
/**
 * Check to see if a user has been assigned a certain role.
 *
 * @param $role
 *   The name of the role you're trying to find.
 * @param $user
 *   The user object for the user you're checking; defaults to the current user.
 * @return
 *   TRUE if the user object has the role, FALSE if it does not.
 */
function user_has_role($role, $user = NULL) {
  if (
$user == NULL) {
    global
$user;
  }

  if (
is_array($user->roles) && in_array($role, array_values($user->roles))) {
    return
TRUE;
  }

  return
FALSE;
}
?>

Please let me know if I put a typo up here or you know of an existing or easier way to do this!

Comments

It might be better to add a user access permission and then use that instead of just checking if they're part of that role:

<?php
function mymodule_perm() {
  return array(
'access something special');
}

function
dosomethingspecial() {
 
// For current user
 
if (user_access('access something special')) {
   
// Doing something special!
 
}

 
// For a specific user
 
if (user_access('access something special', $theuser)) {
   
// Doing something special!
 
}
}
?>

The benefit to using this instead is that it isn't targeted to one role. You can have the access permission across a number of different roles. Drupal also already provides a GUI for managing this in admin/user/access.

Well, I understand when developing a module to use hook_perm() and user_access() to check for permissions level access... but on the fly, when building out a CCK type for example, if I want the available values to differ depending on a user's role, I would use this snippet. I suppose I could use a helper module to define all the special access permissions for a site just as well as I could go through the GUI to create more roles.

Perhaps an answer would be to be a module that lets you create arbitrary permissions and assign those to roles on your site then use user_access() in the CCK/Views custom PHP fields... but then I may as well be checking a user role.

In the long run that becomes quite rigid. Someone changes the role names and you are in trouble - or someone wants to change which roles mean the ability to edit that field and you have to edit code to fix that.

Instead, I tend to use a site specific module (on www.example.com the module would be example.module) where I define a lot of _perms for situations like this and then I use those perms throughout my code.

The more I think about it, that seems like the right thing to do here. So maybe this post turned out to be more about asking a different question than providing an answer. Thanks for the input, Greg. Smile

Great suggestion, greggles. I just found a module to help do this on the fly:
http://drupal.org/project/config_perms

Hope it helps someone.

thats how i would do it.

however, you are usually asking the wrong question if this function is your answer. permissions are far more often checked than inclusion in a role. this function is so specialized that i don't think it needs to be in core.

Agreed... I realized that this isn't something I'd use when creating a module but more when just adding a bit of custom functionality to a node/block's contents or a CCK field/Views argument custom PHP values. Not quite widespread usage.

There is...
http://api.drupal.org/api/function/user_access/5

<?php
$u
= user_load(array('uid' => 12'));
if (user_access('
Administer Nodes', $u)) {
  return t('
User 12 does have access to this');
}
else {
  return t('
User 12 does not have access to this');
}



if (user_access('
Administer Nodes')) {
  return t('
Current User does have access to this');
}
else {
  return t('
Current User does not have access to this');
}
?>

It wouldn't be terribly hard to add this to user_roles().

http://api.drupal.org/api/function/user_roles/5

Given the description of the function -- "Retrieve an array of roles matching specified conditions." -- specifying the $user seems a perfectly valid condition, much like user_load() allowing an array of arguments.

I can see some use cases for it -- mostly in theming -- so I'd file a patch for D7.

Hi,

it is very useful to point me using the $user-roles array, but it looks like since Drupal 5 the roles array no longer contain the `administrator`? It only contains those roles name we created from admin

You're right... my apologies for not pointing it out. The administrator role in the example is just a custom user role I generally use on the sites I create... you can replace that with whatever role you're checking for.

I know this is an old thread, but a better approach might be to check for the $user->roles array keys since those are the role id's and typically would still be the same even if someone went in and renamed the role from something like "student-teacher" to "Student Teacher". As long as they didn't create it as a new role and just edited the existing one, the role id would remain the same and your code snippet wouldn't require any changes to reflect the new spelling/format of the role name.

Hi

Just a small side note. The super administrator has an ID of 1, so a check like this should also be carried out.

    // User #1 has all privileges:
    if ($user->uid == 1) return TRUE;

Otherwise, it may be possible for the primary administrator to be blocked.

Regards

that's why i always grant user 1 an admin role with all permission as well (thanks adminrole module!)...granted, it's not necessary since user 1 has all permissions anyway, but it avoids having to make sure you cover user 1 when checking something based on roles instead of permissions.

I wanted to create a block which would be visible on profiles of only certain types of users.
For example, I wanted to show "Subscribe to this employer" block but only when employer's profile was open.
So seeing your code I used the code below :

<?php
if (arg(0) == 'user'){
   
$user_profile = user_load(array('uid' => arg(1)));
    if (
in_array('Employer', array_values($user_profile->roles))){
        return
TRUE;
    }
}
else {
  return
FALSE;
}
?>

and displayed the block only when Employer profile was open.

Thanks for your help guys. Smile

Glad the discussion could point you in the right direction!

I often have a few flavors of admins and need to check more than one role.

<?php
global $user;
$adminRoles= array('dev','editor','employee');
$adminAble= FALSE;
foreach(
$adminRoles as $role) {
  if(
in_array($role, array_values($user->roles)) ) $adminAble= TRUE;
}
if(
$adminAble) {
    print
'<p>SHOW THE SPECIAL INFO</p>';
}
?>

you could further simplify your code with array_intersect:

<?php
global $user;
$adminRoles= array('dev','editor','employee');
$check = array_intersect($adminRoles, array_values($user->roles))
$adminAble = empty($check) ? FALSE : TRUE;
?>

wow, very elegant improvement!

Very helpful, thank you!!

Hello!

I'm trying to remove a user role after the submission of a webform, now that I've checked that the user has the specific role, how can I remove it? I've searched everywhere but I can't find something similar.

That should be prety easy with a little sql...

<?php
$sql
= "DELETE FROM {users_roles} WHERE uid = %d AND rid = %d";

db_query($sql, $user->uid, $role_id);
?>

Or if you only know the role name and you want to do it in one query:

<?php
$sql
= "DELETE FROM {users_roles} WHERE uid = %d AND rid = ("
          
."     SELECT rid FROM {role} WHERE name = '%s' "
          
.")";

db_query($sql, $user->uid, $role_name);
?>

Hi Ryan, guys,

When using the sample code, I get these:


warning: array_values() [function.array-values]: The argument should be an array in /var/www/vhosts/eadev.pieplan.com/subdomains/gr/httpdocs/modules/locale/locale.module on line 397.

warning: in_array() [function.in-array]: Wrong datatype for second argument in /var/www/vhosts/eadev.pieplan.com/subdomains/gr/httpdocs/modules/locale/locale.module on line 397.

This is because array_values() returns an indexed array of values, instead of a flat list. E.g.

Array
(
[0] => authenticated user
[1] => admin
[2] => area manager
[3] => contributor
[4] => teacher
[5] => student
)

...instead of the flat list that in_array expectes:

Array('authenticated user', 'admin', 'area manager', 'contributor', 'teacher', 'student')

The sample code seems to have worked for most of you, is this a 'feature' of the newer PHP versions?

Nice!

But it's good form to only use $user unless that is definitely, absolutely, the global $user. In your case, $user might just be the account in question.

This is the way user_access() handles the same thing:

  if (!isset($account)) {
    $account = $user;
  }

I need more as one role as array, I need following values:
The parameter must check more roles as one e.g. Administrator, administrator, Admin, admin

E.G.: check values in array: Administrator or administrator or Admin or admin

Thank you :-)