23

How can I determine whether a user has permission to access to a certain page?

  • You didn't specify which version of Drupal you use. More details about your goal would also be useful; in the most common cases Drupal will handle menu access automatically. – Dylan Tack Jun 27 '11 at 23:06
25

If you want to verify if the currently logged-in user has access to a page, you can use the following code:

if ($router_item = menu_get_item($path)) {
  if ($router_item['access']) {
    // The user has access to the page in $path.
  }
}

$path is the path of the page you want to check (e.g. node/1, admin/user/user).

The code works in Drupal 6 and higher versions, and it is the one used from menu_execute_active_handler().

The reason I am not suggesting to directly call the access callback is because the arguments that need to be passed to that function.

The code used by _menu_check_access() is the following one (Drupal 7):

$arguments = menu_unserialize($item['access_arguments'], $map);
// As call_user_func_array is quite slow and user_access is a very common
// callback, it is worth making a special case for it.
if ($callback == 'user_access') {
  $item['access'] = (count($arguments) == 1) ? user_access($arguments[0]) : user_access($arguments[0], $arguments[1]);
}
elseif (function_exists($callback)) {
  $item['access'] = call_user_func_array($callback, $arguments);
}

The code, which needs to be as much generic as possible, doesn't directly handle a user object. This means that is not possible to replace the user object for the currently logged-in user with another user object.
The code must be generic enough to handle menu definitions such as the following ones:

$items['node/add/' . $type_url_str] = array(
  'title' => $type->name, 
  'title callback' => 'check_plain', 
  'page callback' => 'node_add', 
  'page arguments' => array($type->type), 
  'access callback' => 'node_access', 
  'access arguments' => array('create', $type->type), 
  'description' => $type->description, 
  'file' => 'node.pages.inc',
);

$items['node/%node'] = array(
  'title callback' => 'node_page_title', 
  'title arguments' => array(1),
  // The page callback also invokes drupal_set_title() in case
  // the menu router's title is overridden by a menu link. 
  'page callback' => 'node_page_view', 
  'page arguments' => array(1), 
  'access callback' => 'node_access', 
  'access arguments' => array('view', 1),
);

In both the definitions, the access arguments don't include a user object, and node_access() in this case uses the user object for the currently logged in user. In the second case one of the argument is the node object that is obtained from the URL; for example, if the URL is example.com/node/1, then the second argument passed to the access callback is the node object for the node with node ID equal to 1.
Writing code that handles these cases too would mean to duplicate code already existing in Drupal. Even if you duplicated that code, there would be still the problem of the access callbacks that are checking the access against the currently logged-in user.

If you want to check if a user that is not the currently logged-in user can access a menu is to first change the value of the global variable $user, use the code I reported at the beginning of my answer, and then restore the value of $user. For how to change the value of the global $user, you can see Programmatically impersonating another user without causing the currently logged-in user to log out. The difference is that, instead of using the value returned from drupal_anonymous_user(), you use the value returned from user_load().

  • May I know in which hook this code should be written. – Gladiator Sep 24 '13 at 4:58
14

Try drupal_valid_path().

The function returns TRUE is the path passed as argument exists and the current user has access to it. So, if you are working on Drupal 7 and you need to check the access on the currently logged in user, it's the easiest way to go:

if (drupal_valid_path('my/path')) {
  // Your code here...
}
  • 1
    In D7, drupal_valid_path does the job perfectly and is made to fulfill this exact need. It uses menu_get_item and checks access as well. – Weboide Mar 3 '14 at 19:22
  • That's true, but it only works for the currently logged-in user. If you want to know if some other user can access the path, drupal_valid_path won't help you. – Andrew Schulman Mar 2 '16 at 17:51
  • @AndrewSchulman I don't think there is an API for that, but you can temporarily switch users. – peterpoe Mar 3 '16 at 16:59
  • In Drupal 8, this has moved to \Drupal::service('path.validator')->isValid($path); - see the API documentation – gogowitsch Aug 26 '17 at 21:06
3

Call the access callback that is specified in the menu entry that is responsible for the page. That menu entry is usually created by Drupal calling the implementation of hook_menu and is stored somewhere in the database. Beware that the data returned by hook_menu might be changed by a module implementing hook_menu_alter.

Beware that some modules might not pass the user as a separate argument (as specified by the access arguments key of the menu entry), but might instead use the global $user object instead. You will have to check this for each module that you use.

  • This method can be used to find out whether the some other user than the acting user is allowed to access the page. – Oswald Aug 1 '11 at 12:05
  • 1
    Calling the access callback is not as easy as calling any other function, as the access callback needs specific arguments; see _menu_check_access(), which is the function that check if the currently logged in user has access to a menu. – kiamlaluno Aug 1 '11 at 12:47
2

Check out the user_access() function. See the link for the specified parameters for each version of Drupal. From the documentation page for Drupal 7-8:

Parameters

$string The permission, such as "administer nodes", being checked for.

$account (optional) The account to check, if not given use currently logged in user.

Return value

Boolean TRUE if the current user has the requested permission.

All permission checks in Drupal should go through this function. This way, we guarantee consistent behavior, and ensure that the superuser can perform all actions.

  • user_access() is for checking if user has a certain "type" of permissions. What is need is if user can access to a certain "path"; for example, if user can access 'node/12'? – farzan Jun 27 '11 at 14:55
  • Well how are you determining when a user has permission or not then? I would assume there is an option on the permissions page that you either have checked or not to give certain roles the permission – Laxman13 Jun 27 '11 at 15:01
  • user_access() is not always the access callback used by a menu; even it would be, you should know the access arguments that you need to pass to user_access(). – kiamlaluno Aug 1 '11 at 13:24
  • I know it's not always user_access(), just figured the OP had a permission in mind to check to see if user should have access. Not a very descriptive question – Laxman13 Aug 1 '11 at 13:45
  • Even though user_access can't check access to a specific path, I think using user_access whenever possible is the best way to check access. Good answer @Laxman13 +1. – AyeshK Jan 12 '13 at 15:44
2

If you need to know if a user can access a particular node, and are using a node access module, you can use node_access(). (without a node access module they just need the 'access content' permission.)

If you want to figure out if a user can access an arbitrary path that is defined by a hook_menu() implementation, you may have to retrieve the menu entry from the database and evaluate its 'access callback' parameter.

2
    $node = node_load(123);

    $account = user_load(456);

    if (node_access("update", $node, $account) === TRUE) 
   {

         print "access";    
    }

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.