I cannot determine why this will not work for me in hook_menu:

...
'access callback' => 'user_access',
'access arguments' => array('perm1', 'perm2'),
...

Also, these permissions have been declared in hook_perm. I tried clearing cache, etc.
If I use just Array('perm1') it works fine.

"Not work" means I get errors after re-loading the module with the multiple permissions set. From the modules window upon re-loading:

--------
* warning: array_fill() [function.array-fill]: Number of elements must be positive in G:\WampServer\www\site\includes\database.inc on line 241.
* warning: implode() [function.implode]: Invalid arguments passed in G:\WampServer\www\site\includes\database.inc on line 241.
* warning: array_keys() [function.array-keys]: The first argument should be an array in G:\WampServer\www\site\modules\user\user.module on line 502.
* user warning: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ')' at line 1 query: SELECT p.perm FROM role r INNER JOIN permission p ON p.rid = r.rid WHERE r.rid IN () in G:\WampServer\www\site\modules\user\user.module on line 502.
--------

Comments

heine’s picture

If you look at the user_access function parameters, you'll understand. The second argument in the array, is passed as the $account param.

Make your own access callback instead:

//..
'access callback' => 'my_access_callback',
//..

function my_access_callback() {
  return user_access('foo') && user_access('bar');
}

--
The Manual | Troubleshooting FAQ | Tips for posting | How to report a security issue.

rnealxp’s picture

Thanks. I'm a new Drupal developer and this has taught me to analyze the API better before raising a question. Per your suggestion, I wrote a custom function to do the check:

function my_access_check($arr_perms) {
	$bool = true; //Must init to true.
	
	for($i=0; $i<sizeof($arr_perms); $i++){
		$bool = $bool && user_access($arr_perms[$i]);
		if($bool===false){
			return false;
		}
	}
	
	//Passed all checks.
	return true;
}

I can see later adding a 2nd arg to handle whether ALL perms are required or ANY of them (&& vs ||). BTW, how would I pass two args--would I use Array(Array('perm1','perm2'),'ANY')?

rnealxp’s picture

That code snippet I placed above did not work. I'm unable to figure out how to pass multiple args to a custom function. I'm also unable to figure out how to pass a single array. (in the context spoken of above). Please help anyone!

smaier’s picture

I took the core user_access function (Drupal 6) and modified it slightly to check to see if the $string argument was an array. This way I could pass more then 1 value into it.

function MODULENAME_user_access($string, $account = NULL, $reset = FALSE) {
  global $user;
  static $perm = array();

  if ($reset) {
    $perm = array();
  }

  if (is_null($account)) {
    $account = $user;
  }

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

  // To reduce the number of SQL queries, we cache the user's permissions
  // in a static variable.
  if (!isset($perm[$account->uid])) {
    $result = db_query("SELECT p.perm FROM {role} r INNER JOIN {permission} p ON p.rid = r.rid WHERE r.rid IN (". db_placeholders($account->roles) .")", array_keys($account->roles));

    $perms = array();
    while ($row = db_fetch_object($result)) {
      $perms += array_flip(explode(', ', $row->perm));
    }
    $perm[$account->uid] = $perms;
  }

  // If $string is an array, then check each one.
  if( is_array( $string ) ) {
    
	// Loop through each value in the array and return true if there are any matches
	foreach( $string as $value ) {
	  $has_access = isset($perm[$account->uid][$value]);
	  if( $has_access ) return $has_access;
	}
  } else {
    return isset($perm[$account->uid][$string]);
  }
}

I haven't had time to test it thoroughly but my initial tests were good.

In your menu item put this:

  'access callback' => 'MODULENAME_user_access',
  'access arguments' => array( array( 'PERM1', 'PERM2') ),
wthielke’s picture

I ran into the same problem, where I wanted to use multiple arguments. I think I figured this out, at least in Drupal 7. Using user_access as the callback didn't work. But looking at the code in menu.inc, I found that it uses the PHP function call_user_func_array(). The call to call_user_func_array() indeed passes the array of permissions as the second argument, but the array doesn't get passed as an array to the callback. Instead, the callback receives a variable number of arguments.
I solved this as follows, using PHP's func_num_args() and func_get_arg() functions:

function my_callback() {
  for ($i = 0; $i < func_num_args(); $i++) {
    $perm = func_get_arg($i); // get permission
    // check permission via user_access
    if (user_access($perm)) {
      return TRUE; // return TRUE on first success
    }
  }
  return FALSE; // return FALSE if no permission passes
}

This is a general solution for a variable number of arguments. If you know for sure that you only have two arguments, you could code your callback as:

function my_callback($perm1, $perm2)

wthielke’s picture

Or slightly more compact:

function my_callback() {
  foreach (func_get_args() as $perm) {
    if (user_access($perm)) {
      return TRUE;
    }
  }
  return FALSE;
}

func_get_args() returns the arguments as an array, so the familiar foreach construct can be used.

heine’s picture

Eh, no.

You can shortcut on the FALSE (ie !user_access($perm)), but not on the TRUE condition (edited to add) unless you really want to grant access to users with anyone of the permissions, not all of them.

wthielke’s picture

Yes, in my case, I want to grant access if any one of the permissions are valid for the user. My main point, though, is that you can indeed process multiple permissions-- they just don't come in as an array to the callback function, and you can use the standard PHP functions to pull the arguments.

pankaj.g’s picture


// Add this in hook_menu
'access arguments' => array(array('role1', 'role2')), // passing roles
'access callback' => 'custom_permission_access', // callback custom method for granting permission

//callback method
function custom_permission_access($roles){
    if (user_is_logged_in()) {
        global $user;  
        foreach ($roles as $role) {
            if (in_array($role, $user->roles)) {
                return TRUE;
            }
        }
    }
    else {
        return FALSE;
    }
}