How can I determine whether a user has permission to access to a certain page?
6 Answers
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().
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...
}
-
1In 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.– WeboideMar 3, 2014 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. Mar 2, 2016 at 17:51 -
@AndrewSchulman I don't think there is an API for that, but you can temporarily switch users.– peterpoeMar 3, 2016 at 16:59
-
In Drupal 8, this has moved to
\Drupal::service('path.validator')->isValid($path);
- see the API documentation Aug 26, 2017 at 21:06
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.– OswaldAug 1, 2011 at 12:05
-
1Calling 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.– apaderno ♦Aug 1, 2011 at 12:47
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'?– farzanJun 27, 2011 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– Laxman13Jun 27, 2011 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 touser_access()
.– apaderno ♦Aug 1, 2011 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– Laxman13Aug 1, 2011 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.– AKSJan 12, 2013 at 15:44
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.
$node = node_load(123);
$account = user_load(456);
if (node_access("update", $node, $account) === TRUE)
{
print "access";
}